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

Commit bd5ccf06 authored by mattsziklay's avatar mattsziklay
Browse files

Determine indicator type for input outside of display.

Removes explicit TO_DESKTOP region calculation in favor of using
defaults for inputs outside display bounds. Namely:

- Inputs with x < 0 will return a TO_SPLIT_LEFT indicator.
- Inputs with x > display width will return TO_SPLIT_RIGHT indicator.
- Inputs anywhere else not in an explicitly defined region will default
  to NO_INDICATOR for freeform task drags and TO_DESKTOP for all others.
- Fullscreen region is updated to have the top be Short.MIN_VALUE to
  serve as an arbitrarily low number.

This fixes an issue where certain transitions could crash when receiving
input outside of display bounds.

Indicator test is updated accordingly.

Fix: 370613574
Test: Manual
Flag: EXEMPT bug fix
Change-Id: I5ad1aceab557f4546c68e841e5a8998b834143c6
parent f9c546be
Loading
Loading
Loading
Loading
+22 −28
Original line number Diff line number Diff line
@@ -21,6 +21,12 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;

import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.NO_INDICATOR;
import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_DESKTOP_INDICATOR;
import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR;
import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_LEFT_INDICATOR;
import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_RIGHT_INDICATOR;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.RectEvaluator;
@@ -125,7 +131,7 @@ public class DesktopModeVisualIndicator {
        mContext = context;
        mTaskSurface = taskSurface;
        mRootTdaOrganizer = taskDisplayAreaOrganizer;
        mCurrentType = IndicatorType.NO_INDICATOR;
        mCurrentType = NO_INDICATOR;
        mDragStartState = dragStartState;
    }

@@ -136,8 +142,16 @@ public class DesktopModeVisualIndicator {
    @NonNull
    IndicatorType updateIndicatorType(PointF inputCoordinates) {
        final DisplayLayout layout = mDisplayController.getDisplayLayout(mTaskInfo.displayId);
        // Perform a quick check first: any input off the left edge of the display should be split
        // left, and split right for the right edge. This is universal across all drag event types.
        if (inputCoordinates.x < 0) return TO_SPLIT_LEFT_INDICATOR;
        if (inputCoordinates.x > layout.width()) return TO_SPLIT_RIGHT_INDICATOR;
        // If we are in freeform, we don't want a visible indicator in the "freeform" drag zone.
        IndicatorType result = IndicatorType.NO_INDICATOR;
        // In drags not originating on a freeform caption, we should default to a TO_DESKTOP
        // indicator.
        IndicatorType result = mDragStartState == DragStartState.FROM_FREEFORM
                ? NO_INDICATOR
                : TO_DESKTOP_INDICATOR;
        final int transitionAreaWidth = mContext.getResources().getDimensionPixelSize(
                com.android.wm.shell.R.dimen.desktop_mode_transition_region_thickness);
        // Because drags in freeform use task position for indicator calculation, we need to
@@ -149,10 +163,8 @@ public class DesktopModeVisualIndicator {
                captionHeight);
        final Region splitRightRegion = calculateSplitRightRegion(layout, transitionAreaWidth,
                captionHeight);
        final Region toDesktopRegion = calculateToDesktopRegion(layout, splitLeftRegion,
                splitRightRegion, fullscreenRegion);
        if (fullscreenRegion.contains((int) inputCoordinates.x, (int) inputCoordinates.y)) {
            result = IndicatorType.TO_FULLSCREEN_INDICATOR;
            result = TO_FULLSCREEN_INDICATOR;
        }
        if (splitLeftRegion.contains((int) inputCoordinates.x, (int) inputCoordinates.y)) {
            result = IndicatorType.TO_SPLIT_LEFT_INDICATOR;
@@ -160,9 +172,6 @@ public class DesktopModeVisualIndicator {
        if (splitRightRegion.contains((int) inputCoordinates.x, (int) inputCoordinates.y)) {
            result = IndicatorType.TO_SPLIT_RIGHT_INDICATOR;
        }
        if (toDesktopRegion.contains((int) inputCoordinates.x, (int) inputCoordinates.y)) {
            result = IndicatorType.TO_DESKTOP_INDICATOR;
        }
        if (mDragStartState != DragStartState.DRAGGED_INTENT) {
            transitionIndicator(result);
        }
@@ -182,7 +191,7 @@ public class DesktopModeVisualIndicator {
                    R.dimen.desktop_mode_fullscreen_region_scale);
            final float toFullscreenWidth = (layout.width() * toFullscreenScale);
            region.union(new Rect((int) ((layout.width() / 2f) - (toFullscreenWidth / 2f)),
                    -captionHeight,
                    Short.MIN_VALUE,
                    (int) ((layout.width() / 2f) + (toFullscreenWidth / 2f)),
                    transitionHeight));
        }
@@ -192,28 +201,13 @@ public class DesktopModeVisualIndicator {
                || mDragStartState == DragStartState.DRAGGED_INTENT
        ) {
            region.union(new Rect(0,
                    -captionHeight,
                    Short.MIN_VALUE,
                    layout.width(),
                    transitionHeight));
        }
        return region;
    }

    @VisibleForTesting
    Region calculateToDesktopRegion(DisplayLayout layout,
            Region splitLeftRegion, Region splitRightRegion,
            Region toFullscreenRegion) {
        final Region region = new Region();
        // If in desktop, we need no region. Otherwise it's the same for all windowing modes.
        if (mDragStartState != DragStartState.FROM_FREEFORM) {
            region.union(new Rect(0, 0, layout.width(), layout.height()));
            region.op(splitLeftRegion, Region.Op.DIFFERENCE);
            region.op(splitRightRegion, Region.Op.DIFFERENCE);
            region.op(toFullscreenRegion, Region.Op.DIFFERENCE);
        }
        return region;
    }

    @VisibleForTesting
    Region calculateSplitLeftRegion(DisplayLayout layout,
            int transitionEdgeWidth, int captionHeight) {
@@ -311,7 +305,7 @@ public class DesktopModeVisualIndicator {
                }
            });
        }
        mCurrentType = IndicatorType.NO_INDICATOR;
        mCurrentType = NO_INDICATOR;
    }

    /**
@@ -322,9 +316,9 @@ public class DesktopModeVisualIndicator {
        if (mView == null) {
            createView();
        }
        if (mCurrentType == IndicatorType.NO_INDICATOR) {
        if (mCurrentType == NO_INDICATOR) {
            fadeInIndicator(newType);
        } else if (newType == IndicatorType.NO_INDICATOR) {
        } else if (newType == NO_INDICATOR) {
            fadeOutIndicator(null /* finishCallback */);
        } else {
            final VisualIndicatorAnimator animator = VisualIndicatorAnimator.animateIndicatorType(
+1 −1
Original line number Diff line number Diff line
@@ -1574,7 +1574,7 @@ class DesktopTasksController(
            return
        }

        val indicator = visualIndicator ?: return
        val indicator = getVisualIndicator() ?: return
        val indicatorType =
            indicator.updateIndicatorType(
                PointF(inputCoordinate.x, currentDragBounds.top.toFloat()),
+22 −20
Original line number Diff line number Diff line
@@ -17,8 +17,8 @@
package com.android.wm.shell.desktopmode

import android.app.ActivityManager.RunningTaskInfo
import android.graphics.PointF
import android.graphics.Rect
import android.graphics.Region
import android.testing.AndroidTestingRunner
import android.view.SurfaceControl
import androidx.test.filters.SmallTest
@@ -33,6 +33,7 @@ import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
import org.mockito.kotlin.whenever

@@ -58,13 +59,15 @@ class DesktopModeVisualIndicatorTest : ShellTestCase() {
        whenever(displayLayout.width()).thenReturn(DISPLAY_BOUNDS.width())
        whenever(displayLayout.height()).thenReturn(DISPLAY_BOUNDS.height())
        whenever(displayLayout.stableInsets()).thenReturn(STABLE_INSETS)
        whenever(displayController.getDisplayLayout(anyInt())).thenReturn(displayLayout)
    }

    @Test
    fun testFullscreenRegionCalculation() {
        createVisualIndicator(DesktopModeVisualIndicator.DragStartState.FROM_FULLSCREEN)
        var testRegion = visualIndicator.calculateFullscreenRegion(displayLayout, CAPTION_HEIGHT)
        assertThat(testRegion.bounds).isEqualTo(Rect(0, -50, 2400, 2 * STABLE_INSETS.top))
        assertThat(testRegion.bounds).isEqualTo(Rect(0, Short.MIN_VALUE.toInt(), 2400,
            2 * STABLE_INSETS.top))

        createVisualIndicator(DesktopModeVisualIndicator.DragStartState.FROM_FREEFORM)
        testRegion = visualIndicator.calculateFullscreenRegion(displayLayout, CAPTION_HEIGHT)
@@ -75,17 +78,19 @@ class DesktopModeVisualIndicatorTest : ShellTestCase() {
        val toFullscreenWidth = displayLayout.width() * toFullscreenScale
        assertThat(testRegion.bounds).isEqualTo(Rect(
            (DISPLAY_BOUNDS.width() / 2f - toFullscreenWidth / 2f).toInt(),
            -50,
            Short.MIN_VALUE.toInt(),
            (DISPLAY_BOUNDS.width() / 2f + toFullscreenWidth / 2f).toInt(),
            transitionHeight))

        createVisualIndicator(DesktopModeVisualIndicator.DragStartState.FROM_SPLIT)
        testRegion = visualIndicator.calculateFullscreenRegion(displayLayout, CAPTION_HEIGHT)
        assertThat(testRegion.bounds).isEqualTo(Rect(0, -50, 2400, 2 * STABLE_INSETS.top))
        assertThat(testRegion.bounds).isEqualTo(Rect(0, Short.MIN_VALUE.toInt(), 2400,
            2 * STABLE_INSETS.top))

        createVisualIndicator(DesktopModeVisualIndicator.DragStartState.DRAGGED_INTENT)
        testRegion = visualIndicator.calculateFullscreenRegion(displayLayout, CAPTION_HEIGHT)
        assertThat(testRegion.bounds).isEqualTo(Rect(0, -50, 2400, transitionHeight))
        assertThat(testRegion.bounds).isEqualTo(Rect(0, Short.MIN_VALUE.toInt(), 2400,
            transitionHeight))
    }

    @Test
@@ -133,22 +138,19 @@ class DesktopModeVisualIndicatorTest : ShellTestCase() {
    }

    @Test
    fun testToDesktopRegionCalculation() {
    fun testDefaultIndicators() {
        createVisualIndicator(DesktopModeVisualIndicator.DragStartState.FROM_FULLSCREEN)
        val fullscreenRegion = visualIndicator.calculateFullscreenRegion(displayLayout,
            CAPTION_HEIGHT)
        val splitLeftRegion = visualIndicator.calculateSplitLeftRegion(displayLayout,
            TRANSITION_AREA_WIDTH, CAPTION_HEIGHT)
        val splitRightRegion = visualIndicator.calculateSplitRightRegion(displayLayout,
            TRANSITION_AREA_WIDTH, CAPTION_HEIGHT)
        val desktopRegion = visualIndicator.calculateToDesktopRegion(displayLayout,
            splitLeftRegion, splitRightRegion, fullscreenRegion)
        var testRegion = Region()
        testRegion.union(DISPLAY_BOUNDS)
        testRegion.op(splitLeftRegion, Region.Op.DIFFERENCE)
        testRegion.op(splitRightRegion, Region.Op.DIFFERENCE)
        testRegion.op(fullscreenRegion, Region.Op.DIFFERENCE)
        assertThat(desktopRegion).isEqualTo(testRegion)
        var result = visualIndicator.updateIndicatorType(PointF(-10000f, 500f))
        assertThat(result).isEqualTo(DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_LEFT_INDICATOR)
        createVisualIndicator(DesktopModeVisualIndicator.DragStartState.FROM_SPLIT)
        result = visualIndicator.updateIndicatorType(PointF(10000f, 500f))
        assertThat(result).isEqualTo(DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_RIGHT_INDICATOR)
        createVisualIndicator(DesktopModeVisualIndicator.DragStartState.DRAGGED_INTENT)
        result = visualIndicator.updateIndicatorType(PointF(500f, 10000f))
        assertThat(result).isEqualTo(DesktopModeVisualIndicator.IndicatorType.TO_DESKTOP_INDICATOR)
        createVisualIndicator(DesktopModeVisualIndicator.DragStartState.FROM_FREEFORM)
        result = visualIndicator.updateIndicatorType(PointF(500f, 10000f))
        assertThat(result).isEqualTo(DesktopModeVisualIndicator.IndicatorType.NO_INDICATOR)
    }

    private fun createVisualIndicator(dragStartState: DesktopModeVisualIndicator.DragStartState) {
+6 −2
Original line number Diff line number Diff line
@@ -2731,13 +2731,17 @@ class DesktopTasksControllerTest : ShellTestCase() {
  @Test
  fun onDesktopDragMove_endsOutsideValidDragArea_snapsToValidBounds() {
    val task = setUpFreeformTask()
    val spyController = spy(controller)
    val mockSurface = mock(SurfaceControl::class.java)
    val mockDisplayLayout = mock(DisplayLayout::class.java)
    whenever(displayController.getDisplayLayout(task.displayId)).thenReturn(mockDisplayLayout)
    whenever(mockDisplayLayout.stableInsets()).thenReturn(Rect(0, 100, 2000, 2000))
    controller.onDragPositioningMove(task, mockSurface, 200f, Rect(100, -100, 500, 1000))
    spyController.onDragPositioningMove(task, mockSurface, 200f, Rect(100, -100, 500, 1000))

    controller.onDragPositioningEnd(
    whenever(spyController.getVisualIndicator()).thenReturn(desktopModeVisualIndicator)
    whenever(desktopModeVisualIndicator.updateIndicatorType(anyOrNull()))
      .thenReturn(DesktopModeVisualIndicator.IndicatorType.NO_INDICATOR)
    spyController.onDragPositioningEnd(
        task,
        mockSurface,
        Point(100, -100), /* position */