diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 5ffc4f0939b15..a0cb3df237509 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -673,15 +673,6 @@ --> - - - - - @@ -4675,15 +4666,6 @@ - - - - @@ -4163,7 +4162,6 @@ - diff --git a/services/core/Android.bp b/services/core/Android.bp index b67bdc20f7fae..99ce2db006ce4 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -97,6 +97,7 @@ java_library_static { ":platform-compat-config", ":platform-compat-overrides", ":display-device-config", + ":display-layout-config", ":cec-config", ":device-state-config", "java/com/android/server/EventLogTags.logtags", diff --git a/services/core/java/com/android/server/display/DeviceStateToLayoutMap.java b/services/core/java/com/android/server/display/DeviceStateToLayoutMap.java index 91674cd8afa60..1acd5d097525e 100644 --- a/services/core/java/com/android/server/display/DeviceStateToLayoutMap.java +++ b/services/core/java/com/android/server/display/DeviceStateToLayoutMap.java @@ -16,17 +16,26 @@ package com.android.server.display; -import android.content.Context; import android.hardware.devicestate.DeviceStateManager; -import android.text.TextUtils; +import android.os.Environment; import android.util.IndentingPrintWriter; import android.util.Slog; import android.util.SparseArray; import android.view.DisplayAddress; +import com.android.server.display.config.layout.Layouts; +import com.android.server.display.config.layout.XmlParser; import com.android.server.display.layout.Layout; -import java.util.Arrays; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; + +import javax.xml.datatype.DatatypeConfigurationException; /** * Mapping from device states into {@link Layout}s. This allows us to map device @@ -39,11 +48,14 @@ class DeviceStateToLayoutMap { public static final int STATE_DEFAULT = DeviceStateManager.INVALID_DEVICE_STATE; + private static final String CONFIG_FILE_PATH = + "etc/displayconfig/display_layout_configuration.xml"; + private final SparseArray mLayoutMap = new SparseArray<>(); - DeviceStateToLayoutMap(Context context) { - mLayoutMap.append(STATE_DEFAULT, new Layout()); - loadFoldedDisplayConfig(context); + DeviceStateToLayoutMap() { + loadLayoutsFromConfig(); + createLayout(STATE_DEFAULT); } public void dumpLocked(IndentingPrintWriter ipw) { @@ -76,48 +88,36 @@ class DeviceStateToLayoutMap { } /** - * Loads config.xml-specified folded configurations for foldable devices. + * Reads display-layout-configuration files to get the layouts to use for this device. */ - private void loadFoldedDisplayConfig(Context context) { - final String[] strDisplayIds = context.getResources().getStringArray( - com.android.internal.R.array.config_internalFoldedPhysicalDisplayIds); - if (strDisplayIds.length != 2 || TextUtils.isEmpty(strDisplayIds[0]) - || TextUtils.isEmpty(strDisplayIds[1])) { - Slog.w(TAG, "Folded display configuration invalid: [" + Arrays.toString(strDisplayIds) - + "]"); + private void loadLayoutsFromConfig() { + final File configFile = Environment.buildPath( + Environment.getVendorDirectory(), CONFIG_FILE_PATH); + + if (!configFile.exists()) { return; } - final long[] displayIds; - try { - displayIds = new long[] { - Long.parseLong(strDisplayIds[0]), - Long.parseLong(strDisplayIds[1]) - }; - } catch (NumberFormatException nfe) { - Slog.w(TAG, "Folded display config non numerical: " + Arrays.toString(strDisplayIds)); - return; - } - - final int[] foldedDeviceStates = context.getResources().getIntArray( - com.android.internal.R.array.config_foldedDeviceStates); - final int[] unfoldedDeviceStates = context.getResources().getIntArray( - com.android.internal.R.array.config_unfoldedDeviceStates); - // Only add folded states if folded state config is not empty - if (foldedDeviceStates.length == 0 || unfoldedDeviceStates.length == 0) { - return; - } - - for (int state : foldedDeviceStates) { - // Create the folded state layout - createLayout(state).createDisplayLocked( - DisplayAddress.fromPhysicalDisplayId(displayIds[0]), true /*isDefault*/); - } - - for (int state : unfoldedDeviceStates) { - // Create the unfolded state layout - createLayout(state).createDisplayLocked( - DisplayAddress.fromPhysicalDisplayId(displayIds[1]), true /*isDefault*/); + Slog.i(TAG, "Loading display layouts from " + configFile); + try (InputStream in = new BufferedInputStream(new FileInputStream(configFile))) { + final Layouts layouts = XmlParser.read(in); + if (layouts == null) { + Slog.i(TAG, "Display layout config not found: " + configFile); + return; + } + for (com.android.server.display.config.layout.Layout l : layouts.getLayout()) { + final int state = l.getState().intValue(); + final Layout layout = createLayout(state); + for (com.android.server.display.config.layout.Display d: l.getDisplay()) { + layout.createDisplayLocked( + DisplayAddress.fromPhysicalDisplayId(d.getAddress().longValue()), + d.getIsDefault(), + d.getEnabled()); + } + } + } catch (IOException | DatatypeConfigurationException | XmlPullParserException e) { + Slog.e(TAG, "Encountered an error while reading/parsing display layout config file: " + + configFile, e); } } } diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index ce0ba9f3231c8..174d4b2fe00d8 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -423,7 +423,7 @@ public final class DisplayManagerService extends SystemService { mHandler = new DisplayManagerHandler(DisplayThread.get().getLooper()); mUiHandler = UiThread.getHandler(); mDisplayDeviceRepo = new DisplayDeviceRepository(mSyncRoot, mPersistentDataStore); - mLogicalDisplayMapper = new LogicalDisplayMapper(context, mDisplayDeviceRepo, + mLogicalDisplayMapper = new LogicalDisplayMapper(mDisplayDeviceRepo, new LogicalDisplayListener()); mDisplayModeDirector = new DisplayModeDirector(context, mHandler); mBrightnessSynchronizer = new BrightnessSynchronizer(mContext); @@ -1178,7 +1178,10 @@ public final class DisplayManagerService extends SystemService { private void handleLogicalDisplayRemovedLocked(@NonNull LogicalDisplay display) { final int displayId = display.getDisplayIdLocked(); - mDisplayPowerControllers.removeReturnOld(displayId).stop(); + final DisplayPowerController dpc = mDisplayPowerControllers.removeReturnOld(displayId); + if (dpc != null) { + dpc.stop(); + } mDisplayStates.delete(displayId); mDisplayBrightnesses.delete(displayId); DisplayManagerGlobal.invalidateLocalDisplayInfoCaches(); @@ -1200,9 +1203,6 @@ public final class DisplayManagerService extends SystemService { // by the display power controller (if known). DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) { - // TODO - b/170498827 The rules regarding what display state to apply to each - // display will depend on the configuration/mapping of logical displays. - // Clean up LogicalDisplay.isEnabled() mechanism once this is fixed. final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device); final int state; final int displayId = display.getDisplayIdLocked(); diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java index 2bcc35cf176f9..d6826be248df3 100644 --- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java +++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java @@ -16,7 +16,6 @@ package com.android.server.display; -import android.content.Context; import android.hardware.devicestate.DeviceStateManager; import android.os.SystemProperties; import android.text.TextUtils; @@ -90,7 +89,6 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { private final DisplayDeviceRepository mDisplayDeviceRepo; private final DeviceStateToLayoutMap mDeviceStateToLayoutMap; private final Listener mListener; - private final int[] mFoldedDeviceStates; /** * Has an entry for every logical display that the rest of the system has been notified about. @@ -122,16 +120,12 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { private Layout mCurrentLayout = null; private int mDeviceState = DeviceStateManager.INVALID_DEVICE_STATE; - LogicalDisplayMapper(Context context, DisplayDeviceRepository repo, Listener listener) { + LogicalDisplayMapper(DisplayDeviceRepository repo, Listener listener) { mDisplayDeviceRepo = repo; mListener = listener; mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false); mDisplayDeviceRepo.addListener(this); - - mFoldedDeviceStates = context.getResources().getIntArray( - com.android.internal.R.array.config_foldedDeviceStates); - - mDeviceStateToLayoutMap = new DeviceStateToLayoutMap(context); + mDeviceStateToLayoutMap = new DeviceStateToLayoutMap(); } @Override @@ -470,10 +464,10 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { } /** - * Resets the current layout in preparation for a new layout; essentially just marks - * all the currently layed out displays as disabled. This ensures the display devices - * are turned off. If they are meant to be used in the new layout, - * {@link #applyLayoutLocked()} will reenabled them. + * Resets the current layout in preparation for a new layout. Layouts can specify if some + * displays should be disabled (OFF). When switching from one layout to another, we go + * through each of the displays and make sure any displays we might have disabled are + * enabled again. */ private void resetLayoutLocked() { final Layout layout = mDeviceStateToLayoutMap.get(mDeviceState); @@ -481,7 +475,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { final Layout.Display displayLayout = layout.getAt(i); final LogicalDisplay display = getDisplayLocked(displayLayout.getLogicalDisplayId()); if (display != null) { - enableDisplayLocked(display, false); + enableDisplayLocked(display, true); // Reset all displays back to enabled } } } @@ -503,7 +497,8 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { // If the underlying display-device we want to use for this display // doesn't exist, then skip it. This can happen at startup as display-devices - // trickle in one at a time, or if the layout has an error. + // trickle in one at a time. When the new display finally shows up, the layout is + // recalculated so that the display is properly added to the current layout. final DisplayAddress address = displayLayout.getAddress(); final DisplayDevice device = mDisplayDeviceRepo.getByAddressLocked(address); if (device == null) { @@ -526,7 +521,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { if (newDisplay != oldDisplay) { newDisplay.swapDisplaysLocked(oldDisplay); } - enableDisplayLocked(newDisplay, true); + enableDisplayLocked(newDisplay, displayLayout.isEnabled()); } } @@ -545,13 +540,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { final LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device); display.updateLocked(mDisplayDeviceRepo); mLogicalDisplays.put(displayId, display); - - // Internal displays start off disabled. The display is enabled later if it is part of the - // currently selected display layout. - final boolean isEnabled = device != null - && device.getDisplayDeviceInfoLocked().type != Display.TYPE_INTERNAL; - enableDisplayLocked(display, isEnabled); - + enableDisplayLocked(display, device != null); return display; } @@ -582,7 +571,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener { final Layout layoutSet = mDeviceStateToLayoutMap.get(DeviceStateToLayoutMap.STATE_DEFAULT); final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); final boolean isDefault = (info.flags & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0; - layoutSet.createDisplayLocked(info.address, isDefault); + layoutSet.createDisplayLocked(info.address, isDefault, true /* isEnabled */); } private int assignLayerStackLocked(int displayId) { diff --git a/services/core/java/com/android/server/display/layout/Layout.java b/services/core/java/com/android/server/display/layout/Layout.java index 18f39e6ade1d2..ef336674df5d5 100644 --- a/services/core/java/com/android/server/display/layout/Layout.java +++ b/services/core/java/com/android/server/display/layout/Layout.java @@ -57,7 +57,7 @@ public class Layout { * @return The new layout. */ public Display createDisplayLocked( - @NonNull DisplayAddress address, boolean isDefault) { + @NonNull DisplayAddress address, boolean isDefault, boolean isEnabled) { if (contains(address)) { Slog.w(TAG, "Attempting to add second definition for display-device: " + address); return null; @@ -74,7 +74,7 @@ public class Layout { // different layouts, a logical display can be destroyed and later recreated with the // same logical display ID. final int logicalDisplayId = assignDisplayIdLocked(isDefault); - final Display layout = new Display(address, logicalDisplayId); + final Display layout = new Display(address, logicalDisplayId, isEnabled); mDisplays.add(layout); return layout; @@ -130,17 +130,25 @@ public class Layout { * Describes how a {@link LogicalDisplay} is built from {@link DisplayDevice}s. */ public static class Display { + // Address of the display device to map to this display. private final DisplayAddress mAddress; + + // Logical Display ID to apply to this display. private final int mLogicalDisplayId; - Display(@NonNull DisplayAddress address, int logicalDisplayId) { + // Indicates that this display is not usable and should remain off. + private final boolean mIsEnabled; + + Display(@NonNull DisplayAddress address, int logicalDisplayId, boolean isEnabled) { mAddress = address; mLogicalDisplayId = logicalDisplayId; + mIsEnabled = isEnabled; } @Override public String toString() { - return "{addr: " + mAddress + ", dispId: " + mLogicalDisplayId + "}"; + return "{addr: " + mAddress + ", dispId: " + mLogicalDisplayId + + "(" + (mIsEnabled ? "ON" : "OFF") + ")}"; } public DisplayAddress getAddress() { @@ -150,5 +158,9 @@ public class Layout { public int getLogicalDisplayId() { return mLogicalDisplayId; } + + public boolean isEnabled() { + return mIsEnabled; + } } } diff --git a/services/core/xsd/Android.bp b/services/core/xsd/Android.bp index c285ef519e441..6a8f6d4197860 100644 --- a/services/core/xsd/Android.bp +++ b/services/core/xsd/Android.bp @@ -30,7 +30,6 @@ xsd_config { gen_writer: true, } - xsd_config { name: "display-device-config", srcs: ["display-device-config/display-device-config.xsd"], @@ -38,6 +37,12 @@ xsd_config { package_name: "com.android.server.display.config", } +xsd_config { + name: "display-layout-config", + srcs: ["display-layout-config/display-layout-config.xsd"], + api_dir: "display-layout-config/schema", + package_name: "com.android.server.display.config.layout", +} xsd_config { name: "cec-config", diff --git a/services/core/xsd/display-device-config/display-device-config.xsd b/services/core/xsd/display-device-config/display-device-config.xsd index 7d705c1fac690..e4b961299f122 100644 --- a/services/core/xsd/display-device-config/display-device-config.xsd +++ b/services/core/xsd/display-device-config/display-device-config.xsd @@ -1,23 +1,24 @@ + Copyright (C) 2020 The Android Open Source Project - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/services/core/xsd/display-layout-config/schema/current.txt b/services/core/xsd/display-layout-config/schema/current.txt new file mode 100644 index 0000000000000..817188509f81b --- /dev/null +++ b/services/core/xsd/display-layout-config/schema/current.txt @@ -0,0 +1,34 @@ +// Signature format: 2.0 +package com.android.server.display.config.layout { + + public class Display { + ctor public Display(); + method public java.math.BigInteger getAddress(); + method public boolean getEnabled(); + method public boolean getIsDefault(); + method public void setAddress(java.math.BigInteger); + method public void setEnabled(boolean); + method public void setIsDefault(boolean); + } + + public class Layout { + ctor public Layout(); + method public java.util.List getDisplay(); + method public java.math.BigInteger getState(); + method public void setState(java.math.BigInteger); + } + + public class Layouts { + ctor public Layouts(); + method public java.util.List getLayout(); + } + + public class XmlParser { + ctor public XmlParser(); + method public static com.android.server.display.config.layout.Layouts read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException; + method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; + method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; + } + +} + diff --git a/services/core/xsd/display-layout-config/schema/last_current.txt b/services/core/xsd/display-layout-config/schema/last_current.txt new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/services/core/xsd/display-layout-config/schema/last_removed.txt b/services/core/xsd/display-layout-config/schema/last_removed.txt new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/services/core/xsd/display-layout-config/schema/removed.txt b/services/core/xsd/display-layout-config/schema/removed.txt new file mode 100644 index 0000000000000..d802177e249b3 --- /dev/null +++ b/services/core/xsd/display-layout-config/schema/removed.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java index 92221c9713d3c..bcd853c76a792 100644 --- a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java +++ b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java @@ -94,8 +94,7 @@ public class LogicalDisplayMapperTest { // Disable binder caches in this process. PropertyInvalidatedCache.disableForTestMode(); - mLogicalDisplayMapper = new LogicalDisplayMapper( - mContext, mDisplayDeviceRepo, mListenerMock); + mLogicalDisplayMapper = new LogicalDisplayMapper(mDisplayDeviceRepo, mListenerMock); }