Allow tweaking minimum block size and max block ratio

The original settings of 48 and 0.05 resulted in very small results in
real-world use. The min edge length of 48 does not account for possible
padding and is unnecessarily small. The block ratio of 0.05 is probably
OK to exceed, and is unnecessarily limiting. It is worth noting that the
previous defaults usually caused a conflict between the min length and
max ratio.

Keep the parameters in case we change our mind later.

Test: TopologyScaleTest
Flag: com.android.settings.flags.display_topology_pane_in_display_list
Bug: b/352648432
Change-Id: If8f72dd2e0652ffb33f3d61b137ac7d64a4477f5
This commit is contained in:
Matthew DeVore
2024-12-10 21:25:42 +00:00
parent 97072e434d
commit 913b836bd8
2 changed files with 57 additions and 12 deletions

View File

@@ -41,8 +41,20 @@ import kotlin.math.min
* left corner of the pane. It uses a scale optimized for showing all displays with minimal or no * left corner of the pane. It uses a scale optimized for showing all displays with minimal or no
* scrolling. The display coordinates are floating point and the origin can be in any position. In * scrolling. The display coordinates are floating point and the origin can be in any position. In
* practice the origin will be the upper-left coordinate of the primary display. * practice the origin will be the upper-left coordinate of the primary display.
*
* @param paneWidth width of the pane in view coordinates
* @param minEdgeLength the smallest length permitted of a display block. This should be set based
* on accessibility requirements, but also accounting for padding that appears
* around each button.
* @param maxBlockRatio the highest allowed ratio of block size to display size. For instance, a
* value of 0.05 means the block will at most be 1/20 the size of the display
* it represents. This limit may be breached to account for minEdgeLength,
* which is considered an a11y requirement.
* @param displaysPos the absolute topology coordinates for each display in the topology.
*/ */
class TopologyScale(paneWidth : Int, displaysPos : Collection<RectF>) { class TopologyScale(
paneWidth : Int, minEdgeLength : Int, maxBlockRatio : Float,
displaysPos : Collection<RectF>) {
/** Scale of block sizes to real-world display sizes. Should be less than 1. */ /** Scale of block sizes to real-world display sizes. Should be less than 1. */
val blockRatio : Float val blockRatio : Float
@@ -69,16 +81,14 @@ class TopologyScale(paneWidth : Int, displaysPos : Collection<RectF>) {
biggestDisplayHeight = max(biggestDisplayHeight, pos.height()) biggestDisplayHeight = max(biggestDisplayHeight, pos.height())
} }
// Set height according to the width and the aspect ratio of the display bounds. // Set height according to the width and the aspect ratio of the display bounds limitted by
// 0.05 is a reasonable limit to the size of display blocks. It appears to match the // maxBlockRatio. It prevents blocks from being too large, which would make dragging and
// ratio used in the ChromeOS topology editor. It prevents blocks from being too large, // dropping awkward.
// which would make dragging and dropping awkward. val rawBlockRatio = min(maxBlockRatio, paneWidth.toFloat() * 0.6f / displayBounds.width())
val rawBlockRatio = min(0.05, paneWidth.toDouble() * 0.6 / displayBounds.width())
// If the `ratio` is set too low because one of the displays will have an edge less than // If the `ratio` is set too low because one of the displays will have an edge less than
// 48dp long, increase it such that the smallest edge is that long. This may override the // minEdgeLength(dp) long, increase it such that the smallest edge is that long.
// 0.05 limit since it is more important than it. blockRatio = max(minEdgeLength.toFloat() / smallestDisplayDim, rawBlockRatio).toFloat()
blockRatio = max(48.0 / smallestDisplayDim, rawBlockRatio).toFloat()
// Essentially, we just set the pane height based on the pre-determined pane width and the // Essentially, we just set the pane height based on the pre-determined pane width and the
// aspect ratio of the display bounds. But we may need to increase it slightly to achieve // aspect ratio of the display bounds. But we may need to increase it slightly to achieve
@@ -99,9 +109,9 @@ class TopologyScale(paneWidth : Int, displaysPos : Collection<RectF>) {
// such that the display bounds rect is centered in the pane. // such that the display bounds rect is centered in the pane.
// It is unlikely that either of these coordinates will be negative since blockRatio has // It is unlikely that either of these coordinates will be negative since blockRatio has
// been chosen to allow 20% padding around each side of the display blocks. However, the // been chosen to allow 20% padding around each side of the display blocks. However, the
// a11y requirement applied above (48.0 / smallestDisplayDim) may cause the blocks to not // a11y requirement applied above (minEdgeLength / smallestDisplayDim) may cause the blocks
// fit. This should be rare in practice, and can be worked around by moving the settings UI // to not fit. This should be rare in practice, and can be worked around by moving the
// to a larger display. // settings UI to a larger display.
val blockMostLeft = (paneWidth - displayBounds.width() * blockRatio) / 2 val blockMostLeft = (paneWidth - displayBounds.width() * blockRatio) / 2
val blockMostTop = (paneHeight - displayBounds.height() * blockRatio) / 2 val blockMostTop = (paneHeight - displayBounds.height() * blockRatio) / 2

View File

@@ -35,6 +35,7 @@ class TopologyScaleTest {
fun oneDisplay4to3Aspect() { fun oneDisplay4to3Aspect() {
val scale = TopologyScale( val scale = TopologyScale(
/* paneWidth= */ 640, /* paneWidth= */ 640,
minEdgeLength = 48, maxBlockRatio = 0.05f,
listOf(RectF(0f, 0f, 640f, 480f))) listOf(RectF(0f, 0f, 640f, 480f)))
// blockRatio is higher than 0.05 in order to make the smallest display edge (480 dp) 48dp // blockRatio is higher than 0.05 in order to make the smallest display edge (480 dp) 48dp
@@ -51,6 +52,7 @@ class TopologyScaleTest {
fun twoUnalignedDisplays() { fun twoUnalignedDisplays() {
val scale = TopologyScale( val scale = TopologyScale(
/* paneWidth= */ 300, /* paneWidth= */ 300,
minEdgeLength = 48, maxBlockRatio = 0.05f,
listOf(RectF(0f, 0f, 1920f, 1200f), RectF(1920f, -300f, 3840f, 900f))) listOf(RectF(0f, 0f, 1920f, 1200f), RectF(1920f, -300f, 3840f, 900f)))
assertEquals( assertEquals(
@@ -65,6 +67,7 @@ class TopologyScaleTest {
fun twoDisplaysBlockRatioBumpedForGarSizeMinimumHorizontal() { fun twoDisplaysBlockRatioBumpedForGarSizeMinimumHorizontal() {
val scale = TopologyScale( val scale = TopologyScale(
/* paneWidth= */ 192, /* paneWidth= */ 192,
minEdgeLength = 48, maxBlockRatio = 0.05f,
listOf(RectF(0f, 0f, 240f, 320f), RectF(-240f, -320f, 0f, 0f))) listOf(RectF(0f, 0f, 240f, 320f), RectF(-240f, -320f, 0f, 0f)))
// blockRatio is higher than 0.05 in order to make the smallest display edge (240 dp) 48dp // blockRatio is higher than 0.05 in order to make the smallest display edge (240 dp) 48dp
@@ -81,6 +84,7 @@ class TopologyScaleTest {
fun paneVerticalPaddingLimitedByTallestDisplay() { fun paneVerticalPaddingLimitedByTallestDisplay() {
val scale = TopologyScale( val scale = TopologyScale(
/* paneWidth= */ 300, /* paneWidth= */ 300,
minEdgeLength = 48, maxBlockRatio = 0.05f,
listOf( listOf(
RectF(0f, 0f, 640f, 480f), RectF(0f, 0f, 640f, 480f),
RectF(0f, 480f, 640f, 960f), RectF(0f, 480f, 640f, 960f),
@@ -94,4 +98,35 @@ class TopologyScaleTest {
assertEquals(Point(150, 48), scale.displayToPaneCoor(PointF(320f, 0f))) assertEquals(Point(150, 48), scale.displayToPaneCoor(PointF(320f, 0f)))
assertPointF(-180f, 2880f, 0.001f, scale.paneToDisplayCoor(Point(100, 336))) assertPointF(-180f, 2880f, 0.001f, scale.paneToDisplayCoor(Point(100, 336)))
} }
@Test
fun limitedByCustomMaxBlockRatio() {
val scale = TopologyScale(
/* paneWidth= */ 300,
minEdgeLength = 24, maxBlockRatio = 0.12f,
listOf(
RectF(0f, 0f, 640f, 480f),
RectF(0f, 480f, 640f, 960f)))
assertEquals(
"{TopoScale blockRatio=0.120000 originPaneXY=111,57 paneHeight=230}", "" + scale)
assertEquals(Point(149, 57), scale.displayToPaneCoor(PointF(320f, 0f)))
assertPointF(-91.6667f, 2325f, 0.001f, scale.paneToDisplayCoor(Point(100, 336)))
}
@Test
fun largeCustomMinEdgeLength() {
// minBlockEdgeLength/minDisplayEdgeLength = 80/480 = 1/6, so the block ratio will be 1/6
val scale = TopologyScale(
/* paneWidth= */ 300,
minEdgeLength = 80, maxBlockRatio = 0.05f,
listOf(
RectF(0f, 0f, 640f, 480f),
RectF(0f, 480f, 640f, 960f)))
assertEquals(
"{TopoScale blockRatio=0.166667 originPaneXY=96,80 paneHeight=320}", "" + scale)
assertEquals(Point(149, 80), scale.displayToPaneCoor(PointF(320f, 0f)))
assertPointF(24f, 1536f, 0.001f, scale.paneToDisplayCoor(Point(100, 336)))
}
} }