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
* 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.
*
* @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. */
val blockRatio : Float
@@ -69,16 +81,14 @@ class TopologyScale(paneWidth : Int, displaysPos : Collection<RectF>) {
biggestDisplayHeight = max(biggestDisplayHeight, pos.height())
}
// Set height according to the width and the aspect ratio of the display bounds.
// 0.05 is a reasonable limit to the size of display blocks. It appears to match the
// ratio used in the ChromeOS topology editor. It prevents blocks from being too large,
// which would make dragging and dropping awkward.
val rawBlockRatio = min(0.05, paneWidth.toDouble() * 0.6 / displayBounds.width())
// Set height according to the width and the aspect ratio of the display bounds limitted by
// maxBlockRatio. It prevents blocks from being too large, which would make dragging and
// dropping awkward.
val rawBlockRatio = min(maxBlockRatio, paneWidth.toFloat() * 0.6f / displayBounds.width())
// 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
// 0.05 limit since it is more important than it.
blockRatio = max(48.0 / smallestDisplayDim, rawBlockRatio).toFloat()
// minEdgeLength(dp) long, increase it such that the smallest edge is that long.
blockRatio = max(minEdgeLength.toFloat() / smallestDisplayDim, rawBlockRatio).toFloat()
// 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
@@ -99,9 +109,9 @@ class TopologyScale(paneWidth : Int, displaysPos : Collection<RectF>) {
// 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
// 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
// fit. This should be rare in practice, and can be worked around by moving the settings UI
// to a larger display.
// a11y requirement applied above (minEdgeLength / smallestDisplayDim) may cause the blocks
// to not fit. This should be rare in practice, and can be worked around by moving the
// settings UI to a larger display.
val blockMostLeft = (paneWidth - displayBounds.width() * blockRatio) / 2
val blockMostTop = (paneHeight - displayBounds.height() * blockRatio) / 2

View File

@@ -35,6 +35,7 @@ class TopologyScaleTest {
fun oneDisplay4to3Aspect() {
val scale = TopologyScale(
/* paneWidth= */ 640,
minEdgeLength = 48, maxBlockRatio = 0.05f,
listOf(RectF(0f, 0f, 640f, 480f)))
// 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() {
val scale = TopologyScale(
/* paneWidth= */ 300,
minEdgeLength = 48, maxBlockRatio = 0.05f,
listOf(RectF(0f, 0f, 1920f, 1200f), RectF(1920f, -300f, 3840f, 900f)))
assertEquals(
@@ -65,6 +67,7 @@ class TopologyScaleTest {
fun twoDisplaysBlockRatioBumpedForGarSizeMinimumHorizontal() {
val scale = TopologyScale(
/* paneWidth= */ 192,
minEdgeLength = 48, maxBlockRatio = 0.05f,
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
@@ -81,6 +84,7 @@ class TopologyScaleTest {
fun paneVerticalPaddingLimitedByTallestDisplay() {
val scale = TopologyScale(
/* paneWidth= */ 300,
minEdgeLength = 48, maxBlockRatio = 0.05f,
listOf(
RectF(0f, 0f, 640f, 480f),
RectF(0f, 480f, 640f, 960f),
@@ -94,4 +98,35 @@ class TopologyScaleTest {
assertEquals(Point(150, 48), scale.displayToPaneCoor(PointF(320f, 0f)))
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)))
}
}