Loading services/core/java/com/android/server/display/DisplayTopologyCoordinator.java +19 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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"; Loading Loading @@ -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(); } } Loading Loading @@ -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); } Loading services/tests/displayservicetests/src/com/android/server/display/DisplayTopologyCoordinatorTest.kt +137 −38 Original line number Diff line number Diff line Loading @@ -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>() Loading @@ -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 Loading @@ -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, Loading @@ -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( Loading @@ -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, Loading @@ -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, Loading Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading @@ -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( Loading @@ -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() Loading @@ -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 Loading @@ -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()) } Loading @@ -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()) } Loading @@ -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()) } Loading @@ -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()) } Loading @@ -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()) } Loading @@ -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( Loading @@ -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 Loading @@ -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, Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading Loading
services/core/java/com/android/server/display/DisplayTopologyCoordinator.java +19 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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"; Loading Loading @@ -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(); } } Loading Loading @@ -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); } Loading
services/tests/displayservicetests/src/com/android/server/display/DisplayTopologyCoordinatorTest.kt +137 −38 Original line number Diff line number Diff line Loading @@ -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>() Loading @@ -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 Loading @@ -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, Loading @@ -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( Loading @@ -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, Loading @@ -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, Loading Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading @@ -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( Loading @@ -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() Loading @@ -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 Loading @@ -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()) } Loading @@ -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()) } Loading @@ -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()) } Loading @@ -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()) } Loading @@ -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()) } Loading @@ -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( Loading @@ -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 Loading @@ -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, Loading @@ -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 Loading @@ -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 Loading @@ -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 Loading