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

Commit b474b520 authored by Piotr Wilczyński's avatar Piotr Wilczyński Committed by Android (Google) Code Review
Browse files

Merge "Update unique ID mappings in DisplayTopologyCoordinator" into main

parents 53a4d390 bd7a2694
Loading
Loading
Loading
Loading
+19 −2
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.display;

import android.annotation.Nullable;
import android.hardware.display.DisplayTopology;
import android.hardware.display.DisplayTopologyGraph;
import android.os.Trace;
@@ -44,6 +45,7 @@ import java.util.function.Consumer;
class DisplayTopologyCoordinator {
    private static final String TAG = "DisplayTopologyCoordinator";

    @Nullable
    private static String getUniqueId(DisplayInfo info) {
        if (info.displayId == Display.DEFAULT_DISPLAY && info.type == Display.TYPE_INTERNAL) {
            return "internal";
@@ -155,8 +157,19 @@ class DisplayTopologyCoordinator {
            return;
        }
        synchronized (mSyncRoot) {
            if (mTopology.updateDisplay(info.displayId, info.logicalWidth, info.logicalHeight,
                    info.logicalDensityDpi)) {
            boolean topologyUpdated = mTopology.updateDisplay(info.displayId, info.logicalWidth,
                    info.logicalHeight, info.logicalDensityDpi);

            String uniqueId = getUniqueId(info);
            String oldUniqueId = mDisplayIdToUniqueIdMapping.get(info.displayId);
            if (uniqueId != null && oldUniqueId != null && !uniqueId.equals(oldUniqueId)) {
                addDisplayIdMappingLocked(info);

                // Restore the displays' positions by unique ID
                topologyUpdated |= restoreTopologyLocked();
            }

            if (topologyUpdated) {
                sendTopologyUpdateLocked();
            }
        }
@@ -272,6 +285,10 @@ class DisplayTopologyCoordinator {
    @GuardedBy("mSyncRoot")
    private void addDisplayIdMappingLocked(DisplayInfo info) {
        final String uniqueId = getUniqueId(info);
        if (null == uniqueId) {
            Slog.e(TAG, "Can't find uniqueId for displayId=" + info.displayId);
            return;
        }
        mUniqueIdToDisplayIdMapping.put(uniqueId, info.displayId);
        mDisplayIdToUniqueIdMapping.put(info.displayId, uniqueId);
    }
+137 −38
Original line number Diff line number Diff line
@@ -40,6 +40,9 @@ class DisplayTopologyCoordinatorTest {
    private lateinit var displayInfos: List<DisplayInfo>
    private val topologyChangeExecutor = Runnable::run

    private lateinit var uniqueIdToDisplayIdMapping: Map<String, Int>
    private lateinit var displayIdToUniqueIdMapping: SparseArray<String>

    private val mockTopologyStore = mock<DisplayTopologyStore>()
    private val mockTopology = mock<DisplayTopology>()
    private val mockTopologyCopy = mock<DisplayTopology>()
@@ -56,6 +59,7 @@ class DisplayTopologyCoordinatorTest {
        displayInfos = (1..10).map { i ->
            val info = DisplayInfo()
            info.displayId = i
            info.uniqueId = "uniqueId$i"
            info.displayGroupId = Display.DEFAULT_DISPLAY_GROUP
            info.logicalWidth = i * 300
            info.logicalHeight = i * 200
@@ -69,11 +73,15 @@ class DisplayTopologyCoordinatorTest {
            override fun createTopologyStore(
                displayIdToUniqueId: SparseArray<String>,
                uniqueIdToDisplayId: MutableMap<String, Int>
            ) = mockTopologyStore
            ): DisplayTopologyStore {
                uniqueIdToDisplayIdMapping = uniqueIdToDisplayId
                displayIdToUniqueIdMapping = displayIdToUniqueId
                return mockTopologyStore
            }
        }
        whenever(mockIsExtendedDisplayAllowed()).thenReturn(true)
        whenever(mockTopology.copy()).thenReturn(mockTopologyCopy)
        whenever(mockTopologyCopy.getGraph()).thenReturn(mockTopologyGraph)
        whenever(mockTopologyCopy.graph).thenReturn(mockTopologyGraph)
        coordinator = DisplayTopologyCoordinator(injector, mockIsExtendedDisplayAllowed,
            mockShouldIncludeDefaultDisplayInTopology, mockTopologyChangedCallback,
            topologyChangeExecutor, DisplayManagerService.SyncRoot(), mockTopologySavedCallback,
@@ -87,9 +95,13 @@ class DisplayTopologyCoordinatorTest {

            verify(mockTopology).addDisplay(displayInfo.displayId, displayInfo.logicalWidth,
                    displayInfo.logicalHeight, displayInfo.logicalDensityDpi)
            assertThat(displayIdToUniqueIdMapping.get(displayInfo.displayId))
                .isEqualTo(displayInfo.uniqueId)
            assertThat(uniqueIdToDisplayIdMapping[displayInfo.uniqueId])
                .isEqualTo(displayInfo.displayId)
        }

        verify(mockTopologyCopy, times(displayInfos.size)).getGraph()
        verify(mockTopologyCopy, times(displayInfos.size)).graph

        verify(mockTopologyChangedCallback, times(displayInfos.size)).invoke(
            android.util.Pair(
@@ -107,12 +119,15 @@ class DisplayTopologyCoordinatorTest {

    @Test
    fun addDisplay_internal() {
        displayInfos[0].displayId = Display.DEFAULT_DISPLAY
        displayInfos[0].type = Display.TYPE_INTERNAL
        coordinator.onDisplayAdded(displayInfos[0])
        val displayInfo = displayInfos[0]
        displayInfo.displayId = Display.DEFAULT_DISPLAY
        displayInfo.type = Display.TYPE_INTERNAL
        coordinator.onDisplayAdded(displayInfo)

        verify(mockTopology).addDisplay(displayInfos[0].displayId, displayInfos[0].logicalWidth,
                displayInfos[0].logicalHeight, displayInfos[0].logicalDensityDpi)
        verify(mockTopology).addDisplay(displayInfo.displayId, displayInfo.logicalWidth,
                displayInfo.logicalHeight, displayInfo.logicalDensityDpi)
        assertThat(displayIdToUniqueIdMapping.get(displayInfo.displayId)).isEqualTo("internal")
        assertThat(uniqueIdToDisplayIdMapping["internal"]).isEqualTo(displayInfo.displayId)
        verify(mockTopologyChangedCallback).invoke(
            android.util.Pair(
                mockTopologyCopy,
@@ -123,11 +138,16 @@ class DisplayTopologyCoordinatorTest {

    @Test
    fun addDisplay_overlay() {
        displayInfos[0].type = Display.TYPE_OVERLAY
        coordinator.onDisplayAdded(displayInfos[0])
        val displayInfo = displayInfos[0]
        displayInfo.type = Display.TYPE_OVERLAY
        coordinator.onDisplayAdded(displayInfo)

        verify(mockTopology).addDisplay(displayInfos[0].displayId, displayInfos[0].logicalWidth,
                displayInfos[0].logicalHeight, displayInfos[0].logicalDensityDpi)
        verify(mockTopology).addDisplay(displayInfo.displayId, displayInfo.logicalWidth,
                displayInfo.logicalHeight, displayInfo.logicalDensityDpi)
        assertThat(displayIdToUniqueIdMapping.get(displayInfo.displayId))
            .isEqualTo(displayInfo.uniqueId)
        assertThat(uniqueIdToDisplayIdMapping[displayInfo.uniqueId])
            .isEqualTo(displayInfo.displayId)
        verify(mockTopologyChangedCallback).invoke(
            android.util.Pair(
                mockTopologyCopy,
@@ -205,7 +225,7 @@ class DisplayTopologyCoordinatorTest {

    @Test
    fun addNonDefaultDisplay_defaultDisplayInTopologySwitchDisabled() {
        whenever(mockFlags.isDefaultDisplayInTopologySwitchEnabled()).thenReturn(true)
        whenever(mockFlags.isDefaultDisplayInTopologySwitchEnabled).thenReturn(true)
        whenever(mockShouldIncludeDefaultDisplayInTopology()).thenReturn(false)

        // Add default display and a non-default display into the topology
@@ -222,7 +242,7 @@ class DisplayTopologyCoordinatorTest {

    @Test
    fun addNonDefaultDisplay_defaultDisplayInTopologySwitchEnabled() {
        whenever(mockFlags.isDefaultDisplayInTopologySwitchEnabled()).thenReturn(true)
        whenever(mockFlags.isDefaultDisplayInTopologySwitchEnabled).thenReturn(true)
        whenever(mockShouldIncludeDefaultDisplayInTopology()).thenReturn(true)

        // Add default display and a non-default display into the topology
@@ -239,7 +259,7 @@ class DisplayTopologyCoordinatorTest {

    @Test
    fun addNonDefaultDisplay_flagDisabled() {
        whenever(mockFlags.isDefaultDisplayInTopologySwitchEnabled()).thenReturn(false)
        whenever(mockFlags.isDefaultDisplayInTopologySwitchEnabled).thenReturn(false)
        whenever(mockShouldIncludeDefaultDisplayInTopology()).thenReturn(false)

        // Add default display and a non-default display into the topology
@@ -256,19 +276,33 @@ class DisplayTopologyCoordinatorTest {

    @Test
    fun updateDisplay() {
        whenever(mockTopology.updateDisplay(eq(displayInfos[0].displayId),
                                            anyInt(), anyInt(), anyInt()))
            .thenReturn(true)
        val displayInfo = displayInfos[0]
        whenever(
            mockTopology.updateDisplay(
                eq(displayInfo.displayId),
                anyInt(),
                anyInt(),
                anyInt()
            )
        ).thenReturn(true)
        addDisplay()

        displayInfos[0].logicalWidth += 100
        displayInfos[0].logicalHeight += 100
        coordinator.onDisplayChanged(displayInfos[0])
        displayInfo.logicalWidth += 100
        displayInfo.logicalHeight += 100
        displayInfo.uniqueId = "newUniqueId"
        coordinator.onDisplayChanged(displayInfo)

        verify(mockTopology).updateDisplay(displayInfos[0].displayId, displayInfos[0].logicalWidth,
                displayInfos[0].logicalHeight, displayInfos[0].logicalDensityDpi)
        verify(mockTopology).updateDisplay(
            displayInfo.displayId, displayInfo.logicalWidth,
            displayInfo.logicalHeight, displayInfo.logicalDensityDpi
        )

        verify(mockTopologyCopy).getGraph()
        assertThat(displayIdToUniqueIdMapping.get(displayInfo.displayId))
            .isEqualTo(displayInfo.uniqueId)
        assertThat(uniqueIdToDisplayIdMapping[displayInfo.uniqueId])
            .isEqualTo(displayInfo.displayId)

        verify(mockTopologyCopy).graph

        verify(mockTopologyChangedCallback).invoke(
            android.util.Pair(
@@ -278,6 +312,69 @@ class DisplayTopologyCoordinatorTest {
        )
    }

    @Test
    fun updateDisplay_type_uniqueIdUpdated() {
        val displayInfo = displayInfos[0]
        displayInfo.displayId = Display.DEFAULT_DISPLAY
        addDisplay()
        val restoredTopology = mock<DisplayTopology>()
        whenever(restoredTopology.copy()).thenReturn(mock<DisplayTopology>())
        whenever(mockTopologyStore.restoreTopology(mockTopology)).thenReturn(restoredTopology)

        // Change to internal
        displayInfo.type = Display.TYPE_INTERNAL
        coordinator.onDisplayChanged(displayInfo)

        assertThat(displayIdToUniqueIdMapping.get(displayInfo.displayId)).isEqualTo("internal")
        assertThat(uniqueIdToDisplayIdMapping["internal"]).isEqualTo(displayInfo.displayId)
        verify(mockTopologyStore).restoreTopology(mockTopology)

        // Back to external
        displayInfo.type = Display.TYPE_EXTERNAL
        coordinator.onDisplayChanged(displayInfo)

        assertThat(displayIdToUniqueIdMapping.get(displayInfo.displayId))
            .isEqualTo(displayInfo.uniqueId)
        assertThat(uniqueIdToDisplayIdMapping[displayInfo.uniqueId])
            .isEqualTo(displayInfo.displayId)
        verify(mockTopologyStore).restoreTopology(restoredTopology)
    }

    @Test
    fun updateDisplay_swapUniqueIds() {
        val displayInfo1 = displayInfos[0]
        val displayInfo2 = displayInfos[1]
        addDisplay()
        val restoredTopology = mock<DisplayTopology>()
        whenever(restoredTopology.copy()).thenReturn(mock<DisplayTopology>())
        whenever(mockTopologyStore.restoreTopology(mockTopology)).thenReturn(restoredTopology)

        displayInfo1.uniqueId = displayInfo2.uniqueId
        coordinator.onDisplayChanged(displayInfo1)

        assertThat(displayIdToUniqueIdMapping.get(displayInfo1.displayId))
            .isEqualTo(displayInfo1.uniqueId)
        assertThat(uniqueIdToDisplayIdMapping[displayInfo1.uniqueId])
            .isEqualTo(displayInfo1.displayId)
        verify(mockTopologyStore).restoreTopology(mockTopology)

        // Now temporarily two logical display IDs map to the same unique ID. Make sure that
        // the following does not remove the mapping for the first display.
        displayInfo2.uniqueId = "newUniqueId"
        coordinator.onDisplayChanged(displayInfo2)

        assertThat(displayIdToUniqueIdMapping.get(displayInfo2.displayId))
            .isEqualTo(displayInfo2.uniqueId)
        assertThat(uniqueIdToDisplayIdMapping[displayInfo2.uniqueId])
            .isEqualTo(displayInfo2.displayId)
        // This mapping should still be there
        assertThat(displayIdToUniqueIdMapping.get(displayInfo1.displayId))
            .isEqualTo(displayInfo1.uniqueId)
        assertThat(uniqueIdToDisplayIdMapping[displayInfo1.uniqueId])
            .isEqualTo(displayInfo1.displayId)
        verify(mockTopologyStore).restoreTopology(restoredTopology)
    }

    @Test
    fun updateDisplay_notChanged() {
        addDisplay()
@@ -289,10 +386,12 @@ class DisplayTopologyCoordinatorTest {
        // Try to update a display that does not exist
        val info = DisplayInfo()
        info.displayId = 100
        info.uniqueId = "someUniqueId"
        coordinator.onDisplayChanged(info)

        verify(mockTopologyCopy, never()).getGraph()
        verify(mockTopologyCopy, never()).graph
        verify(mockTopologyChangedCallback, never()).invoke(any())
        verify(mockTopologyStore, never()).restoreTopology(any())
    }

    @Test
@@ -302,7 +401,7 @@ class DisplayTopologyCoordinatorTest {
        coordinator.onDisplayChanged(displayInfos[0])

        verify(mockTopology, never()).updateDisplay(anyInt(), anyInt(), anyInt(), anyInt())
        verify(mockTopologyCopy, never()).getGraph()
        verify(mockTopologyCopy, never()).graph
        verify(mockTopologyChangedCallback, never()).invoke(any())
    }

@@ -313,7 +412,7 @@ class DisplayTopologyCoordinatorTest {
        coordinator.onDisplayChanged(displayInfos[0])

        verify(mockTopology, never()).updateDisplay(anyInt(), anyInt(), anyInt(), anyInt())
        verify(mockTopologyCopy, never()).getGraph()
        verify(mockTopologyCopy, never()).graph
        verify(mockTopologyChangedCallback, never()).invoke(any())
    }

@@ -324,7 +423,7 @@ class DisplayTopologyCoordinatorTest {
        coordinator.onDisplayChanged(displayInfos[0])

        verify(mockTopology, never()).updateDisplay(anyInt(), anyInt(), anyInt(), anyInt())
        verify(mockTopologyCopy, never()).getGraph()
        verify(mockTopologyCopy, never()).graph
        verify(mockTopologyChangedCallback, never()).invoke(any())
    }

@@ -336,7 +435,7 @@ class DisplayTopologyCoordinatorTest {
        coordinator.onDisplayChanged(displayInfos[0])

        verify(mockTopology, never()).updateDisplay(anyInt(), anyInt(), anyInt(), anyInt())
        verify(mockTopologyCopy, never()).getGraph()
        verify(mockTopologyCopy, never()).graph
        verify(mockTopologyChangedCallback, never()).invoke(any())
    }

@@ -349,7 +448,7 @@ class DisplayTopologyCoordinatorTest {
        }

        verify(mockTopology, never()).updateDisplay(anyInt(), anyInt(), anyInt(), anyInt())
        verify(mockTopologyCopy, never()).getGraph()
        verify(mockTopologyCopy, never()).graph
        verify(mockTopologyChangedCallback, never()).invoke(any())
    }

@@ -376,7 +475,7 @@ class DisplayTopologyCoordinatorTest {
            coordinator.onDisplayRemoved(displayInfo.displayId)
        }

        verify(mockTopologyCopy, times(displaysToRemove.size)).getGraph()
        verify(mockTopologyCopy, times(displaysToRemove.size)).graph

        verify(mockTopologyChangedCallback, times(displaysToRemove.size)).invoke(
            android.util.Pair(
@@ -397,7 +496,7 @@ class DisplayTopologyCoordinatorTest {

    @Test
    fun removeNonDefaultDisplay_defaultDisplayInTopologySwitchDisabled() {
        whenever(mockFlags.isDefaultDisplayInTopologySwitchEnabled()).thenReturn(true)
        whenever(mockFlags.isDefaultDisplayInTopologySwitchEnabled).thenReturn(true)
        whenever(mockShouldIncludeDefaultDisplayInTopology()).thenReturn(false)

        // Set up the default display
@@ -408,7 +507,7 @@ class DisplayTopologyCoordinatorTest {
        displayInfos[1].displayId = Display.DEFAULT_DISPLAY + 1
        displayInfos[1].type = Display.TYPE_EXTERNAL
        whenever(mockTopology.removeDisplay(displayInfos[1].displayId)).thenReturn(true)
        whenever(mockTopology.isEmpty()).thenReturn(true)
        whenever(mockTopology.isEmpty).thenReturn(true)
        coordinator.onDisplayRemoved(displayInfos[1].displayId)

        verify(mockTopology).addDisplay(displayInfos[0].displayId, displayInfos[0].logicalWidth,
@@ -417,7 +516,7 @@ class DisplayTopologyCoordinatorTest {

    @Test
    fun removeNonDefaultDisplay_defaultDisplayInTopologySwitchEnabled() {
        whenever(mockFlags.isDefaultDisplayInTopologySwitchEnabled()).thenReturn(true)
        whenever(mockFlags.isDefaultDisplayInTopologySwitchEnabled).thenReturn(true)
        whenever(mockShouldIncludeDefaultDisplayInTopology()).thenReturn(true)

        // Set up the default display
@@ -435,7 +534,7 @@ class DisplayTopologyCoordinatorTest {

    @Test
    fun removeNonDefaultDisplay_flagDisabled() {
        whenever(mockFlags.isDefaultDisplayInTopologySwitchEnabled()).thenReturn(false)
        whenever(mockFlags.isDefaultDisplayInTopologySwitchEnabled).thenReturn(false)
        whenever(mockShouldIncludeDefaultDisplayInTopology()).thenReturn(false)

        // Set up the default display
@@ -462,7 +561,7 @@ class DisplayTopologyCoordinatorTest {
        val topologyCopy = mock<DisplayTopology>()
        val topologyGraph = mock<DisplayTopologyGraph>()
        whenever(topology.copy()).thenReturn(topologyCopy)
        whenever(topologyCopy.getGraph()).thenReturn(topologyGraph)
        whenever(topologyCopy.graph).thenReturn(topologyGraph)
        whenever(mockTopologyStore.saveTopology(topology)).thenReturn(true)

        coordinator.topology = topology