Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f40bd478 authored by Eric Jeong's avatar Eric Jeong
Browse files

Add leadDisplayAddress to display-layout-config

- If leadDisplayAddress is not specified in display-layout-config XML,
  no lead display is set.
- This CL will set a lead display according to leadDisplayAddress in
  display-layout-config.

Bug: 274391981
Test: atest DeviceStateToLayoutmapTest
Change-Id: I6f9272ff41429f64c8e55984182c55a9ccebd9f7
parent b6ca21a6
Loading
Loading
Loading
Loading
+7 −3
Original line number Original line Diff line number Diff line
@@ -22,7 +22,6 @@ import android.os.Environment;
import android.util.IndentingPrintWriter;
import android.util.IndentingPrintWriter;
import android.util.Slog;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseArray;
import android.view.Display;
import android.view.DisplayAddress;
import android.view.DisplayAddress;


import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting;
@@ -38,6 +37,7 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStream;
import java.math.BigInteger;


import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeConfigurationException;


@@ -115,13 +115,16 @@ class DeviceStateToLayoutMap {
                Slog.i(TAG, "Display layout config not found: " + configFile);
                Slog.i(TAG, "Display layout config not found: " + configFile);
                return;
                return;
            }
            }
            int leadDisplayId = Display.DEFAULT_DISPLAY;
            for (com.android.server.display.config.layout.Layout l : layouts.getLayout()) {
            for (com.android.server.display.config.layout.Layout l : layouts.getLayout()) {
                final int state = l.getState().intValue();
                final int state = l.getState().intValue();
                final Layout layout = createLayout(state);
                final Layout layout = createLayout(state);
                for (com.android.server.display.config.layout.Display d: l.getDisplay()) {
                for (com.android.server.display.config.layout.Display d: l.getDisplay()) {
                    assert layout != null;
                    assert layout != null;
                    int position = getPosition(d.getPosition());
                    int position = getPosition(d.getPosition());
                    BigInteger leadDisplayPhysicalId = d.getLeadDisplayAddress();
                    DisplayAddress leadDisplayAddress = leadDisplayPhysicalId == null ? null
                            : DisplayAddress.fromPhysicalDisplayId(
                                    leadDisplayPhysicalId.longValue());
                    layout.createDisplayLocked(
                    layout.createDisplayLocked(
                            DisplayAddress.fromPhysicalDisplayId(d.getAddress().longValue()),
                            DisplayAddress.fromPhysicalDisplayId(d.getAddress().longValue()),
                            d.isDefaultDisplay(),
                            d.isDefaultDisplay(),
@@ -129,11 +132,12 @@ class DeviceStateToLayoutMap {
                            d.getDisplayGroup(),
                            d.getDisplayGroup(),
                            mIdProducer,
                            mIdProducer,
                            position,
                            position,
                            leadDisplayId,
                            leadDisplayAddress,
                            d.getBrightnessThrottlingMapId(),
                            d.getBrightnessThrottlingMapId(),
                            d.getRefreshRateZoneId(),
                            d.getRefreshRateZoneId(),
                            d.getRefreshRateThermalThrottlingMapId());
                            d.getRefreshRateThermalThrottlingMapId());
                }
                }
                layout.postProcessLocked();
            }
            }
        } catch (IOException | DatatypeConfigurationException | XmlPullParserException e) {
        } catch (IOException | DatatypeConfigurationException | XmlPullParserException e) {
            Slog.e(TAG, "Encountered an error while reading/parsing display layout config file: "
            Slog.e(TAG, "Encountered an error while reading/parsing display layout config file: "
+97 −16
Original line number Original line Diff line number Diff line
@@ -22,6 +22,8 @@ import static com.android.server.display.layout.Layout.Display.POSITION_UNKNOWN;


import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Slog;
import android.util.Slog;
import android.view.DisplayAddress;
import android.view.DisplayAddress;


@@ -77,7 +79,7 @@ public class Layout {
            DisplayIdProducer idProducer) {
            DisplayIdProducer idProducer) {
        createDisplayLocked(address, /* isDefault= */ true, /* isEnabled= */ true,
        createDisplayLocked(address, /* isDefault= */ true, /* isEnabled= */ true,
                DEFAULT_DISPLAY_GROUP_NAME, idProducer, POSITION_UNKNOWN,
                DEFAULT_DISPLAY_GROUP_NAME, idProducer, POSITION_UNKNOWN,
                NO_LEAD_DISPLAY, /* brightnessThrottlingMapId= */ null,
                /* leadDisplayAddress= */ null, /* brightnessThrottlingMapId= */ null,
                /* refreshRateZoneId= */ null, /* refreshRateThermalThrottlingMapId= */ null);
                /* refreshRateZoneId= */ null, /* refreshRateThermalThrottlingMapId= */ null);
    }
    }


@@ -90,19 +92,20 @@ public class Layout {
     * @param displayGroupName Name of the display group to which the display is assigned.
     * @param displayGroupName Name of the display group to which the display is assigned.
     * @param idProducer Produces the logical display id.
     * @param idProducer Produces the logical display id.
     * @param position Indicates the position this display is facing in this layout.
     * @param position Indicates the position this display is facing in this layout.
     * @param leadDisplayId Display that this one follows (-1 if none).
     * @param leadDisplayAddress Address of a display that this one follows ({@code null} if none).
     * @param brightnessThrottlingMapId Name of which brightness throttling policy should be used.
     * @param brightnessThrottlingMapId Name of which brightness throttling policy should be used.
     * @param refreshRateZoneId Layout limited refresh rate zone name.
     * @param refreshRateZoneId Layout limited refresh rate zone name.
     * @param refreshRateThermalThrottlingMapId Name of which refresh rate throttling
     * @param refreshRateThermalThrottlingMapId Name of which refresh rate throttling
     *                                          policy should be used.
     *                                          policy should be used.

     *
     * @exception IllegalArgumentException When a default display owns a display group other than
     * @exception IllegalArgumentException When a default display owns a display group other than
     *            DEFAULT_DISPLAY_GROUP.
     *            DEFAULT_DISPLAY_GROUP.
     */
     */
    public void createDisplayLocked(
    public void createDisplayLocked(
            @NonNull DisplayAddress address, boolean isDefault, boolean isEnabled,
            @NonNull DisplayAddress address, boolean isDefault, boolean isEnabled,
            String displayGroupName, DisplayIdProducer idProducer, int position, int leadDisplayId,
            String displayGroupName, DisplayIdProducer idProducer, int position,
            String brightnessThrottlingMapId, @Nullable String refreshRateZoneId,
            @Nullable DisplayAddress leadDisplayAddress, String brightnessThrottlingMapId,
            @Nullable String refreshRateZoneId,
            @Nullable String refreshRateThermalThrottlingMapId) {
            @Nullable String refreshRateThermalThrottlingMapId) {
        if (contains(address)) {
        if (contains(address)) {
            Slog.w(TAG, "Attempting to add second definition for display-device: " + address);
            Slog.w(TAG, "Attempting to add second definition for display-device: " + address);
@@ -115,21 +118,27 @@ public class Layout {
            return;
            return;
        }
        }


        // Assign a logical display ID and create the new display.
        // Note that the logical display ID is saved into the layout, so when switching between
        // different layouts, a logical display can be destroyed and later recreated with the
        // same logical display ID.
        if (displayGroupName == null) {
        if (displayGroupName == null) {
            displayGroupName = DEFAULT_DISPLAY_GROUP_NAME;
            displayGroupName = DEFAULT_DISPLAY_GROUP_NAME;
        }
        }
        if (isDefault && !displayGroupName.equals(DEFAULT_DISPLAY_GROUP_NAME)) {
        if (isDefault && !displayGroupName.equals(DEFAULT_DISPLAY_GROUP_NAME)) {
            throw new IllegalArgumentException("Default display should own DEFAULT_DISPLAY_GROUP");
            throw new IllegalArgumentException("Default display should own DEFAULT_DISPLAY_GROUP");
        }
        }
        if (isDefault && leadDisplayAddress != null) {
            throw new IllegalArgumentException("Default display cannot have a lead display");
        }
        if (address.equals(leadDisplayAddress)) {
            throw new IllegalArgumentException("Lead display address cannot be the same as display "
                    + " address");
        }
        // Assign a logical display ID and create the new display.
        // Note that the logical display ID is saved into the layout, so when switching between
        // different layouts, a logical display can be destroyed and later recreated with the
        // same logical display ID.
        final int logicalDisplayId = idProducer.getId(isDefault);
        final int logicalDisplayId = idProducer.getId(isDefault);
        leadDisplayId = isDefault ? NO_LEAD_DISPLAY : leadDisplayId;


        final Display display = new Display(address, logicalDisplayId, isEnabled, displayGroupName,
        final Display display = new Display(address, logicalDisplayId, isEnabled, displayGroupName,
                brightnessThrottlingMapId, position, leadDisplayId, refreshRateZoneId,
                brightnessThrottlingMapId, position, leadDisplayAddress, refreshRateZoneId,
                refreshRateThermalThrottlingMapId);
                refreshRateThermalThrottlingMapId);


        mDisplays.add(display);
        mDisplays.add(display);
@@ -145,6 +154,43 @@ public class Layout {
        }
        }
    }
    }


    /**
     * Applies post-processing to displays to make sure the information of each display is
     * up-to-date.
     *
     * <p>At creation of a display, lead display is specified by display address. At post
     * processing, we convert it to logical display ID.
     */
    public void postProcessLocked() {
        for (int i = 0; i < mDisplays.size(); i++) {
            Display display = mDisplays.get(i);
            if (display.getLogicalDisplayId() == DEFAULT_DISPLAY) {
                display.setLeadDisplayId(NO_LEAD_DISPLAY);
                continue;
            }
            DisplayAddress leadDisplayAddress = display.getLeadDisplayAddress();
            if (leadDisplayAddress == null) {
                display.setLeadDisplayId(NO_LEAD_DISPLAY);
                continue;
            }
            Display leadDisplay = getByAddress(leadDisplayAddress);
            if (leadDisplay == null) {
                throw new IllegalArgumentException("Cannot find a lead display whose address is "
                        + leadDisplayAddress);
            }
            if (!TextUtils.equals(display.getDisplayGroupName(),
                    leadDisplay.getDisplayGroupName())) {
                throw new IllegalArgumentException("Lead display(" + leadDisplay + ") should be in "
                        + "the same display group of the display(" + display + ")");
            }
            if (hasCyclicLeadDisplay(display)) {
                throw new IllegalArgumentException("Display(" + display + ") has a cyclic lead "
                        + "display");
            }
            display.setLeadDisplayId(leadDisplay.getLogicalDisplayId());
        }
    }

    /**
    /**
     * @param address The address to check.
     * @param address The address to check.
     *
     *
@@ -208,6 +254,20 @@ public class Layout {
        return mDisplays.size();
        return mDisplays.size();
    }
    }


    private boolean hasCyclicLeadDisplay(Display display) {
        ArraySet<Display> visited = new ArraySet<>();

        while (display != null) {
            if (visited.contains(display)) {
                return true;
            }
            visited.add(display);
            DisplayAddress leadDisplayAddress = display.getLeadDisplayAddress();
            display = leadDisplayAddress == null ? null : getByAddress(leadDisplayAddress);
        }
        return false;
    }

    /**
    /**
     * Describes how a {@link LogicalDisplay} is built from {@link DisplayDevice}s.
     * Describes how a {@link LogicalDisplay} is built from {@link DisplayDevice}s.
     */
     */
@@ -240,8 +300,9 @@ public class Layout {
        @Nullable
        @Nullable
        private final String mThermalBrightnessThrottlingMapId;
        private final String mThermalBrightnessThrottlingMapId;


        // The ID of the lead display that this display will follow in a layout. -1 means no lead.
        // The address of the lead display that is specified in display-layout-configuration.
        private final int mLeadDisplayId;
        @Nullable
        private final DisplayAddress mLeadDisplayAddress;


        // Refresh rate zone id for specific layout
        // Refresh rate zone id for specific layout
        @Nullable
        @Nullable
@@ -250,9 +311,13 @@ public class Layout {
        @Nullable
        @Nullable
        private final String mThermalRefreshRateThrottlingMapId;
        private final String mThermalRefreshRateThrottlingMapId;


        // The ID of the lead display that this display will follow in a layout. -1 means no lead.
        // This is determined using {@code mLeadDisplayAddress}.
        private int mLeadDisplayId;

        private Display(@NonNull DisplayAddress address, int logicalDisplayId, boolean isEnabled,
        private Display(@NonNull DisplayAddress address, int logicalDisplayId, boolean isEnabled,
                @NonNull String displayGroupName, String brightnessThrottlingMapId, int position,
                @NonNull String displayGroupName, String brightnessThrottlingMapId, int position,
                int leadDisplayId, @Nullable String refreshRateZoneId,
                @Nullable DisplayAddress leadDisplayAddress, @Nullable String refreshRateZoneId,
                @Nullable String refreshRateThermalThrottlingMapId) {
                @Nullable String refreshRateThermalThrottlingMapId) {
            mAddress = address;
            mAddress = address;
            mLogicalDisplayId = logicalDisplayId;
            mLogicalDisplayId = logicalDisplayId;
@@ -260,9 +325,10 @@ public class Layout {
            mDisplayGroupName = displayGroupName;
            mDisplayGroupName = displayGroupName;
            mPosition = position;
            mPosition = position;
            mThermalBrightnessThrottlingMapId = brightnessThrottlingMapId;
            mThermalBrightnessThrottlingMapId = brightnessThrottlingMapId;
            mLeadDisplayAddress = leadDisplayAddress;
            mRefreshRateZoneId = refreshRateZoneId;
            mRefreshRateZoneId = refreshRateZoneId;
            mThermalRefreshRateThrottlingMapId = refreshRateThermalThrottlingMapId;
            mThermalRefreshRateThrottlingMapId = refreshRateThermalThrottlingMapId;
            mLeadDisplayId = leadDisplayId;
            mLeadDisplayId = NO_LEAD_DISPLAY;
        }
        }


        @Override
        @Override
@@ -276,6 +342,7 @@ public class Layout {
                    + ", mThermalBrightnessThrottlingMapId: " + mThermalBrightnessThrottlingMapId
                    + ", mThermalBrightnessThrottlingMapId: " + mThermalBrightnessThrottlingMapId
                    + ", mRefreshRateZoneId: " + mRefreshRateZoneId
                    + ", mRefreshRateZoneId: " + mRefreshRateZoneId
                    + ", mLeadDisplayId: " + mLeadDisplayId
                    + ", mLeadDisplayId: " + mLeadDisplayId
                    + ", mLeadDisplayAddress: " + mLeadDisplayAddress
                    + ", mThermalRefreshRateThrottlingMapId: " + mThermalRefreshRateThrottlingMapId
                    + ", mThermalRefreshRateThrottlingMapId: " + mThermalRefreshRateThrottlingMapId
                    + "}";
                    + "}";
        }
        }
@@ -297,6 +364,7 @@ public class Layout {
                    otherDisplay.mThermalBrightnessThrottlingMapId)
                    otherDisplay.mThermalBrightnessThrottlingMapId)
                    && Objects.equals(otherDisplay.mRefreshRateZoneId, this.mRefreshRateZoneId)
                    && Objects.equals(otherDisplay.mRefreshRateZoneId, this.mRefreshRateZoneId)
                    && this.mLeadDisplayId == otherDisplay.mLeadDisplayId
                    && this.mLeadDisplayId == otherDisplay.mLeadDisplayId
                    && Objects.equals(mLeadDisplayAddress, otherDisplay.mLeadDisplayAddress)
                    && Objects.equals(mThermalRefreshRateThrottlingMapId,
                    && Objects.equals(mThermalRefreshRateThrottlingMapId,
                    otherDisplay.mThermalRefreshRateThrottlingMapId);
                    otherDisplay.mThermalRefreshRateThrottlingMapId);
        }
        }
@@ -309,9 +377,10 @@ public class Layout {
            result = 31 * result + mLogicalDisplayId;
            result = 31 * result + mLogicalDisplayId;
            result = 31 * result + mDisplayGroupName.hashCode();
            result = 31 * result + mDisplayGroupName.hashCode();
            result = 31 * result + mAddress.hashCode();
            result = 31 * result + mAddress.hashCode();
            result = 31 * result + mThermalBrightnessThrottlingMapId.hashCode();
            result = 31 * result + Objects.hashCode(mThermalBrightnessThrottlingMapId);
            result = 31 * result + Objects.hashCode(mRefreshRateZoneId);
            result = 31 * result + Objects.hashCode(mRefreshRateZoneId);
            result = 31 * result + mLeadDisplayId;
            result = 31 * result + mLeadDisplayId;
            result = 31 * result + Objects.hashCode(mLeadDisplayAddress);
            result = 31 * result + Objects.hashCode(mThermalRefreshRateThrottlingMapId);
            result = 31 * result + Objects.hashCode(mThermalRefreshRateThrottlingMapId);
            return result;
            return result;
        }
        }
@@ -360,8 +429,20 @@ public class Layout {
            return mLeadDisplayId;
            return mLeadDisplayId;
        }
        }


        /**
         * @return Display address of the display that this one follows.
         */
        @Nullable
        public DisplayAddress getLeadDisplayAddress() {
            return mLeadDisplayAddress;
        }

        public String getRefreshRateThermalThrottlingMapId() {
        public String getRefreshRateThermalThrottlingMapId() {
            return mThermalRefreshRateThrottlingMapId;
            return mThermalRefreshRateThrottlingMapId;
        }
        }

        private void setLeadDisplayId(int id) {
            mLeadDisplayId = id;
        }
    }
    }
}
}
+1 −0
Original line number Original line Diff line number Diff line
@@ -53,6 +53,7 @@
            <xs:element name="position" type="xs:string" minOccurs="0" 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="brightnessThrottlingMapId" type="xs:string" minOccurs="0" maxOccurs="1" />
            <xs:element name="refreshRateThermalThrottlingMapId" type="xs:string" minOccurs="0" />
            <xs:element name="refreshRateThermalThrottlingMapId" type="xs:string" minOccurs="0" />
            <xs:element name="leadDisplayAddress" type="xs:nonNegativeInteger" minOccurs="0" maxOccurs="1" />
        </xs:sequence>
        </xs:sequence>
        <xs:attribute name="enabled" type="xs:boolean" use="optional" />
        <xs:attribute name="enabled" type="xs:boolean" use="optional" />
        <xs:attribute name="defaultDisplay" type="xs:boolean" use="optional" />
        <xs:attribute name="defaultDisplay" type="xs:boolean" use="optional" />
+2 −0
Original line number Original line Diff line number Diff line
@@ -6,6 +6,7 @@ package com.android.server.display.config.layout {
    method public java.math.BigInteger getAddress();
    method public java.math.BigInteger getAddress();
    method public String getBrightnessThrottlingMapId();
    method public String getBrightnessThrottlingMapId();
    method public String getDisplayGroup();
    method public String getDisplayGroup();
    method public java.math.BigInteger getLeadDisplayAddress();
    method public String getPosition();
    method public String getPosition();
    method public String getRefreshRateThermalThrottlingMapId();
    method public String getRefreshRateThermalThrottlingMapId();
    method public String getRefreshRateZoneId();
    method public String getRefreshRateZoneId();
@@ -16,6 +17,7 @@ package com.android.server.display.config.layout {
    method public void setDefaultDisplay(boolean);
    method public void setDefaultDisplay(boolean);
    method public void setDisplayGroup(String);
    method public void setDisplayGroup(String);
    method public void setEnabled(boolean);
    method public void setEnabled(boolean);
    method public void setLeadDisplayAddress(java.math.BigInteger);
    method public void setPosition(String);
    method public void setPosition(String);
    method public void setRefreshRateThermalThrottlingMapId(String);
    method public void setRefreshRateThermalThrottlingMapId(String);
    method public void setRefreshRateZoneId(String);
    method public void setRefreshRateZoneId(String);
+136 −11
Original line number Original line Diff line number Diff line
@@ -19,8 +19,8 @@ package com.android.server.display;


import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThrows;


import android.view.Display;
import android.view.DisplayAddress;
import android.view.DisplayAddress;


import androidx.test.filters.SmallTest;
import androidx.test.filters.SmallTest;
@@ -65,9 +65,15 @@ public class DeviceStateToLayoutMapTest {


        Layout testLayout = new Layout();
        Layout testLayout = new Layout();
        createDefaultDisplay(testLayout, 123456L);
        createDefaultDisplay(testLayout, 123456L);
        createNonDefaultDisplay(testLayout, 78910L, /* enabled= */ false, /* group= */ null);
        createNonDefaultDisplay(testLayout, 78910L, /* enabled= */ false, /* group= */ null,
        createNonDefaultDisplay(testLayout, 98765L, /* enabled= */ true, /* group= */ "group1");
                /* leadDisplayAddress= */ null);
        createNonDefaultDisplay(testLayout, 786L, /* enabled= */ false, /* group= */ "group2");
        createNonDefaultDisplay(testLayout, 98765L, /* enabled= */ true, /* group= */ "group1",
                /* leadDisplayAddress= */ null);
        createNonDefaultDisplay(testLayout, 786L, /* enabled= */ false, /* group= */ "group2",
                /* leadDisplayAddress= */ null);
        createNonDefaultDisplay(testLayout, 1092L, /* enabled= */ true, /* group= */ null,
                DisplayAddress.fromPhysicalDisplayId(78910L));
        testLayout.postProcessLocked();


        assertEquals(testLayout, configLayout);
        assertEquals(testLayout, configLayout);
    }
    }
@@ -78,7 +84,9 @@ public class DeviceStateToLayoutMapTest {


        Layout testLayout = new Layout();
        Layout testLayout = new Layout();
        createDefaultDisplay(testLayout, 78910L);
        createDefaultDisplay(testLayout, 78910L);
        createNonDefaultDisplay(testLayout, 123456L, /* enabled= */ false, /* group= */ null);
        createNonDefaultDisplay(testLayout, 123456L, /* enabled= */ false, /* group= */ null,
                /* leadDisplayAddress= */ null);
        testLayout.postProcessLocked();


        assertEquals(testLayout, configLayout);
        assertEquals(testLayout, configLayout);
    }
    }
@@ -122,20 +130,132 @@ public class DeviceStateToLayoutMapTest {
        Layout testLayout = new Layout();
        Layout testLayout = new Layout();
        testLayout.createDisplayLocked(DisplayAddress.fromPhysicalDisplayId(345L),
        testLayout.createDisplayLocked(DisplayAddress.fromPhysicalDisplayId(345L),
                /* isDefault= */ true, /* isEnabled= */ true, /* displayGroupName= */ null,
                /* isDefault= */ true, /* isEnabled= */ true, /* displayGroupName= */ null,
                mDisplayIdProducerMock,  Layout.Display.POSITION_FRONT, Display.DEFAULT_DISPLAY,
                mDisplayIdProducerMock,  Layout.Display.POSITION_FRONT,
                /* brightnessThrottlingMapId= */ "brightness1",
                /* leadDisplayAddress= */ null, /* brightnessThrottlingMapId= */ "brightness1",
                /* refreshRateZoneId= */ "zone1",
                /* refreshRateZoneId= */ "zone1",
                /* refreshRateThermalThrottlingMapId= */ "rr1");
                /* refreshRateThermalThrottlingMapId= */ "rr1");
        testLayout.createDisplayLocked(DisplayAddress.fromPhysicalDisplayId(678L),
        testLayout.createDisplayLocked(DisplayAddress.fromPhysicalDisplayId(678L),
                /* isDefault= */ false, /* isEnabled= */ false, /* displayGroupName= */ "group1",
                /* isDefault= */ false, /* isEnabled= */ false, /* displayGroupName= */ "group1",
                mDisplayIdProducerMock, Layout.Display.POSITION_REAR, Display.DEFAULT_DISPLAY,
                mDisplayIdProducerMock, Layout.Display.POSITION_REAR,
                /* brightnessThrottlingMapId= */ "brightness2",
                /* leadDisplayAddress= */ null, /* brightnessThrottlingMapId= */ "brightness2",
                /* refreshRateZoneId= */ "zone2",
                /* refreshRateZoneId= */ "zone2",
                /* refreshRateThermalThrottlingMapId= */ "rr2");
                /* refreshRateThermalThrottlingMapId= */ "rr2");
        testLayout.postProcessLocked();


        assertEquals(testLayout, configLayout);
        assertEquals(testLayout, configLayout);
    }
    }


    @Test
    public void testLeadDisplayAddress() {
        Layout layout = new Layout();
        createNonDefaultDisplay(layout, 111L, /* enabled= */ true, /* group= */ null,
                /* leadDisplayAddress= */ null);
        createNonDefaultDisplay(layout, 222L, /* enabled= */ true, /* group= */ null,
                DisplayAddress.fromPhysicalDisplayId(111L));

        layout.postProcessLocked();

        com.android.server.display.layout.Layout.Display display111 =
                layout.getByAddress(DisplayAddress.fromPhysicalDisplayId(111));
        com.android.server.display.layout.Layout.Display display222 =
                layout.getByAddress(DisplayAddress.fromPhysicalDisplayId(222));
        assertEquals(display111.getLeadDisplayId(), layout.NO_LEAD_DISPLAY);
        assertEquals(display222.getLeadDisplayId(), display111.getLogicalDisplayId());
    }

    @Test
    public void testLeadDisplayAddress_defaultDisplay() {
        Layout layout = new Layout();
        createDefaultDisplay(layout, 123456L);

        layout.postProcessLocked();

        com.android.server.display.layout.Layout.Display display =
                layout.getByAddress(DisplayAddress.fromPhysicalDisplayId(123456));
        assertEquals(display.getLeadDisplayId(), layout.NO_LEAD_DISPLAY);
    }

    @Test
    public void testLeadDisplayAddress_noLeadDisplay() {
        Layout layout = new Layout();
        createNonDefaultDisplay(layout, 222L, /* enabled= */ true, /* group= */ null,
                /* leadDisplayAddress= */ null);

        layout.postProcessLocked();

        com.android.server.display.layout.Layout.Display display =
                layout.getByAddress(DisplayAddress.fromPhysicalDisplayId(222));
        assertEquals(display.getLeadDisplayId(), layout.NO_LEAD_DISPLAY);
    }

    @Test
    public void testLeadDisplayAddress_selfLeadDisplayForNonDefaultDisplay() {
        Layout layout = new Layout();

        assertThrows("Expected Layout to throw IllegalArgumentException when the display points out"
                + " itself as a lead display",
                IllegalArgumentException.class,
                () -> layout.createDisplayLocked(DisplayAddress.fromPhysicalDisplayId(123L),
                    /* isDefault= */ true, /* isEnabled= */ true, /* displayGroupName= */ null,
                    mDisplayIdProducerMock,  Layout.Display.POSITION_FRONT,
                    DisplayAddress.fromPhysicalDisplayId(123L),
                    /* brightnessThrottlingMapId= */ null, /* refreshRateZoneId= */ null,
                    /* refreshRateThermalThrottlingMapId= */ null));
    }

    @Test
    public void testLeadDisplayAddress_wrongLeadDisplayForDefaultDisplay() {
        Layout layout = new Layout();

        assertThrows("Expected Layout to throw IllegalArgumentException when the default display "
                + "has a lead display",
                IllegalArgumentException.class,
                () -> layout.createDisplayLocked(DisplayAddress.fromPhysicalDisplayId(123L),
                    /* isDefault= */ true, /* isEnabled= */ true, /* displayGroupName= */ null,
                    mDisplayIdProducerMock,  Layout.Display.POSITION_FRONT,
                    DisplayAddress.fromPhysicalDisplayId(987L),
                    /* brightnessThrottlingMapId= */ null, /* refreshRateZoneId= */ null,
                    /* refreshRateThermalThrottlingMapId= */ null));
    }

    @Test
    public void testLeadDisplayAddress_notExistingLeadDisplayForNonDefaultDisplay() {
        Layout layout = new Layout();
        createNonDefaultDisplay(layout, 222L, /* enabled= */ true, /* group= */ null,
                DisplayAddress.fromPhysicalDisplayId(111L));

        assertThrows("Expected Layout to throw IllegalArgumentException when a lead display doesn't"
                + " exist", IllegalArgumentException.class, () -> layout.postProcessLocked());
    }

    @Test
    public void testLeadDisplayAddress_leadDisplayInDifferentDisplayGroup() {
        Layout layout = new Layout();
        createNonDefaultDisplay(layout, 111, /* enabled= */ true, /* group= */ "group1",
                /* leadDisplayAddress= */ null);
        createNonDefaultDisplay(layout, 222L, /* enabled= */ true, /* group= */ "group2",
                DisplayAddress.fromPhysicalDisplayId(111L));

        assertThrows("Expected Layout to throw IllegalArgumentException when pointing to a lead "
                + "display in the different group",
                IllegalArgumentException.class, () -> layout.postProcessLocked());
    }

    @Test
    public void testLeadDisplayAddress_cyclicLeadDisplay() {
        Layout layout = new Layout();
        createNonDefaultDisplay(layout, 111, /* enabled= */ true, /* group= */ null,
                DisplayAddress.fromPhysicalDisplayId(222L));
        createNonDefaultDisplay(layout, 222L, /* enabled= */ true, /* group= */ null,
                DisplayAddress.fromPhysicalDisplayId(333L));
        createNonDefaultDisplay(layout, 333L, /* enabled= */ true, /* group= */ null,
                DisplayAddress.fromPhysicalDisplayId(222L));

        assertThrows("Expected Layout to throw IllegalArgumentException when pointing to a lead "
                + "display in the different group",
                IllegalArgumentException.class, () -> layout.postProcessLocked());
    }

    ////////////////////
    ////////////////////
    // Helper Methods //
    // Helper Methods //
    ////////////////////
    ////////////////////
@@ -145,10 +265,11 @@ public class DeviceStateToLayoutMapTest {
                mDisplayIdProducerMock);
                mDisplayIdProducerMock);
    }
    }


    private void createNonDefaultDisplay(Layout layout, long id, boolean enabled, String group) {
    private void createNonDefaultDisplay(Layout layout, long id, boolean enabled, String group,
            DisplayAddress leadDisplayAddress) {
        layout.createDisplayLocked(DisplayAddress.fromPhysicalDisplayId(id), /* isDefault= */ false,
        layout.createDisplayLocked(DisplayAddress.fromPhysicalDisplayId(id), /* isDefault= */ false,
                enabled, group, mDisplayIdProducerMock, Layout.Display.POSITION_UNKNOWN,
                enabled, group, mDisplayIdProducerMock, Layout.Display.POSITION_UNKNOWN,
                Display.DEFAULT_DISPLAY, /* brightnessThrottlingMapId= */ null,
                leadDisplayAddress, /* brightnessThrottlingMapId= */ null,
                /* refreshRateZoneId= */ null,
                /* refreshRateZoneId= */ null,
                /* refreshRateThermalThrottlingMapId= */ null);
                /* refreshRateThermalThrottlingMapId= */ null);
    }
    }
@@ -177,6 +298,10 @@ public class DeviceStateToLayoutMapTest {
                +      "<display enabled=\"false\" displayGroup=\"group2\">\n"
                +      "<display enabled=\"false\" displayGroup=\"group2\">\n"
                +        "<address>786</address>\n"
                +        "<address>786</address>\n"
                +      "</display>\n"
                +      "</display>\n"
                +      "<display enabled=\"true\">\n"
                +        "<address>1092</address>\n"
                +        "<leadDisplayAddress>78910</leadDisplayAddress>\n"
                +      "</display>\n"
                +    "</layout>\n"
                +    "</layout>\n"


                +    "<layout>\n"
                +    "<layout>\n"
Loading