Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4943337e authored by Matthew DeVore's avatar Matthew DeVore Committed by Android (Google) Code Review
Browse files

Merge "Do not shrink topology pane after a drag" into main

parents 98124ddb 515a2ef2
Loading
Loading
Loading
Loading
+31 −21
Original line number Diff line number Diff line
@@ -51,6 +51,10 @@ import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min

// These extension methods make calls to min and max chainable.
fun Float.atMost(n: Number): Float = min(this, n.toFloat())
fun Float.atLeast(n: Number): Float = max(this, n.toFloat())

/**
 * Contains the parameters needed for transforming global display coordinates to and from topology
 * pane coordinates. This is necessary for implementing an interactive display topology pane. The
@@ -64,6 +68,9 @@ import kotlin.math.min
 * 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
 *                      affect the block ratio, but only the final height of the pane and the
 *                      position of the display bounds' center.
 * @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.
@@ -74,7 +81,7 @@ import kotlin.math.min
 * @param displaysPos the absolute topology coordinates for each display in the topology.
 */
class TopologyScale(
        paneWidth : Int, minEdgeLength : Int, maxBlockRatio : Float,
        paneWidth: Int, minPaneHeight: Float, minEdgeLength: Int, maxBlockRatio: Float,
        displaysPos: Collection<RectF>) {
    /** Scale of block sizes to real-world display sizes. Should be less than 1. */
    val blockRatio: Float
@@ -102,28 +109,30 @@ class TopologyScale(
            biggestDisplayHeight = max(biggestDisplayHeight, pos.height())
        }

        // Set height according to the width and the aspect ratio of the display bounds limitted by
        // 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.
        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
        // minEdgeLength(dp) long, increase it such that the smallest edge is that long.
        blockRatio = max(minEdgeLength.toFloat() / smallestDisplayDim, rawBlockRatio).toFloat()
        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.
                .atLeast(minEdgeLength.toFloat() / smallestDisplayDim)

        // 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
        // 20% padding above and below the display bounds - this is where the 0.6 comes from.
        val rawPaneHeight = max(
                paneWidth.toDouble() / displayBounds.width() * displayBounds.height(),
                displayBounds.height() * blockRatio / 0.6).toFloat()

        // 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 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.
        paneHeight = min(
                rawPaneHeight, blockRatio * (displayBounds.height() + biggestDisplayHeight * 2f))
        // 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
                // 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)

        // 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.
@@ -365,7 +374,8 @@ class DisplayTopologyPreference(context : Context)
        }

        val scaling = TopologyScale(
                mPaneContent.width, minEdgeLength = 60, maxBlockRatio = 0.12f,
                mPaneContent.width, minPaneHeight = mTopologyInfo?.scaling?.paneHeight ?: 0f,
                minEdgeLength = 60, maxBlockRatio = 0.12f,
                newBounds.map { it.second }.toList())
        mPaneHolder.layoutParams.let {
            val newHeight = scaling.paneHeight.toInt()
+17 −6
Original line number Diff line number Diff line
@@ -34,7 +34,7 @@ class TopologyScaleTest {
    @Test
    fun oneDisplay4to3Aspect() {
        val scale = TopologyScale(
                /* paneWidth= */ 640,
                /* paneWidth= */ 640, minPaneHeight = 0f,
                minEdgeLength = 48, maxBlockRatio = 0.05f,
                listOf(RectF(0f, 0f, 640f, 480f)))

@@ -47,12 +47,23 @@ class TopologyScaleTest {
        assertPointF(352f, 96f, 0.001f, scale.displayToPaneCoor(640f, 480f))
        assertPointF(320f, 72f, 0.001f, scale.displayToPaneCoor(320f, 240f))
        assertPointF(640f, 480f, 0.001f, scale.paneToDisplayCoor(352f, 96f))

        // Same as original scale but made taller with minPaneHeight.
        // The paneHeight and origin coordinates are changed but the block ratio is the same.
        val taller = TopologyScale(
                /* paneWidth= */ 640, minPaneHeight = 155.0f,
                minEdgeLength = 48, maxBlockRatio = 0.05f,
                listOf(RectF(0f, 0f, 640f, 480f)))

        assertEquals(
                "{TopologyScale blockRatio=0.100000 originPaneXY=288.0,53.5 paneHeight=155.0}",
                "" + taller)
    }

    @Test
    fun twoUnalignedDisplays() {
        val scale = TopologyScale(
                /* paneWidth= */ 300,
                /* paneWidth= */ 300, minPaneHeight = 0f,
                minEdgeLength = 48, maxBlockRatio = 0.05f,
                listOf(RectF(0f, 0f, 1920f, 1200f), RectF(1920f, -300f, 3840f, 900f)))

@@ -68,7 +79,7 @@ class TopologyScaleTest {
    @Test
    fun twoDisplaysBlockRatioBumpedForGarSizeMinimumHorizontal() {
        val scale = TopologyScale(
                /* paneWidth= */ 192,
                /* paneWidth= */ 192, minPaneHeight = 0f,
                minEdgeLength = 48, maxBlockRatio = 0.05f,
                listOf(RectF(0f, 0f, 240f, 320f), RectF(-240f, -320f, 0f, 0f)))

@@ -86,7 +97,7 @@ class TopologyScaleTest {
    @Test
    fun paneVerticalPaddingLimitedByTallestDisplay() {
        val scale = TopologyScale(
                /* paneWidth= */ 300,
                /* paneWidth= */ 300, minPaneHeight = 0f,
                minEdgeLength = 48, maxBlockRatio = 0.05f,
                listOf(
                        RectF(0f, 0f, 640f, 480f),
@@ -106,7 +117,7 @@ class TopologyScaleTest {
    @Test
    fun limitedByCustomMaxBlockRatio() {
        val scale = TopologyScale(
                /* paneWidth= */ 300,
                /* paneWidth= */ 300, minPaneHeight = 0f,
                minEdgeLength = 24, maxBlockRatio = 0.12f,
                listOf(
                        RectF(0f, 0f, 640f, 480f),
@@ -123,7 +134,7 @@ class TopologyScaleTest {
    fun largeCustomMinEdgeLength() {
        // minBlockEdgeLength/minDisplayEdgeLength = 80/480 = 1/6, so the block ratio will be 1/6
        val scale = TopologyScale(
                /* paneWidth= */ 300,
                /* paneWidth= */ 300, minPaneHeight = 0f,
                minEdgeLength = 80, maxBlockRatio = 0.05f,
                listOf(
                        RectF(0f, 0f, 640f, 480f),