Loading core/java/android/content/res/Configuration.java +26 −21 Original line number Diff line number Diff line Loading @@ -2432,27 +2432,10 @@ public final class Configuration implements Parcelable, Comparable<Configuration break; } switch (config.uiMode & Configuration.UI_MODE_TYPE_MASK) { case Configuration.UI_MODE_TYPE_APPLIANCE: parts.add("appliance"); break; case Configuration.UI_MODE_TYPE_DESK: parts.add("desk"); break; case Configuration.UI_MODE_TYPE_TELEVISION: parts.add("television"); break; case Configuration.UI_MODE_TYPE_CAR: parts.add("car"); break; case Configuration.UI_MODE_TYPE_WATCH: parts.add("watch"); break; case Configuration.UI_MODE_TYPE_VR_HEADSET: parts.add("vrheadset"); break; default: break; final String uiModeTypeString = getUiModeTypeString(config.uiMode & Configuration.UI_MODE_TYPE_MASK); if (uiModeTypeString != null) { parts.add(uiModeTypeString); } switch (config.uiMode & Configuration.UI_MODE_NIGHT_MASK) { Loading Loading @@ -2586,6 +2569,28 @@ public final class Configuration implements Parcelable, Comparable<Configuration return TextUtils.join("-", parts); } /** * @hide */ public static String getUiModeTypeString(int uiModeType) { switch (uiModeType) { case Configuration.UI_MODE_TYPE_APPLIANCE: return "appliance"; case Configuration.UI_MODE_TYPE_DESK: return "desk"; case Configuration.UI_MODE_TYPE_TELEVISION: return "television"; case Configuration.UI_MODE_TYPE_CAR: return "car"; case Configuration.UI_MODE_TYPE_WATCH: return "watch"; case Configuration.UI_MODE_TYPE_VR_HEADSET: return "vrheadset"; default: return null; } } /** * Generate a delta Configuration between <code>base</code> and <code>change</code>. The * resulting delta can be used with {@link #updateFrom(Configuration)}. Loading services/core/java/com/android/server/display/DensityMap.java 0 → 100644 +137 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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.display; import java.util.Arrays; import java.util.Comparator; /** * Class which can compute the logical density for a display resolution. It holds a collection * of pre-configured densities, which are used for look-up and interpolation. */ public class DensityMap { // Instead of resolutions we store the squared diagonal size. Diagonals make the map // keys invariant to rotations and are useful for interpolation because they're scalars. // Squared diagonals have the same properties as diagonals (the square function is monotonic) // but also allow us to use integer types and avoid floating point arithmetics. private final Entry[] mSortedDensityMapEntries; /** * Creates a density map. The newly created object takes ownership of the passed array. */ static DensityMap createByOwning(Entry[] densityMapEntries) { return new DensityMap(densityMapEntries); } private DensityMap(Entry[] densityMapEntries) { Arrays.sort(densityMapEntries, Comparator.comparingInt(entry -> entry.squaredDiagonal)); mSortedDensityMapEntries = densityMapEntries; verifyDensityMap(mSortedDensityMapEntries); } /** * Returns the logical density for the given resolution. * * If the resolution matches one of the entries in the map, the corresponding density is * returned. Otherwise the return value is interpolated using the closest entries in the map. */ public int getDensityForResolution(int width, int height) { int squaredDiagonal = width * width + height * height; // Search for two pre-configured entries "left" and "right" with the following criteria // * left <= squaredDiagonal // * squaredDiagonal - left is minimal // * right > squaredDiagonal // * right - squaredDiagonal is minimal Entry left = Entry.ZEROES; Entry right = null; for (Entry entry : mSortedDensityMapEntries) { if (entry.squaredDiagonal <= squaredDiagonal) { left = entry; } else { right = entry; break; } } // Check if we found an exact match. if (left.squaredDiagonal == squaredDiagonal) { return left.density; } // If no configured resolution is higher than the specified resolution, interpolate // between (0,0) and (maxConfiguredDiagonal, maxConfiguredDensity). if (right == null) { right = left; // largest entry in the sorted array left = Entry.ZEROES; } double leftDiagonal = Math.sqrt(left.squaredDiagonal); double rightDiagonal = Math.sqrt(right.squaredDiagonal); double diagonal = Math.sqrt(squaredDiagonal); return (int) Math.round((diagonal - leftDiagonal) * (right.density - left.density) / (rightDiagonal - leftDiagonal) + left.density); } private static void verifyDensityMap(Entry[] sortedEntries) { for (int i = 1; i < sortedEntries.length; i++) { Entry prev = sortedEntries[i - 1]; Entry curr = sortedEntries[i]; if (prev.squaredDiagonal == curr.squaredDiagonal) { // This will most often happen because there are two entries with the same // resolution (AxB and AxB) or rotated resolution (AxB and BxA), but it can also // happen in the very rare cases when two different resolutions happen to have // the same diagonal (e.g. 100x700 and 500x500). throw new IllegalStateException("Found two entries in the density map with" + " the same diagonal: " + prev + ", " + curr); } else if (prev.density > curr.density) { throw new IllegalStateException("Found two entries in the density map with" + " increasing diagonal but decreasing density: " + prev + ", " + curr); } } } @Override public String toString() { return "DensityMap{" + "mDensityMapEntries=" + Arrays.toString(mSortedDensityMapEntries) + '}'; } static class Entry { public static final Entry ZEROES = new Entry(0, 0, 0); public final int squaredDiagonal; public final int density; Entry(int width, int height, int density) { this.squaredDiagonal = width * width + height * height; this.density = density; } @Override public String toString() { return "DensityMapEntry{" + "squaredDiagonal=" + squaredDiagonal + ", density=" + density + '}'; } } } services/core/java/com/android/server/display/DisplayDeviceConfig.java +115 −17 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.server.display; import android.annotation.NonNull; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; import android.hardware.display.DisplayManagerInternal; import android.hardware.display.DisplayManagerInternal.RefreshRateLimitation; Loading @@ -31,6 +32,7 @@ import android.view.DisplayAddress; import com.android.internal.R; import com.android.internal.display.BrightnessSynchronizer; import com.android.server.display.config.Density; import com.android.server.display.config.DisplayConfiguration; import com.android.server.display.config.DisplayQuirks; import com.android.server.display.config.HbmTiming; Loading @@ -52,6 +54,7 @@ import java.io.InputStream; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import javax.xml.datatype.DatatypeConfigurationException; Loading @@ -70,6 +73,8 @@ public class DisplayDeviceConfig { private static final String ETC_DIR = "etc"; private static final String DISPLAY_CONFIG_DIR = "displayconfig"; private static final String CONFIG_FILE_FORMAT = "display_%s.xml"; private static final String DEFAULT_CONFIG_FILE = "default.xml"; private static final String DEFAULT_CONFIG_FILE_WITH_UIMODE_FORMAT = "default_%s.xml"; private static final String PORT_SUFFIX_FORMAT = "port_%d"; private static final String STABLE_ID_SUFFIX_FORMAT = "id_%d"; private static final String NO_SUFFIX_FORMAT = "%d"; Loading Loading @@ -121,6 +126,7 @@ public class DisplayDeviceConfig { private List<String> mQuirks; private boolean mIsHighBrightnessModeEnabled = false; private HighBrightnessModeData mHbmData; private DensityMap mDensityMap; private String mLoadedFrom = null; private DisplayDeviceConfig(Context context) { Loading @@ -141,6 +147,33 @@ public class DisplayDeviceConfig { */ public static DisplayDeviceConfig create(Context context, long physicalDisplayId, boolean isDefaultDisplay) { final DisplayDeviceConfig config = createWithoutDefaultValues(context, physicalDisplayId, isDefaultDisplay); config.copyUninitializedValuesFromSecondaryConfig(loadDefaultConfigurationXml(context)); return config; } /** * Creates an instance using global values since no display device config xml exists. * Uses values from config or PowerManager. * * @param context * @param useConfigXml * @return A configuration instance. */ public static DisplayDeviceConfig create(Context context, boolean useConfigXml) { final DisplayDeviceConfig config; if (useConfigXml) { config = getConfigFromGlobalXml(context); } else { config = getConfigFromPmValues(context); } return config; } private static DisplayDeviceConfig createWithoutDefaultValues(Context context, long physicalDisplayId, boolean isDefaultDisplay) { DisplayDeviceConfig config; config = loadConfigFromDirectory(context, Environment.getProductDirectory(), Loading @@ -161,22 +194,53 @@ public class DisplayDeviceConfig { return create(context, isDefaultDisplay); } /** * Creates an instance using global values since no display device config xml exists. * Uses values from config or PowerManager. * * @param context * @param useConfigXml * @return A configuration instance. */ public static DisplayDeviceConfig create(Context context, boolean useConfigXml) { DisplayDeviceConfig config; if (useConfigXml) { config = getConfigFromGlobalXml(context); } else { config = getConfigFromPmValues(context); private static DisplayConfiguration loadDefaultConfigurationXml(Context context) { List<File> defaultXmlLocations = new ArrayList<>(); defaultXmlLocations.add(Environment.buildPath(Environment.getProductDirectory(), ETC_DIR, DISPLAY_CONFIG_DIR, DEFAULT_CONFIG_FILE)); defaultXmlLocations.add(Environment.buildPath(Environment.getVendorDirectory(), ETC_DIR, DISPLAY_CONFIG_DIR, DEFAULT_CONFIG_FILE)); // Read config_defaultUiModeType directly because UiModeManager hasn't started yet. final int uiModeType = context.getResources() .getInteger(com.android.internal.R.integer.config_defaultUiModeType); final String uiModeTypeStr = Configuration.getUiModeTypeString(uiModeType); if (uiModeTypeStr != null) { defaultXmlLocations.add(Environment.buildPath(Environment.getRootDirectory(), ETC_DIR, DISPLAY_CONFIG_DIR, String.format(DEFAULT_CONFIG_FILE_WITH_UIMODE_FORMAT, uiModeTypeStr))); } return config; defaultXmlLocations.add(Environment.buildPath(Environment.getRootDirectory(), ETC_DIR, DISPLAY_CONFIG_DIR, DEFAULT_CONFIG_FILE)); final File configFile = getFirstExistingFile(defaultXmlLocations); if (configFile == null) { // Display configuration files aren't required to exist. return null; } DisplayConfiguration defaultConfig = null; try (InputStream in = new BufferedInputStream(new FileInputStream(configFile))) { defaultConfig = XmlParser.read(in); if (defaultConfig == null) { Slog.i(TAG, "Default DisplayDeviceConfig file is null"); } } catch (IOException | DatatypeConfigurationException | XmlPullParserException e) { Slog.e(TAG, "Encountered an error while reading/parsing display config file: " + configFile, e); } return defaultConfig; } private static File getFirstExistingFile(Collection<File> files) { for (File file : files) { if (file.exists() && file.isFile()) { return file; } } return null; } private static DisplayDeviceConfig loadConfigFromDirectory(Context context, Loading Loading @@ -316,9 +380,13 @@ public class DisplayDeviceConfig { return mRefreshRateLimitations; } public DensityMap getDensityMap() { return mDensityMap; } @Override public String toString() { String str = "DisplayDeviceConfig{" return "DisplayDeviceConfig{" + "mLoadedFrom=" + mLoadedFrom + ", mBacklight=" + Arrays.toString(mBacklight) + ", mNits=" + Arrays.toString(mNits) Loading @@ -340,8 +408,8 @@ public class DisplayDeviceConfig { + ", mAmbientLightSensor=" + mAmbientLightSensor + ", mProximitySensor=" + mProximitySensor + ", mRefreshRateLimitations= " + Arrays.toString(mRefreshRateLimitations.toArray()) + ", mDensityMap= " + mDensityMap + "}"; return str; } private static DisplayDeviceConfig getConfigFromSuffix(Context context, File baseDirectory, Loading Loading @@ -384,6 +452,7 @@ public class DisplayDeviceConfig { try (InputStream in = new BufferedInputStream(new FileInputStream(configFile))) { final DisplayConfiguration config = XmlParser.read(in); if (config != null) { loadDensityMap(config); loadBrightnessDefaultFromDdcXml(config); loadBrightnessConstraintsFromConfigXml(); loadBrightnessMap(config); Loading Loading @@ -429,6 +498,35 @@ public class DisplayDeviceConfig { setProxSensorUnspecified(); } private void copyUninitializedValuesFromSecondaryConfig(DisplayConfiguration defaultConfig) { if (defaultConfig == null) { return; } if (mDensityMap == null) { loadDensityMap(defaultConfig); } } private void loadDensityMap(DisplayConfiguration config) { if (config.getDensityMap() == null) { return; } final List<Density> entriesFromXml = config.getDensityMap().getDensity(); final DensityMap.Entry[] entries = new DensityMap.Entry[entriesFromXml.size()]; for (int i = 0; i < entriesFromXml.size(); i++) { final Density density = entriesFromXml.get(i); entries[i] = new DensityMap.Entry( density.getWidth().intValue(), density.getHeight().intValue(), density.getDensity().intValue()); } mDensityMap = DensityMap.createByOwning(entries); } private void loadBrightnessDefaultFromDdcXml(DisplayConfiguration config) { // Default brightness values are stored in the displayDeviceConfig file, // Or we fallback standard values if not. Loading services/core/java/com/android/server/display/LocalDisplayAdapter.java +11 −2 Original line number Diff line number Diff line Loading @@ -426,6 +426,15 @@ final class LocalDisplayAdapter extends DisplayAdapter { : mDefaultModeId; } private int getLogicalDensity() { DensityMap densityMap = getDisplayDeviceConfig().getDensityMap(); if (densityMap == null) { return (int) (mStaticDisplayInfo.density * 160 + 0.5); } return densityMap.getDensityForResolution(mInfo.width, mInfo.height); } private void loadDisplayDeviceConfig() { // Load display device config final Context context = getOverlayContext(); Loading Loading @@ -591,7 +600,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { final DisplayAddress.Physical physicalAddress = DisplayAddress.fromPhysicalDisplayId(mPhysicalDisplayId); mInfo.address = physicalAddress; mInfo.densityDpi = (int) (mStaticDisplayInfo.density * 160 + 0.5f); mInfo.densityDpi = getLogicalDensity(); mInfo.xDpi = mActiveSfDisplayMode.xDpi; mInfo.yDpi = mActiveSfDisplayMode.yDpi; mInfo.deviceProductInfo = mStaticDisplayInfo.deviceProductInfo; Loading Loading @@ -1029,7 +1038,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { for (int i = 0; i < mSupportedModes.size(); i++) { pw.println(" " + mSupportedModes.valueAt(i)); } pw.println("mSupportedColorModes=" + mSupportedColorModes.toString()); pw.println("mSupportedColorModes=" + mSupportedColorModes); pw.println("mDisplayDeviceConfig=" + mDisplayDeviceConfig); } Loading services/core/java/com/android/server/wm/DisplayContent.java +14 −1 Original line number Diff line number Diff line Loading @@ -2833,8 +2833,14 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp mBaseDisplayDensity = baseDensity; if (mMaxUiWidth > 0 && mBaseDisplayWidth > mMaxUiWidth) { mBaseDisplayHeight = (mMaxUiWidth * mBaseDisplayHeight) / mBaseDisplayWidth; final float ratio = mMaxUiWidth / (float) mBaseDisplayWidth; mBaseDisplayHeight = (int) (mBaseDisplayHeight * ratio); mBaseDisplayWidth = mMaxUiWidth; if (!mIsDensityForced) { // Update the density proportionally so the size of the UI elements won't change // from the user's perspective. mBaseDisplayDensity = (int) (mBaseDisplayDensity * ratio); } if (DEBUG_DISPLAY) { Slog.v(TAG_WM, "Applying config restraints:" + mBaseDisplayWidth + "x" Loading Loading @@ -2891,6 +2897,13 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp /** If the given width and height equal to initial size, the setting will be cleared. */ void setForcedSize(int width, int height) { // Can't force size higher than the maximal allowed if (mMaxUiWidth > 0 && width > mMaxUiWidth) { final float ratio = mMaxUiWidth / (float) width; height = (int) (height * ratio); width = mMaxUiWidth; } mIsSizeForced = mInitialDisplayWidth != width || mInitialDisplayHeight != height; if (mIsSizeForced) { // Set some sort of reasonable bounds on the size of the display that we will try Loading Loading
core/java/android/content/res/Configuration.java +26 −21 Original line number Diff line number Diff line Loading @@ -2432,27 +2432,10 @@ public final class Configuration implements Parcelable, Comparable<Configuration break; } switch (config.uiMode & Configuration.UI_MODE_TYPE_MASK) { case Configuration.UI_MODE_TYPE_APPLIANCE: parts.add("appliance"); break; case Configuration.UI_MODE_TYPE_DESK: parts.add("desk"); break; case Configuration.UI_MODE_TYPE_TELEVISION: parts.add("television"); break; case Configuration.UI_MODE_TYPE_CAR: parts.add("car"); break; case Configuration.UI_MODE_TYPE_WATCH: parts.add("watch"); break; case Configuration.UI_MODE_TYPE_VR_HEADSET: parts.add("vrheadset"); break; default: break; final String uiModeTypeString = getUiModeTypeString(config.uiMode & Configuration.UI_MODE_TYPE_MASK); if (uiModeTypeString != null) { parts.add(uiModeTypeString); } switch (config.uiMode & Configuration.UI_MODE_NIGHT_MASK) { Loading Loading @@ -2586,6 +2569,28 @@ public final class Configuration implements Parcelable, Comparable<Configuration return TextUtils.join("-", parts); } /** * @hide */ public static String getUiModeTypeString(int uiModeType) { switch (uiModeType) { case Configuration.UI_MODE_TYPE_APPLIANCE: return "appliance"; case Configuration.UI_MODE_TYPE_DESK: return "desk"; case Configuration.UI_MODE_TYPE_TELEVISION: return "television"; case Configuration.UI_MODE_TYPE_CAR: return "car"; case Configuration.UI_MODE_TYPE_WATCH: return "watch"; case Configuration.UI_MODE_TYPE_VR_HEADSET: return "vrheadset"; default: return null; } } /** * Generate a delta Configuration between <code>base</code> and <code>change</code>. The * resulting delta can be used with {@link #updateFrom(Configuration)}. Loading
services/core/java/com/android/server/display/DensityMap.java 0 → 100644 +137 −0 Original line number Diff line number Diff line /* * Copyright (C) 2021 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.display; import java.util.Arrays; import java.util.Comparator; /** * Class which can compute the logical density for a display resolution. It holds a collection * of pre-configured densities, which are used for look-up and interpolation. */ public class DensityMap { // Instead of resolutions we store the squared diagonal size. Diagonals make the map // keys invariant to rotations and are useful for interpolation because they're scalars. // Squared diagonals have the same properties as diagonals (the square function is monotonic) // but also allow us to use integer types and avoid floating point arithmetics. private final Entry[] mSortedDensityMapEntries; /** * Creates a density map. The newly created object takes ownership of the passed array. */ static DensityMap createByOwning(Entry[] densityMapEntries) { return new DensityMap(densityMapEntries); } private DensityMap(Entry[] densityMapEntries) { Arrays.sort(densityMapEntries, Comparator.comparingInt(entry -> entry.squaredDiagonal)); mSortedDensityMapEntries = densityMapEntries; verifyDensityMap(mSortedDensityMapEntries); } /** * Returns the logical density for the given resolution. * * If the resolution matches one of the entries in the map, the corresponding density is * returned. Otherwise the return value is interpolated using the closest entries in the map. */ public int getDensityForResolution(int width, int height) { int squaredDiagonal = width * width + height * height; // Search for two pre-configured entries "left" and "right" with the following criteria // * left <= squaredDiagonal // * squaredDiagonal - left is minimal // * right > squaredDiagonal // * right - squaredDiagonal is minimal Entry left = Entry.ZEROES; Entry right = null; for (Entry entry : mSortedDensityMapEntries) { if (entry.squaredDiagonal <= squaredDiagonal) { left = entry; } else { right = entry; break; } } // Check if we found an exact match. if (left.squaredDiagonal == squaredDiagonal) { return left.density; } // If no configured resolution is higher than the specified resolution, interpolate // between (0,0) and (maxConfiguredDiagonal, maxConfiguredDensity). if (right == null) { right = left; // largest entry in the sorted array left = Entry.ZEROES; } double leftDiagonal = Math.sqrt(left.squaredDiagonal); double rightDiagonal = Math.sqrt(right.squaredDiagonal); double diagonal = Math.sqrt(squaredDiagonal); return (int) Math.round((diagonal - leftDiagonal) * (right.density - left.density) / (rightDiagonal - leftDiagonal) + left.density); } private static void verifyDensityMap(Entry[] sortedEntries) { for (int i = 1; i < sortedEntries.length; i++) { Entry prev = sortedEntries[i - 1]; Entry curr = sortedEntries[i]; if (prev.squaredDiagonal == curr.squaredDiagonal) { // This will most often happen because there are two entries with the same // resolution (AxB and AxB) or rotated resolution (AxB and BxA), but it can also // happen in the very rare cases when two different resolutions happen to have // the same diagonal (e.g. 100x700 and 500x500). throw new IllegalStateException("Found two entries in the density map with" + " the same diagonal: " + prev + ", " + curr); } else if (prev.density > curr.density) { throw new IllegalStateException("Found two entries in the density map with" + " increasing diagonal but decreasing density: " + prev + ", " + curr); } } } @Override public String toString() { return "DensityMap{" + "mDensityMapEntries=" + Arrays.toString(mSortedDensityMapEntries) + '}'; } static class Entry { public static final Entry ZEROES = new Entry(0, 0, 0); public final int squaredDiagonal; public final int density; Entry(int width, int height, int density) { this.squaredDiagonal = width * width + height * height; this.density = density; } @Override public String toString() { return "DensityMapEntry{" + "squaredDiagonal=" + squaredDiagonal + ", density=" + density + '}'; } } }
services/core/java/com/android/server/display/DisplayDeviceConfig.java +115 −17 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.server.display; import android.annotation.NonNull; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; import android.hardware.display.DisplayManagerInternal; import android.hardware.display.DisplayManagerInternal.RefreshRateLimitation; Loading @@ -31,6 +32,7 @@ import android.view.DisplayAddress; import com.android.internal.R; import com.android.internal.display.BrightnessSynchronizer; import com.android.server.display.config.Density; import com.android.server.display.config.DisplayConfiguration; import com.android.server.display.config.DisplayQuirks; import com.android.server.display.config.HbmTiming; Loading @@ -52,6 +54,7 @@ import java.io.InputStream; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import javax.xml.datatype.DatatypeConfigurationException; Loading @@ -70,6 +73,8 @@ public class DisplayDeviceConfig { private static final String ETC_DIR = "etc"; private static final String DISPLAY_CONFIG_DIR = "displayconfig"; private static final String CONFIG_FILE_FORMAT = "display_%s.xml"; private static final String DEFAULT_CONFIG_FILE = "default.xml"; private static final String DEFAULT_CONFIG_FILE_WITH_UIMODE_FORMAT = "default_%s.xml"; private static final String PORT_SUFFIX_FORMAT = "port_%d"; private static final String STABLE_ID_SUFFIX_FORMAT = "id_%d"; private static final String NO_SUFFIX_FORMAT = "%d"; Loading Loading @@ -121,6 +126,7 @@ public class DisplayDeviceConfig { private List<String> mQuirks; private boolean mIsHighBrightnessModeEnabled = false; private HighBrightnessModeData mHbmData; private DensityMap mDensityMap; private String mLoadedFrom = null; private DisplayDeviceConfig(Context context) { Loading @@ -141,6 +147,33 @@ public class DisplayDeviceConfig { */ public static DisplayDeviceConfig create(Context context, long physicalDisplayId, boolean isDefaultDisplay) { final DisplayDeviceConfig config = createWithoutDefaultValues(context, physicalDisplayId, isDefaultDisplay); config.copyUninitializedValuesFromSecondaryConfig(loadDefaultConfigurationXml(context)); return config; } /** * Creates an instance using global values since no display device config xml exists. * Uses values from config or PowerManager. * * @param context * @param useConfigXml * @return A configuration instance. */ public static DisplayDeviceConfig create(Context context, boolean useConfigXml) { final DisplayDeviceConfig config; if (useConfigXml) { config = getConfigFromGlobalXml(context); } else { config = getConfigFromPmValues(context); } return config; } private static DisplayDeviceConfig createWithoutDefaultValues(Context context, long physicalDisplayId, boolean isDefaultDisplay) { DisplayDeviceConfig config; config = loadConfigFromDirectory(context, Environment.getProductDirectory(), Loading @@ -161,22 +194,53 @@ public class DisplayDeviceConfig { return create(context, isDefaultDisplay); } /** * Creates an instance using global values since no display device config xml exists. * Uses values from config or PowerManager. * * @param context * @param useConfigXml * @return A configuration instance. */ public static DisplayDeviceConfig create(Context context, boolean useConfigXml) { DisplayDeviceConfig config; if (useConfigXml) { config = getConfigFromGlobalXml(context); } else { config = getConfigFromPmValues(context); private static DisplayConfiguration loadDefaultConfigurationXml(Context context) { List<File> defaultXmlLocations = new ArrayList<>(); defaultXmlLocations.add(Environment.buildPath(Environment.getProductDirectory(), ETC_DIR, DISPLAY_CONFIG_DIR, DEFAULT_CONFIG_FILE)); defaultXmlLocations.add(Environment.buildPath(Environment.getVendorDirectory(), ETC_DIR, DISPLAY_CONFIG_DIR, DEFAULT_CONFIG_FILE)); // Read config_defaultUiModeType directly because UiModeManager hasn't started yet. final int uiModeType = context.getResources() .getInteger(com.android.internal.R.integer.config_defaultUiModeType); final String uiModeTypeStr = Configuration.getUiModeTypeString(uiModeType); if (uiModeTypeStr != null) { defaultXmlLocations.add(Environment.buildPath(Environment.getRootDirectory(), ETC_DIR, DISPLAY_CONFIG_DIR, String.format(DEFAULT_CONFIG_FILE_WITH_UIMODE_FORMAT, uiModeTypeStr))); } return config; defaultXmlLocations.add(Environment.buildPath(Environment.getRootDirectory(), ETC_DIR, DISPLAY_CONFIG_DIR, DEFAULT_CONFIG_FILE)); final File configFile = getFirstExistingFile(defaultXmlLocations); if (configFile == null) { // Display configuration files aren't required to exist. return null; } DisplayConfiguration defaultConfig = null; try (InputStream in = new BufferedInputStream(new FileInputStream(configFile))) { defaultConfig = XmlParser.read(in); if (defaultConfig == null) { Slog.i(TAG, "Default DisplayDeviceConfig file is null"); } } catch (IOException | DatatypeConfigurationException | XmlPullParserException e) { Slog.e(TAG, "Encountered an error while reading/parsing display config file: " + configFile, e); } return defaultConfig; } private static File getFirstExistingFile(Collection<File> files) { for (File file : files) { if (file.exists() && file.isFile()) { return file; } } return null; } private static DisplayDeviceConfig loadConfigFromDirectory(Context context, Loading Loading @@ -316,9 +380,13 @@ public class DisplayDeviceConfig { return mRefreshRateLimitations; } public DensityMap getDensityMap() { return mDensityMap; } @Override public String toString() { String str = "DisplayDeviceConfig{" return "DisplayDeviceConfig{" + "mLoadedFrom=" + mLoadedFrom + ", mBacklight=" + Arrays.toString(mBacklight) + ", mNits=" + Arrays.toString(mNits) Loading @@ -340,8 +408,8 @@ public class DisplayDeviceConfig { + ", mAmbientLightSensor=" + mAmbientLightSensor + ", mProximitySensor=" + mProximitySensor + ", mRefreshRateLimitations= " + Arrays.toString(mRefreshRateLimitations.toArray()) + ", mDensityMap= " + mDensityMap + "}"; return str; } private static DisplayDeviceConfig getConfigFromSuffix(Context context, File baseDirectory, Loading Loading @@ -384,6 +452,7 @@ public class DisplayDeviceConfig { try (InputStream in = new BufferedInputStream(new FileInputStream(configFile))) { final DisplayConfiguration config = XmlParser.read(in); if (config != null) { loadDensityMap(config); loadBrightnessDefaultFromDdcXml(config); loadBrightnessConstraintsFromConfigXml(); loadBrightnessMap(config); Loading Loading @@ -429,6 +498,35 @@ public class DisplayDeviceConfig { setProxSensorUnspecified(); } private void copyUninitializedValuesFromSecondaryConfig(DisplayConfiguration defaultConfig) { if (defaultConfig == null) { return; } if (mDensityMap == null) { loadDensityMap(defaultConfig); } } private void loadDensityMap(DisplayConfiguration config) { if (config.getDensityMap() == null) { return; } final List<Density> entriesFromXml = config.getDensityMap().getDensity(); final DensityMap.Entry[] entries = new DensityMap.Entry[entriesFromXml.size()]; for (int i = 0; i < entriesFromXml.size(); i++) { final Density density = entriesFromXml.get(i); entries[i] = new DensityMap.Entry( density.getWidth().intValue(), density.getHeight().intValue(), density.getDensity().intValue()); } mDensityMap = DensityMap.createByOwning(entries); } private void loadBrightnessDefaultFromDdcXml(DisplayConfiguration config) { // Default brightness values are stored in the displayDeviceConfig file, // Or we fallback standard values if not. Loading
services/core/java/com/android/server/display/LocalDisplayAdapter.java +11 −2 Original line number Diff line number Diff line Loading @@ -426,6 +426,15 @@ final class LocalDisplayAdapter extends DisplayAdapter { : mDefaultModeId; } private int getLogicalDensity() { DensityMap densityMap = getDisplayDeviceConfig().getDensityMap(); if (densityMap == null) { return (int) (mStaticDisplayInfo.density * 160 + 0.5); } return densityMap.getDensityForResolution(mInfo.width, mInfo.height); } private void loadDisplayDeviceConfig() { // Load display device config final Context context = getOverlayContext(); Loading Loading @@ -591,7 +600,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { final DisplayAddress.Physical physicalAddress = DisplayAddress.fromPhysicalDisplayId(mPhysicalDisplayId); mInfo.address = physicalAddress; mInfo.densityDpi = (int) (mStaticDisplayInfo.density * 160 + 0.5f); mInfo.densityDpi = getLogicalDensity(); mInfo.xDpi = mActiveSfDisplayMode.xDpi; mInfo.yDpi = mActiveSfDisplayMode.yDpi; mInfo.deviceProductInfo = mStaticDisplayInfo.deviceProductInfo; Loading Loading @@ -1029,7 +1038,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { for (int i = 0; i < mSupportedModes.size(); i++) { pw.println(" " + mSupportedModes.valueAt(i)); } pw.println("mSupportedColorModes=" + mSupportedColorModes.toString()); pw.println("mSupportedColorModes=" + mSupportedColorModes); pw.println("mDisplayDeviceConfig=" + mDisplayDeviceConfig); } Loading
services/core/java/com/android/server/wm/DisplayContent.java +14 −1 Original line number Diff line number Diff line Loading @@ -2833,8 +2833,14 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp mBaseDisplayDensity = baseDensity; if (mMaxUiWidth > 0 && mBaseDisplayWidth > mMaxUiWidth) { mBaseDisplayHeight = (mMaxUiWidth * mBaseDisplayHeight) / mBaseDisplayWidth; final float ratio = mMaxUiWidth / (float) mBaseDisplayWidth; mBaseDisplayHeight = (int) (mBaseDisplayHeight * ratio); mBaseDisplayWidth = mMaxUiWidth; if (!mIsDensityForced) { // Update the density proportionally so the size of the UI elements won't change // from the user's perspective. mBaseDisplayDensity = (int) (mBaseDisplayDensity * ratio); } if (DEBUG_DISPLAY) { Slog.v(TAG_WM, "Applying config restraints:" + mBaseDisplayWidth + "x" Loading Loading @@ -2891,6 +2897,13 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp /** If the given width and height equal to initial size, the setting will be cleared. */ void setForcedSize(int width, int height) { // Can't force size higher than the maximal allowed if (mMaxUiWidth > 0 && width > mMaxUiWidth) { final float ratio = mMaxUiWidth / (float) width; height = (int) (height * ratio); width = mMaxUiWidth; } mIsSizeForced = mInitialDisplayWidth != width || mInitialDisplayHeight != height; if (mIsSizeForced) { // Set some sort of reasonable bounds on the size of the display that we will try Loading