summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Santos Cordon <santoscordon@google.com> 2024-01-08 09:32:53 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2024-01-08 09:32:53 +0000
commit68101dbb91f35514c404ebb37d2f913514cc032c (patch)
tree4f513859044bd4302a9dab86fbb367b242a01b0b
parent7e7a8b844331e01214e7142c124296cc74cbcc68 (diff)
parentf477d54c689dce4af9835d3149c93ec93fa738ea (diff)
Merge "Specify display by Port in display-layout-config" into main
-rw-r--r--core/java/android/view/DisplayAddress.java24
-rw-r--r--services/core/java/com/android/server/display/DeviceStateToLayoutMap.java29
-rw-r--r--services/core/java/com/android/server/display/DisplayDeviceRepository.java4
-rw-r--r--services/core/java/com/android/server/display/LogicalDisplayMapper.java6
-rw-r--r--services/core/java/com/android/server/display/feature/DisplayManagerFlags.java10
-rw-r--r--services/core/java/com/android/server/display/feature/display_flags.aconfig8
-rw-r--r--services/core/java/com/android/server/display/layout/Layout.java11
-rw-r--r--services/core/xsd/display-layout-config/display-layout-config.xsd9
-rw-r--r--services/core/xsd/display-layout-config/schema/current.txt6
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/DeviceStateToLayoutMapTest.java60
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java10
11 files changed, 151 insertions, 26 deletions
diff --git a/core/java/android/view/DisplayAddress.java b/core/java/android/view/DisplayAddress.java
index 99e811a72605..c3c4ab52d5ef 100644
--- a/core/java/android/view/DisplayAddress.java
+++ b/core/java/android/view/DisplayAddress.java
@@ -138,6 +138,30 @@ public abstract class DisplayAddress implements Parcelable {
out.writeLong(mPhysicalDisplayId);
}
+ /**
+ * This method is meant to check to see if the ports match
+ * @param a1 Address to compare
+ * @param a2 Address to compare
+ *
+ * @return true if the arguments have the same port, and at least one does not specify
+ * a model.
+ */
+ public static boolean isPortMatch(DisplayAddress a1, DisplayAddress a2) {
+ // Both displays must be of type Physical
+ if (!(a1 instanceof Physical && a2 instanceof Physical)) {
+ return false;
+ }
+ Physical p1 = (Physical) a1;
+ Physical p2 = (Physical) a2;
+
+ // If both addresses specify a model, fallback to a basic match check (which
+ // also checks the port).
+ if (p1.getModel() != null && p2.getModel() != null) {
+ return p1.equals(p2);
+ }
+ return p1.getPort() == p2.getPort();
+ }
+
private Physical(long physicalDisplayId) {
mPhysicalDisplayId = physicalDisplayId;
}
diff --git a/services/core/java/com/android/server/display/DeviceStateToLayoutMap.java b/services/core/java/com/android/server/display/DeviceStateToLayoutMap.java
index 7cea9c422b4d..e54f30fa29f1 100644
--- a/services/core/java/com/android/server/display/DeviceStateToLayoutMap.java
+++ b/services/core/java/com/android/server/display/DeviceStateToLayoutMap.java
@@ -27,6 +27,7 @@ import android.view.DisplayAddress;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.display.config.layout.Layouts;
import com.android.server.display.config.layout.XmlParser;
+import com.android.server.display.feature.DisplayManagerFlags;
import com.android.server.display.layout.DisplayIdProducer;
import com.android.server.display.layout.Layout;
@@ -68,12 +69,15 @@ class DeviceStateToLayoutMap {
private final SparseArray<Layout> mLayoutMap = new SparseArray<>();
private final DisplayIdProducer mIdProducer;
+ private final boolean mIsPortInDisplayLayoutEnabled;
- DeviceStateToLayoutMap(DisplayIdProducer idProducer) {
- this(idProducer, getConfigFile());
+ DeviceStateToLayoutMap(DisplayIdProducer idProducer, DisplayManagerFlags flags) {
+ this(idProducer, flags, getConfigFile());
}
- DeviceStateToLayoutMap(DisplayIdProducer idProducer, File configFile) {
+ DeviceStateToLayoutMap(DisplayIdProducer idProducer, DisplayManagerFlags flags,
+ File configFile) {
+ mIsPortInDisplayLayoutEnabled = flags.isPortInDisplayLayoutEnabled();
mIdProducer = idProducer;
loadLayoutsFromConfig(configFile);
createLayout(STATE_DEFAULT);
@@ -93,6 +97,7 @@ class DeviceStateToLayoutMap {
ipw.println("DeviceStateToLayoutMap:");
ipw.increaseIndent();
+ ipw.println("mIsPortInDisplayLayoutEnabled=" + mIsPortInDisplayLayoutEnabled);
ipw.println("Registered Layouts:");
for (int i = 0; i < mLayoutMap.size(); i++) {
ipw.println("state(" + mLayoutMap.keyAt(i) + "): " + mLayoutMap.valueAt(i));
@@ -132,13 +137,15 @@ class DeviceStateToLayoutMap {
final Layout layout = createLayout(state);
for (com.android.server.display.config.layout.Display d: l.getDisplay()) {
assert layout != null;
+ final DisplayAddress address = getDisplayAddressForLayoutDisplay(d);
+
int position = getPosition(d.getPosition());
BigInteger leadDisplayPhysicalId = d.getLeadDisplayAddress();
DisplayAddress leadDisplayAddress = leadDisplayPhysicalId == null ? null
: DisplayAddress.fromPhysicalDisplayId(
leadDisplayPhysicalId.longValue());
layout.createDisplayLocked(
- DisplayAddress.fromPhysicalDisplayId(d.getAddress().longValue()),
+ address,
d.isDefaultDisplay(),
d.isEnabled(),
d.getDisplayGroup(),
@@ -158,6 +165,20 @@ class DeviceStateToLayoutMap {
}
}
+ private DisplayAddress getDisplayAddressForLayoutDisplay(
+ @NonNull com.android.server.display.config.layout.Display display) {
+ BigInteger xmlAddress = display.getAddress_optional();
+ if (xmlAddress != null) {
+ return DisplayAddress.fromPhysicalDisplayId(xmlAddress.longValue());
+ }
+ if (!mIsPortInDisplayLayoutEnabled || display.getPort_optional() == null) {
+ throw new IllegalArgumentException(
+ "Must specify a display identifier in display layout configuration: " + display);
+ }
+ return DisplayAddress.fromPortAndModel((int) display.getPort_optional().longValue(),
+ /* model= */ null);
+ }
+
private int getPosition(@NonNull String position) {
int positionInt = POSITION_UNKNOWN;
if (FRONT_STRING.equals(position)) {
diff --git a/services/core/java/com/android/server/display/DisplayDeviceRepository.java b/services/core/java/com/android/server/display/DisplayDeviceRepository.java
index 67e612d1fd99..6164154b1e63 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceRepository.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceRepository.java
@@ -129,7 +129,9 @@ class DisplayDeviceRepository implements DisplayAdapter.Listener {
public DisplayDevice getByAddressLocked(@NonNull DisplayAddress address) {
for (int i = mDisplayDevices.size() - 1; i >= 0; i--) {
final DisplayDevice device = mDisplayDevices.get(i);
- if (address.equals(device.getDisplayDeviceInfoLocked().address)) {
+ final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
+ if (address.equals(info.address)
+ || DisplayAddress.Physical.isPortMatch(address, info.address)) {
return device;
}
}
diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
index 115111a4afa3..2e8de31f2af1 100644
--- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java
+++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
@@ -205,7 +205,7 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
@NonNull Handler handler, DisplayManagerFlags flags) {
this(context, foldSettingProvider, repo, listener, syncRoot, handler,
new DeviceStateToLayoutMap((isDefault) -> isDefault ? DEFAULT_DISPLAY
- : sNextNonDefaultDisplayId++), flags);
+ : sNextNonDefaultDisplayId++, flags), flags);
}
LogicalDisplayMapper(@NonNull Context context, FoldSettingProvider foldSettingProvider,
@@ -1094,8 +1094,8 @@ class LogicalDisplayMapper implements DisplayDeviceRepository.Listener {
final DisplayAddress address = displayLayout.getAddress();
final DisplayDevice device = mDisplayDeviceRepo.getByAddressLocked(address);
if (device == null) {
- Slog.w(TAG, "The display device (" + address + "), is not available"
- + " for the display state " + mDeviceState);
+ Slog.w(TAG, "applyLayoutLocked: The display device (" + address + "), is not "
+ + "available for the display state " + mDeviceState);
continue;
}
diff --git a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
index 35991b356bba..be48eb437dfe 100644
--- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
+++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
@@ -37,6 +37,9 @@ public class DisplayManagerFlags {
// 'adb shell setprop persist.log.tag.DisplayManagerFlags DEBUG && adb reboot'
private static final boolean DEBUG = DebugUtils.isDebuggable(TAG);
+ private final FlagState mPortInDisplayLayoutFlagState = new FlagState(
+ Flags.FLAG_ENABLE_PORT_IN_DISPLAY_LAYOUT,
+ Flags::enablePortInDisplayLayout);
private final FlagState mConnectedDisplayManagementFlagState = new FlagState(
Flags.FLAG_ENABLE_CONNECTED_DISPLAY_MANAGEMENT,
@@ -114,6 +117,13 @@ public class DisplayManagerFlags {
Flags::refreshRateVotingTelemetry
);
+ /**
+ * @return {@code true} if 'port' is allowed in display layout configuration file.
+ */
+ public boolean isPortInDisplayLayoutEnabled() {
+ return mPortInDisplayLayoutFlagState.isEnabled();
+ }
+
/** Returns whether connected display management is enabled or not. */
public boolean isConnectedDisplayManagementEnabled() {
return mConnectedDisplayManagementFlagState.isEnabled();
diff --git a/services/core/java/com/android/server/display/feature/display_flags.aconfig b/services/core/java/com/android/server/display/feature/display_flags.aconfig
index e735282a496e..c9569cbf4b9a 100644
--- a/services/core/java/com/android/server/display/feature/display_flags.aconfig
+++ b/services/core/java/com/android/server/display/feature/display_flags.aconfig
@@ -3,6 +3,14 @@ package: "com.android.server.display.feature.flags"
# Important: Flags must be accessed through DisplayManagerFlags.
flag {
+ name: "enable_port_in_display_layout"
+ namespace: "display_manager"
+ description: "Allows refering to displays by port in display layout"
+ bug: "303058435"
+ is_fixed_read_only: true
+}
+
+flag {
name: "enable_connected_display_management"
namespace: "display_manager"
description: "Feature flag for Connected Display management"
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 40cb3303adda..8a362f78a9a3 100644
--- a/services/core/java/com/android/server/display/layout/Layout.java
+++ b/services/core/java/com/android/server/display/layout/Layout.java
@@ -200,13 +200,7 @@ public class Layout {
* @return True if the specified address is used in this layout.
*/
public boolean contains(@NonNull DisplayAddress address) {
- final int size = mDisplays.size();
- for (int i = 0; i < size; i++) {
- if (address.equals(mDisplays.get(i).getAddress())) {
- return true;
- }
- }
- return false;
+ return getByAddress(address) != null;
}
/**
@@ -237,6 +231,9 @@ public class Layout {
if (address.equals(display.getAddress())) {
return display;
}
+ if (DisplayAddress.Physical.isPortMatch(address, display.getAddress())) {
+ return display;
+ }
}
return null;
}
diff --git a/services/core/xsd/display-layout-config/display-layout-config.xsd b/services/core/xsd/display-layout-config/display-layout-config.xsd
index 4e954653bcbb..73c13cec6bc2 100644
--- a/services/core/xsd/display-layout-config/display-layout-config.xsd
+++ b/services/core/xsd/display-layout-config/display-layout-config.xsd
@@ -49,7 +49,7 @@
<xs:complexType name="display">
<xs:sequence>
- <xs:element name="address" type="xs:nonNegativeInteger"/>
+ <xs:group ref="displayReference" minOccurs="1" maxOccurs="1"/>
<xs:element name="position" type="xs:string" minOccurs="0" maxOccurs="1" />
<xs:element name="brightnessThrottlingMapId" type="xs:string" minOccurs="0" maxOccurs="1" />
<xs:element name="powerThrottlingMapId" type="xs:string" minOccurs="0" maxOccurs="1" />
@@ -67,4 +67,11 @@
</xs:simpleType>
</xs:attribute>
</xs:complexType>
+
+ <xs:group name="displayReference">
+ <xs:choice>
+ <xs:element name="address" type="xs:nonNegativeInteger" minOccurs="0"/>
+ <xs:element name="port" type="xs:nonNegativeInteger" minOccurs="0"/>
+ </xs:choice>
+ </xs:group>
</xs:schema>
diff --git a/services/core/xsd/display-layout-config/schema/current.txt b/services/core/xsd/display-layout-config/schema/current.txt
index 195cae5aee14..0d2f6a89ac25 100644
--- a/services/core/xsd/display-layout-config/schema/current.txt
+++ b/services/core/xsd/display-layout-config/schema/current.txt
@@ -3,22 +3,24 @@ package com.android.server.display.config.layout {
public class Display {
ctor public Display();
- method public java.math.BigInteger getAddress();
+ method public java.math.BigInteger getAddress_optional();
method public String getBrightnessThrottlingMapId();
method public String getDisplayGroup();
method public java.math.BigInteger getLeadDisplayAddress();
+ method public java.math.BigInteger getPort_optional();
method public String getPosition();
method public String getPowerThrottlingMapId();
method public String getRefreshRateThermalThrottlingMapId();
method public String getRefreshRateZoneId();
method public boolean isDefaultDisplay();
method public boolean isEnabled();
- method public void setAddress(java.math.BigInteger);
+ method public void setAddress_optional(java.math.BigInteger);
method public void setBrightnessThrottlingMapId(String);
method public void setDefaultDisplay(boolean);
method public void setDisplayGroup(String);
method public void setEnabled(boolean);
method public void setLeadDisplayAddress(java.math.BigInteger);
+ method public void setPort_optional(java.math.BigInteger);
method public void setPosition(String);
method public void setPowerThrottlingMapId(String);
method public void setRefreshRateThermalThrottlingMapId(String);
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DeviceStateToLayoutMapTest.java b/services/tests/displayservicetests/src/com/android/server/display/DeviceStateToLayoutMapTest.java
index 8cc3408ad79b..567792ecb6e0 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DeviceStateToLayoutMapTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DeviceStateToLayoutMapTest.java
@@ -25,6 +25,7 @@ import android.view.DisplayAddress;
import androidx.test.filters.SmallTest;
+import com.android.server.display.feature.DisplayManagerFlags;
import com.android.server.display.layout.DisplayIdProducer;
import com.android.server.display.layout.Layout;
@@ -45,6 +46,7 @@ public class DeviceStateToLayoutMapTest {
private DeviceStateToLayoutMap mDeviceStateToLayoutMap;
@Mock DisplayIdProducer mDisplayIdProducerMock;
+ @Mock DisplayManagerFlags mMockFlags;
@Before
public void setUp() throws IOException {
@@ -52,7 +54,7 @@ public class DeviceStateToLayoutMapTest {
Mockito.when(mDisplayIdProducerMock.getId(false)).thenReturn(1);
- setupDeviceStateToLayoutMap();
+ setupDeviceStateToLayoutMap(getContent());
}
//////////////////
@@ -268,6 +270,41 @@ public class DeviceStateToLayoutMapTest {
IllegalArgumentException.class, () -> layout.postProcessLocked());
}
+ @Test
+ public void testPortInLayout_disabledFlag() {
+ Mockito.when(mMockFlags.isPortInDisplayLayoutEnabled()).thenReturn(false);
+ assertThrows("Expected IllegalArgumentException when using <port>",
+ IllegalArgumentException.class,
+ () -> setupDeviceStateToLayoutMap(getPortContent()));
+ }
+
+ @Test
+ public void testPortInLayout_readLayout() throws Exception {
+ Mockito.when(mMockFlags.isPortInDisplayLayoutEnabled()).thenReturn(true);
+ setupDeviceStateToLayoutMap(getPortContent());
+
+ Layout configLayout = mDeviceStateToLayoutMap.get(0);
+
+ Layout testLayout = new Layout();
+ testLayout.createDisplayLocked(DisplayAddress.fromPortAndModel(123, null),
+ /* isDefault= */ true, /* isEnabled= */ true, /* displayGroupName= */ null,
+ mDisplayIdProducerMock, Layout.Display.POSITION_UNKNOWN,
+ /* leadDisplayAddress= */ null, /* brightnessThrottlingMapId= */ null,
+ /* refreshRateZoneId= */ null,
+ /* refreshRateThermalThrottlingMapId= */ null,
+ /* powerThrottlingMapId= */ null);
+ testLayout.createDisplayLocked(DisplayAddress.fromPhysicalDisplayId(78910L),
+ /* isDefault= */ false, /* isEnabled= */ false, /* displayGroupName= */ null,
+ mDisplayIdProducerMock, Layout.Display.POSITION_UNKNOWN,
+ /* leadDisplayAddress= */ null, /* brightnessThrottlingMapId= */ null,
+ /* refreshRateZoneId= */ null,
+ /* refreshRateThermalThrottlingMapId= */ null,
+ /* powerThrottlingMapId= */ null);
+ testLayout.postProcessLocked();
+
+ assertEquals(testLayout, configLayout);
+ }
+
////////////////////
// Helper Methods //
////////////////////
@@ -287,13 +324,28 @@ public class DeviceStateToLayoutMapTest {
/* powerThrottlingMapId= */ null);
}
- private void setupDeviceStateToLayoutMap() throws IOException {
+ private void setupDeviceStateToLayoutMap(String content) throws IOException {
Path tempFile = Files.createTempFile("device_state_layout_map", ".tmp");
- Files.write(tempFile, getContent().getBytes(StandardCharsets.UTF_8));
- mDeviceStateToLayoutMap = new DeviceStateToLayoutMap(mDisplayIdProducerMock,
+ Files.write(tempFile, content.getBytes(StandardCharsets.UTF_8));
+ mDeviceStateToLayoutMap = new DeviceStateToLayoutMap(mDisplayIdProducerMock, mMockFlags,
tempFile.toFile());
}
+ private String getPortContent() {
+ return "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ + "<layouts>\n"
+ + "<layout>\n"
+ + "<state>0</state> \n"
+ + "<display enabled=\"true\" defaultDisplay=\"true\">\n"
+ + "<port>123</port>\n"
+ + "</display>\n"
+ + "<display enabled=\"false\">\n"
+ + "<address>78910</address>\n"
+ + "</display>\n"
+ + "</layout>\n"
+ + "</layouts>\n";
+ }
+
private String getContent() {
return "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+ "<layouts>\n"
diff --git a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
index 28ec89629df0..bed6f928a55c 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
@@ -49,8 +49,9 @@ import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.times;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -83,7 +84,6 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import org.mockito.Spy;
import java.io.File;
import java.io.InputStream;
@@ -111,14 +111,14 @@ public class LogicalDisplayMapperTest {
private final DisplayIdProducer mIdProducer = (isDefault) ->
isDefault ? DEFAULT_DISPLAY : sNextNonDefaultDisplayId++;
+ private DeviceStateToLayoutMap mDeviceStateToLayoutMapSpy;
+
@Mock LogicalDisplayMapper.Listener mListenerMock;
@Mock Context mContextMock;
@Mock FoldSettingProvider mFoldSettingProviderMock;
@Mock Resources mResourcesMock;
@Mock IPowerManager mIPowerManagerMock;
@Mock IThermalService mIThermalServiceMock;
- @Spy DeviceStateToLayoutMap mDeviceStateToLayoutMapSpy =
- new DeviceStateToLayoutMap(mIdProducer, NON_EXISTING_FILE);
@Mock DisplayManagerFlags mFlagsMock;
@Mock DisplayAdapter mDisplayAdapterMock;
@@ -131,6 +131,8 @@ public class LogicalDisplayMapperTest {
System.setProperty("dexmaker.share_classloader", "true");
MockitoAnnotations.initMocks(this);
+ mDeviceStateToLayoutMapSpy =
+ spy(new DeviceStateToLayoutMap(mIdProducer, mFlagsMock, NON_EXISTING_FILE));
mDisplayDeviceRepo = new DisplayDeviceRepository(
new DisplayManagerService.SyncRoot(),
new PersistentDataStore(new PersistentDataStore.Injector() {