Merge "Simplify pane sizing and scaling algorithm" into main
This commit is contained in:
committed by
Android (Google) Code Review
commit
d73552fca5
@@ -67,10 +67,10 @@ fun Float.atLeast(n: Number): Float = max(this, n.toFloat())
|
||||
* pane coordinates is necessary when rendering the original topology. Conversion in the other
|
||||
* direction, to display coordinates, is necessary for resolve a drag position to display space.
|
||||
*
|
||||
* The topology pane coordinates are integral and represent the relative position from the upper-
|
||||
* 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.
|
||||
* The topology pane coordinates are physical pixels and represent the relative position from the
|
||||
* upper-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 minPaneHeight smallest allowed height of the pane in view coordinates. This will not
|
||||
@@ -79,14 +79,13 @@ fun Float.atLeast(n: Number): Float = max(this, n.toFloat())
|
||||
* @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 maxEdgeLength the longest width or height permitted of a display block. This will limit
|
||||
* the amount of dragging and scrolling the user will need to do to set the
|
||||
* arrangement.
|
||||
* @param displaysPos the absolute topology coordinates for each display in the topology.
|
||||
*/
|
||||
class TopologyScale(
|
||||
paneWidth: Int, minPaneHeight: Float, minEdgeLength: Float, maxBlockRatio: Float,
|
||||
paneWidth: Int, minPaneHeight: Float, minEdgeLength: Float, maxEdgeLength: Float,
|
||||
displaysPos: Collection<RectF>) {
|
||||
/** Scale of block sizes to real-world display sizes. Should be less than 1. */
|
||||
val blockRatio: Float
|
||||
@@ -104,40 +103,33 @@ class TopologyScale(
|
||||
val displayBounds = RectF(
|
||||
Float.MAX_VALUE, Float.MAX_VALUE, Float.MIN_VALUE, Float.MIN_VALUE)
|
||||
var smallestDisplayDim = Float.MAX_VALUE
|
||||
var biggestDisplayHeight = Float.MIN_VALUE
|
||||
var biggestDisplayDim = Float.MIN_VALUE
|
||||
|
||||
// displayBounds is the smallest rect encompassing all displays, in display space.
|
||||
// smallestDisplayDim is the size of the smallest display edge, in display space.
|
||||
for (pos in displaysPos) {
|
||||
displayBounds.union(pos)
|
||||
smallestDisplayDim = minOf(smallestDisplayDim, pos.height(), pos.width())
|
||||
biggestDisplayHeight = max(biggestDisplayHeight, pos.height())
|
||||
biggestDisplayDim = maxOf(biggestDisplayDim, pos.height(), pos.width())
|
||||
}
|
||||
|
||||
// Set height according to the width and the aspect ratio of the display bounds limited by
|
||||
// maxBlockRatio. It prevents blocks from being too large, which would make dragging and
|
||||
// dropping awkward.
|
||||
blockRatio = maxBlockRatio
|
||||
.atMost(paneWidth * 0.6 / displayBounds.width())
|
||||
// If the `ratio` is set too low because one of the displays will have an edge less
|
||||
// than minEdgeLength(dp) long, increase it such that the smallest edge is that
|
||||
// long.
|
||||
// Initialize blockRatio such that there is 20% padding on left and right sides of the
|
||||
// display bounds.
|
||||
blockRatio = (paneWidth * 0.6 / displayBounds.width()).toFloat()
|
||||
// If the `ratio` is set too high because one of the displays will have an edge
|
||||
// greater than maxEdgeLength(px) long, decrease it such that the largest edge is
|
||||
// that long.
|
||||
.atMost(maxEdgeLength / biggestDisplayDim)
|
||||
// Also do the opposite of the above, this latter step taking precedence for a11y
|
||||
// requirements.
|
||||
.atLeast(minEdgeLength / smallestDisplayDim)
|
||||
|
||||
// Essentially, we just set the pane height based on the pre-determined pane width and the
|
||||
// aspect ratio of the display bounds.
|
||||
paneHeight = (paneWidth.toFloat() / displayBounds.width() * displayBounds.height())
|
||||
// We may need to increase it slightly to achieve 20% padding above and below the
|
||||
// display bounds - this is where the 0.6 comes from.
|
||||
.atLeast(displayBounds.height() * blockRatio / 0.6)
|
||||
|
||||
// It is easy for the aspect ratio to result in an excessively tall pane, since the
|
||||
// width is pre-determined and may be considerably wider than necessary. So we
|
||||
paneHeight = minPaneHeight
|
||||
// A tall pane is likely to result in more scrolling. So we
|
||||
// prevent the height from growing too large here, by limiting vertical padding to
|
||||
// the size of the tallest display. This improves results for very tall display
|
||||
// bounds.
|
||||
.atMost(blockRatio * (displayBounds.height() + biggestDisplayHeight * 2f))
|
||||
.atLeast(minPaneHeight)
|
||||
// 1.5x of the minEdgeLength on each side. This keeps a comfortable amount of
|
||||
// padding without it resulting in too much deadspace.
|
||||
.atLeast(blockRatio * displayBounds.height() + minEdgeLength * 3f)
|
||||
|
||||
// Set originPaneXY (the location of 0,0 in display space in the pane's coordinate system)
|
||||
// such that the display bounds rect is centered in the pane.
|
||||
@@ -414,7 +406,7 @@ class DisplayTopologyPreference(context : Context)
|
||||
val scaling = TopologyScale(
|
||||
mPaneContent.width, minPaneHeight = mTopologyInfo?.scaling?.paneHeight ?: 0f,
|
||||
minEdgeLength = DisplayTopology.dpToPx(60f, dpi),
|
||||
maxBlockRatio = DisplayTopology.dpToPx(0.12f, dpi),
|
||||
maxEdgeLength = DisplayTopology.dpToPx(256f, dpi),
|
||||
newBounds.map { it.second }.toList())
|
||||
mPaneHolder.layoutParams.let {
|
||||
val newHeight = scaling.paneHeight.toInt()
|
||||
|
Reference in New Issue
Block a user