From b9ea2e327f705365c981c6f89c02f478dc7a1e1e Mon Sep 17 00:00:00 2001 From: Matthew DeVore Date: Thu, 16 Jan 2025 01:51:50 +0000 Subject: [PATCH] DisplayTopology: user cannot drag only display When dragging a single display, we don't constrain the position of the display, and the user can drag it anywhere on the fragment. As such we need to either prevent the drag or refresh the pane always if there is only one display. This CL chooses the former. Flag: com.android.settings.flags.display_topology_pane_in_display_list Test: atest DisplayTopologyPreferenceTest.kt Bug: b/352650922 Change-Id: Icb101b734ce9b88435f64a71bf77f878f9b230e0 --- .../display/DisplayTopology.kt | 8 +++- .../display/DisplayTopologyPreferenceTest.kt | 39 +++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/com/android/settings/connecteddevice/display/DisplayTopology.kt b/src/com/android/settings/connecteddevice/display/DisplayTopology.kt index c4f0b29ac00..1497182cdb8 100644 --- a/src/com/android/settings/connecteddevice/display/DisplayTopology.kt +++ b/src/com/android/settings/connecteddevice/display/DisplayTopology.kt @@ -404,8 +404,12 @@ class DisplayTopologyPreference(context : Context) private fun onBlockTouchDown( displayId: Int, displayPos: RectF, block: DisplayBlock, ev: MotionEvent): Boolean { - val stationaryDisps = (mTopologyInfo ?: return false) - .positions.filter { it.first != displayId } + val positions = (mTopologyInfo ?: return false).positions + + // Do not allow dragging for single-display topology, since there is nothing to clamp it to. + if (positions.size <= 1) { return false } + + val stationaryDisps = positions.filter { it.first != displayId } // We have to use rawX and rawY for the coordinates since the view receiving the event is // also the view that is moving. We need coordinates relative to something that isn't diff --git a/tests/robotests/src/com/android/settings/connecteddevice/display/DisplayTopologyPreferenceTest.kt b/tests/robotests/src/com/android/settings/connecteddevice/display/DisplayTopologyPreferenceTest.kt index 9ab2cec5029..d149605a748 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/display/DisplayTopologyPreferenceTest.kt +++ b/tests/robotests/src/com/android/settings/connecteddevice/display/DisplayTopologyPreferenceTest.kt @@ -102,6 +102,15 @@ class DisplayTopologyPreferenceTest { .map { preference.mPaneContent.getChildAt(it) as DisplayBlock } .toList() + fun singleDisplayTopology(): DisplayTopology { + val primaryId = 22; + + val root = DisplayTopology.TreeNode( + primaryId, /* width= */ 200f, /* height= */ 160f, POSITION_LEFT, /* offset= */ 0f) + + return DisplayTopology(root, primaryId) + } + fun twoDisplayTopology(childPosition: Int, childOffset: Float): DisplayTopology { val primaryId = 1 @@ -287,6 +296,36 @@ class DisplayTopologyPreferenceTest { assertThat(preference.mTimesReceivedSameTopology).isEqualTo(1) } + @Test + fun cannotMoveSingleDisplay() { + injector.topology = singleDisplayTopology() + preparePane() + + val paneChildren = getPaneChildren() + assertThat(paneChildren).hasSize(1) + val block = paneChildren[0] + + val origY = block.unpaddedY + + block.dispatchTouchEvent(MotionEventBuilder.newBuilder() + .setAction(MotionEvent.ACTION_DOWN) + .setPointer(0f, 0f) + .build()) + block.dispatchTouchEvent(MotionEventBuilder.newBuilder() + .setAction(MotionEvent.ACTION_MOVE) + .setPointer(0f, 30f) + .build()) + + assertThat(block.unpaddedY).isWithin(0.01f).of(origY) + + block.dispatchTouchEvent(MotionEventBuilder.newBuilder() + .setAction(MotionEvent.ACTION_UP) + .build()) + + // Block should be back to original position. + assertThat(block.unpaddedY).isWithin(0.01f).of(origY) + } + @Test fun updatedTopologyCancelsDragIfNonTrivialChange() { val (leftBlock, rightBlock) = setupTwoDisplays(POSITION_LEFT, /* childOffset= */ 42f)