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

Commit b39c74af authored by Pierre Barbier de Reuille's avatar Pierre Barbier de Reuille
Browse files

Fix the size of the handle and touch area.

Set the touch region correctly, including corners, divider and handle.
Also increases the size of the handle.

Fix: 377960322
Test: manual + existing tests
Flag: com.android.window.flags.enable_tile_resizing

Change-Id: I148e9b0117c0205fea71eef6bf9d4f042227ac4d
parent 27e05672
Loading
Loading
Loading
Loading
+75 −14
Original line number Diff line number Diff line
@@ -18,10 +18,12 @@ package com.android.wm.shell.windowdecor.tiling

import android.content.Context
import android.content.res.Configuration
import android.graphics.Path
import android.graphics.PixelFormat
import android.graphics.Rect
import android.graphics.Region
import android.os.Binder
import android.util.Size
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.RoundedCorner
@@ -40,7 +42,6 @@ import android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER
import android.view.WindowlessWindowManager
import com.android.wm.shell.R
import com.android.wm.shell.common.SyncTransactionQueue
import com.android.wm.shell.desktopmode.DesktopModeEventLogger
import java.util.function.Supplier

/**
@@ -48,7 +49,7 @@ import java.util.function.Supplier
 * when two tasks are tiled on left and right to resize them simultaneously.
 */
class DesktopTilingDividerWindowManager(
    private val config: Configuration,
    config: Configuration,
    private val windowName: String,
    private val context: Context,
    private val leash: SurfaceControl,
@@ -61,7 +62,11 @@ class DesktopTilingDividerWindowManager(
    private lateinit var viewHost: SurfaceControlViewHost
    private var tilingDividerView: TilingDividerView? = null
    private var dividerShown = false
    private var handleRegionWidth: Int = -1
    private var handleRegionSize: Size =
        Size(
            context.resources.getDimensionPixelSize(R.dimen.split_divider_handle_region_width),
            context.resources.getDimensionPixelSize(R.dimen.split_divider_handle_region_height),
        )
    private var setTouchRegion = true
    private val maxRoundedCornerRadius = getMaxRoundedCornerRadius()

@@ -74,9 +79,62 @@ class DesktopTilingDividerWindowManager(
        rect.set(dividerBounds)
    }

    /** Sets the touch region for the SurfaceControlViewHost. */
    fun setTouchRegion(region: Rect) {
        setTouchRegion(viewHost.windowToken.asBinder(), Region(region))
    /**
     * Sets the touch region for the SurfaceControlViewHost.
     *
     * The region includes the area around the handle (for accessibility), the divider itself and
     * the rounded corners (to prevent click reaching windows behind).
     */
    fun setTouchRegion(handle: Rect, divider: Rect, cornerRadius: Float) {
        val path = Path()
        path.fillType = Path.FillType.WINDING
        // The UI starts on the top-left corner, the region will be:
        //
        //      cornerLeft     cornerRight
        // c1Top        +--------+
        //              |corners |
        // c1Bottom     +--+  +--+
        //                 |  |
        //       handleLeft|  |  handleRight
        // handleTop  +----+  +----+
        //            |  handle    |
        // handleBot  +----+  +----+
        //                 |  |
        //                 |  |
        // c2Top        +--+  +--+
        //              |corners |
        // c2Bottom     +--------+
        val cornerLeft = 0f
        val centerX = cornerRadius + divider.width() / 2f
        val centerY = divider.height()
        val cornerRight = divider.width() + 2 * cornerRadius
        val handleLeft = centerX - handle.width() / 2f
        val handleRight = handleLeft + handle.width()
        val dividerLeft = centerY - divider.width() / 2f
        val dividerRight = dividerLeft + divider.width()

        val c1Top = 0f
        val c1Bottom = cornerRadius
        val handleTop = centerY - handle.height() / 2f
        val handleBottom = handleTop + handle.height()
        val c2Top = divider.height() - cornerRadius
        val c2Bottom = divider.height().toFloat()

        // Top corners
        path.addRect(cornerLeft, c1Top, cornerRight, c1Bottom, Path.Direction.CCW)
        // Bottom corners
        path.addRect(cornerLeft, c1Top, cornerRight, c2Bottom, Path.Direction.CCW)
        // Handle
        path.addRect(handleLeft, handleTop, handleRight, handleBottom, Path.Direction.CCW)
        // Divider
        path.addRect(dividerLeft, c2Top, dividerRight, c2Bottom, Path.Direction.CCW)

        val clip = Rect(handleLeft.toInt(), c1Top.toInt(), handleRight.toInt(), c2Bottom.toInt())

        val region = Region()
        region.setPath(path, Region(clip))

        setTouchRegion(viewHost.windowToken.asBinder(), region)
    }

    /**
@@ -96,7 +154,7 @@ class DesktopTilingDividerWindowManager(
        surfaceControlViewHost.setView(dividerView, lp)
        val tmpDividerBounds = Rect()
        getDividerBounds(tmpDividerBounds)
        dividerView.setup(this, tmpDividerBounds)
        dividerView.setup(this, tmpDividerBounds, handleRegionSize)
        t.setRelativeLayer(leash, relativeLeash, 1)
            .setPosition(
                leash,
@@ -112,7 +170,7 @@ class DesktopTilingDividerWindowManager(
        viewHost = surfaceControlViewHost
        dividerView.addOnLayoutChangeListener(this)
        tilingDividerView = dividerView
        handleRegionWidth = dividerView.handleRegionWidth
        updateTouchRegion()
    }

    /** Hides the divider bar. */
@@ -176,8 +234,8 @@ class DesktopTilingDividerWindowManager(
    private fun getWindowManagerParams(): WindowManager.LayoutParams {
        val lp =
            WindowManager.LayoutParams(
                dividerBounds.width() + 2 * maxRoundedCornerRadius,
                dividerBounds.height(),
                /* w= */ dividerBounds.width() + 2 * maxRoundedCornerRadius,
                /* h= */ dividerBounds.height(),
                TYPE_DOCK_DIVIDER,
                FLAG_NOT_FOCUSABLE or
                    FLAG_NOT_TOUCH_MODAL or
@@ -216,13 +274,16 @@ class DesktopTilingDividerWindowManager(
    ) {
        if (!setTouchRegion) return

        val startX = (dividerBounds.width() - handleRegionWidth) / 2
        val startY = 0
        val tempRect = Rect(startX, startY, startX + handleRegionWidth, dividerBounds.height())
        setTouchRegion(tempRect)
        updateTouchRegion()
        setTouchRegion = false
    }

    private fun updateTouchRegion() {
        val startX = -handleRegionSize.width / 2
        val handle = Rect(startX, 0, startX + handleRegionSize.width, dividerBounds.height())
        setTouchRegion(handle, dividerBounds, maxRoundedCornerRadius.toFloat())
    }

    private fun setSlippery(slippery: Boolean) {
        val lp = tilingDividerView?.layoutParams as WindowManager.LayoutParams
        val isSlippery = (lp.flags and FLAG_SLIPPERY) != 0
+18 −13
Original line number Diff line number Diff line
@@ -21,8 +21,10 @@ import android.graphics.Paint
import android.graphics.Rect
import android.provider.DeviceConfig
import android.util.AttributeSet
import android.util.Size
import android.view.MotionEvent
import android.view.PointerIcon
import android.view.RoundedCorner
import android.view.View
import android.view.ViewConfiguration
import android.widget.FrameLayout
@@ -42,6 +44,7 @@ class TilingDividerView : FrameLayout, View.OnTouchListener, DragDetector.Motion
    private lateinit var callback: DividerMoveCallback
    private lateinit var handle: DividerHandleView
    private lateinit var corners: DividerRoundedCorner
    private var cornersRadius: Int = 0
    private var touchElevation = 0

    private var moving = false
@@ -49,8 +52,7 @@ class TilingDividerView : FrameLayout, View.OnTouchListener, DragDetector.Motion
    var handleRegionWidth: Int = 0
    private var handleRegionHeight = 0
    private var lastAcceptedPos = 0
    @VisibleForTesting var handleStartY = 0
    @VisibleForTesting var handleEndY = 0
    @VisibleForTesting var handleY: IntRange = 0..0
    private var canResize = false
    private var resized = false
    /**
@@ -79,16 +81,19 @@ class TilingDividerView : FrameLayout, View.OnTouchListener, DragDetector.Motion
    ) : super(context, attrs, defStyleAttr, defStyleRes)

    /** Sets up essential dependencies of the divider bar. */
    fun setup(dividerMoveCallback: DividerMoveCallback, dividerBounds: Rect) {
    fun setup(
        dividerMoveCallback: DividerMoveCallback,
        dividerBounds: Rect,
        handleRegionSize: Size,
    ) {
        callback = dividerMoveCallback
        this.dividerBounds.set(dividerBounds)
        handle.setIsLeftRightSplit(true)
        corners.setIsLeftRightSplit(true)
        handleRegionHeight =
            resources.getDimensionPixelSize(R.dimen.split_divider_handle_region_width)

        handleRegionWidth =
            resources.getDimensionPixelSize(R.dimen.split_divider_handle_region_height)
        handleRegionHeight = handleRegionSize.height
        handleRegionWidth = handleRegionSize.width
        cornersRadius =
            context.display.getRoundedCorner(RoundedCorner.POSITION_TOP_LEFT)?.radius ?: 0
        initHandleYCoordinates()
        dragDetector =
            DragDetector(
@@ -241,17 +246,17 @@ class TilingDividerView : FrameLayout, View.OnTouchListener, DragDetector.Motion
        return true
    }

    private fun isWithinHandleRegion(touchYPos: Int): Boolean {
        return touchYPos in handleStartY..handleEndY
    }
    private fun isWithinHandleRegion(touchYPos: Int): Boolean = touchYPos in handleY

    private fun initHandleYCoordinates() {
        handleStartY = (dividerBounds.height() - handleRegionHeight) / 2
        handleEndY = handleStartY + handleRegionHeight
        val handleStartY = (dividerBounds.height() - handleRegionHeight) / 2
        val handleEndY = handleStartY + handleRegionHeight
        handleY = handleStartY..handleEndY
    }

    companion object {
        const val TOUCH_ANIMATION_DURATION: Long = 150
        const val TOUCH_RELEASE_ANIMATION_DURATION: Long = 200
        private val TAG = TilingDividerView::class.java.simpleName
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -122,6 +122,6 @@ class DesktopTilingDividerWindowManagerTest : ShellTestCase() {

    companion object {
        private val BOUNDS = Rect(1, 2, 3, 4)
        private val CORNER_RADIUS = 28
        private const val CORNER_RADIUS = 28
    }
}
+12 −4
Original line number Diff line number Diff line
@@ -19,9 +19,12 @@ package com.android.wm.shell.windowdecor.tiling
import android.graphics.Rect
import android.os.SystemClock
import android.testing.AndroidTestingRunner
import android.util.Size
import android.view.Display
import android.view.InputDevice
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.RoundedCorner
import android.view.View
import androidx.test.annotation.UiThreadTest
import androidx.test.filters.SmallTest
@@ -46,16 +49,19 @@ class TilingDividerViewTest : ShellTestCase() {
    private val dividerMoveCallbackMock = mock<DividerMoveCallback>()

    private val viewMock = mock<View>()
    private val display = mock<Display>()
    private val roundedCorner = mock<RoundedCorner>()

    @Before
    @UiThreadTest
    fun setUp() {
        whenever(display.getRoundedCorner(any())).thenReturn(roundedCorner)
        whenever(roundedCorner.radius).thenReturn(CORNER_RADIUS)
        tilingDividerView =
            LayoutInflater.from(mContext).inflate(R.layout.tiling_split_divider, /* root= */ null)
                as TilingDividerView
        tilingDividerView.setup(dividerMoveCallbackMock, BOUNDS)
        tilingDividerView.handleStartY = 0
        tilingDividerView.handleEndY = 1500
        tilingDividerView.setup(dividerMoveCallbackMock, DIVIDER_BOUNDS, HANDLE_SIZE)
        tilingDividerView.handleY = 0..1500
    }

    @Test
@@ -130,6 +136,8 @@ class TilingDividerViewTest : ShellTestCase() {
    }

    companion object {
        private val BOUNDS = Rect(0, 0, 1500, 1500)
        private val DIVIDER_BOUNDS = Rect(15, 0, 35, 1500)
        private val HANDLE_SIZE = Size(800, 300)
        private const val CORNER_RADIUS = 15
    }
}