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)