diff options
| author | 2024-01-08 09:32:53 +0000 | |
|---|---|---|
| committer | 2024-01-08 09:32:53 +0000 | |
| commit | 68101dbb91f35514c404ebb37d2f913514cc032c (patch) | |
| tree | 4f513859044bd4302a9dab86fbb367b242a01b0b | |
| parent | 7e7a8b844331e01214e7142c124296cc74cbcc68 (diff) | |
| parent | f477d54c689dce4af9835d3149c93ec93fa738ea (diff) | |
Merge "Specify display by Port in display-layout-config" into main
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() { |