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

Commit 1657c81a authored by mattsziklay's avatar mattsziklay
Browse files

Update desktop gesture exclusion criteria.

Expands the gesture exclusion regions generated per task to include
caption bounds. This prevents gestures from occurring when attempting to
drag position a task from the edge of the screen.

This CL also excludes the corners from the gesture exclusion region for
non-resizeable tasks.

Bug: 296925353
Test: Manual, drag task off the edge of the screen, then drag back from
the edge without triggering gesture.

Change-Id: If6cbcd24934bf0163d226ab5d158c20610f5dde5
parent 9402275c
Loading
Loading
Loading
Loading
+21 −18
Original line number Diff line number Diff line
@@ -52,8 +52,8 @@ class DesktopModeTaskRepository {
    private val activeTasksListeners = ArraySet<ActiveTasksListener>()
    // Track visible tasks separately because a task may be part of the desktop but not visible.
    private val visibleTasksListeners = ArrayMap<VisibleTasksListener, Executor>()
    // Track corners of desktop tasks, used to determine gesture exclusion
    private val desktopCorners = SparseArray<Region>()
    // Track corner/caption regions of desktop tasks, used to determine gesture exclusion
    private val desktopExclusionRegions = SparseArray<Region>()
    private var desktopGestureExclusionListener: Consumer<Region>? = null
    private var desktopGestureExclusionExecutor: Executor? = null

@@ -96,10 +96,11 @@ class DesktopModeTaskRepository {
    }

    /**
     * Add a Consumer which will inform other classes of changes to corners for all Desktop tasks.
     * Add a Consumer which will inform other classes of changes to exclusion regions for all
     * Desktop tasks.
     */
    fun setTaskCornerListener(cornersListener: Consumer<Region>, executor: Executor) {
        desktopGestureExclusionListener = cornersListener
    fun setExclusionRegionListener(regionListener: Consumer<Region>, executor: Executor) {
        desktopGestureExclusionListener = regionListener
        desktopGestureExclusionExecutor = executor
        executor.execute {
            desktopGestureExclusionListener?.accept(calculateDesktopExclusionRegion())
@@ -107,14 +108,14 @@ class DesktopModeTaskRepository {
    }

    /**
     * Create a new merged region representative of all corners in all desktop tasks.
     * Create a new merged region representative of all exclusion regions in all desktop tasks.
     */
    private fun calculateDesktopExclusionRegion(): Region {
        val desktopCornersRegion = Region()
        desktopCorners.valueIterator().forEach { taskCorners ->
            desktopCornersRegion.op(taskCorners, Region.Op.UNION)
        val desktopExclusionRegion = Region()
        desktopExclusionRegions.valueIterator().forEach { taskExclusionRegion ->
            desktopExclusionRegion.op(taskExclusionRegion, Region.Op.UNION)
        }
        return desktopCornersRegion
        return desktopExclusionRegion
    }

    /**
@@ -294,22 +295,24 @@ class DesktopModeTaskRepository {
    }

    /**
     * Updates the active desktop corners; if desktopCorners has been accepted by
     * desktopCornersListener, it will be updated in the appropriate classes.
     * Updates the active desktop gesture exclusion regions; if desktopExclusionRegions has been
     * accepted by desktopGestureExclusionListener, it will be updated in the
     * appropriate classes.
     */
    fun updateTaskCorners(taskId: Int, taskCorners: Region) {
        desktopCorners.put(taskId, taskCorners)
    fun updateTaskExclusionRegions(taskId: Int, taskExclusionRegions: Region) {
        desktopExclusionRegions.put(taskId, taskExclusionRegions)
        desktopGestureExclusionExecutor?.execute {
            desktopGestureExclusionListener?.accept(calculateDesktopExclusionRegion())
        }
    }

    /**
     * Removes the active desktop corners for the specified task; if desktopCorners has been
     * accepted by desktopCornersListener, it will be updated in the appropriate classes.
     * Removes the desktop gesture exclusion region for the specified task; if exclusionRegion
     * has been accepted by desktopGestureExclusionListener, it will be updated in the
     * appropriate classes.
     */
    fun removeTaskCorners(taskId: Int) {
        desktopCorners.delete(taskId)
    fun removeExclusionRegion(taskId: Int) {
        desktopExclusionRegions.delete(taskId)
        desktopGestureExclusionExecutor?.execute {
            desktopGestureExclusionListener?.accept(calculateDesktopExclusionRegion())
        }
+10 −10
Original line number Diff line number Diff line
@@ -972,17 +972,17 @@ class DesktopTasksController(
    }

    /**
     * Update the corner region for a specified task
     * Update the exclusion region for a specified task
     */
    fun onTaskCornersChanged(taskId: Int, corner: Region) {
        desktopModeTaskRepository.updateTaskCorners(taskId, corner)
    fun onExclusionRegionChanged(taskId: Int, exclusionRegion: Region) {
        desktopModeTaskRepository.updateTaskExclusionRegions(taskId, exclusionRegion)
    }

    /**
     * Remove a previously tracked corner region for a specified task.
     * Remove a previously tracked exclusion region for a specified task.
     */
    fun removeCornersForTask(taskId: Int) {
        desktopModeTaskRepository.removeTaskCorners(taskId)
    fun removeExclusionRegionForTask(taskId: Int) {
        desktopModeTaskRepository.removeExclusionRegion(taskId)
    }

    /**
@@ -996,16 +996,16 @@ class DesktopTasksController(
    }

    /**
     * Adds a listener to track changes to desktop task corners
     * Adds a listener to track changes to desktop task gesture exclusion regions
     *
     * @param listener the listener to add.
     * @param callbackExecutor the executor to call the listener on.
     */
    fun setTaskCornerListener(
    fun setTaskRegionListener(
            listener: Consumer<Region>,
            callbackExecutor: Executor
    ) {
        desktopModeTaskRepository.setTaskCornerListener(listener, callbackExecutor)
        desktopModeTaskRepository.setExclusionRegionListener(listener, callbackExecutor)
    }

    private fun dump(pw: PrintWriter, prefix: String) {
@@ -1031,7 +1031,7 @@ class DesktopTasksController(
                callbackExecutor: Executor
        ) {
            mainExecutor.execute {
                this@DesktopTasksController.setTaskCornerListener(listener, callbackExecutor)
                this@DesktopTasksController.setTaskRegionListener(listener, callbackExecutor)
            }
        }
    }
+10 −10
Original line number Diff line number Diff line
@@ -21,7 +21,6 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;

import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
import static com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FINAL_FREEFORM_SCALE;
@@ -79,7 +78,7 @@ import com.android.wm.shell.sysui.KeyguardChangeListener;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration.TaskCornersListener;
import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration.ExclusionRegionListener;

import java.util.Optional;
import java.util.function.Supplier;
@@ -106,7 +105,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {

    private SparseArray<EventReceiver> mEventReceiversByDisplay = new SparseArray<>();

    private final TaskCornersListener mCornersListener = new TaskCornersListenerImpl();
    private final ExclusionRegionListener mExclusionRegionListener =
            new ExclusionRegionListenerImpl();

    private final SparseArray<DesktopModeWindowDecoration> mWindowDecorByTaskId =
            new SparseArray<>();
@@ -920,7 +920,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {

        windowDecoration.setCaptionListeners(
                touchEventListener, touchEventListener, touchEventListener);
        windowDecoration.setCornersListener(mCornersListener);
        windowDecoration.setExclusionRegionListener(mExclusionRegionListener);
        windowDecoration.setDragPositioningCallback(dragPositioningCallback);
        windowDecoration.setDragDetector(touchEventListener.mDragDetector);
        windowDecoration.relayout(taskInfo, startT, finishT,
@@ -958,17 +958,17 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
        }
    }

    private class TaskCornersListenerImpl
            implements DesktopModeWindowDecoration.TaskCornersListener {
    private class ExclusionRegionListenerImpl
            implements ExclusionRegionListener {

        @Override
        public void onTaskCornersChanged(int taskId, Region corner) {
            mDesktopTasksController.ifPresent(d -> d.onTaskCornersChanged(taskId, corner));
        public void onExclusionRegionChanged(int taskId, Region region) {
            mDesktopTasksController.ifPresent(d -> d.onExclusionRegionChanged(taskId, region));
        }

        @Override
        public void onTaskCornersRemoved(int taskId) {
            mDesktopTasksController.ifPresent(d -> d.removeCornersForTask(taskId));
        public void onExclusionRegionDismissed(int taskId) {
            mDesktopTasksController.ifPresent(d -> d.removeExclusionRegionForTask(taskId));
        }
    }

+48 −20
Original line number Diff line number Diff line
@@ -92,7 +92,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
    private Drawable mAppIcon;
    private CharSequence mAppName;

    private TaskCornersListener mCornersListener;
    private ExclusionRegionListener mExclusionRegionListener;

    private final Set<IBinder> mTransitionsPausingRelayout = new HashSet<>();
    private int mRelayoutBlock;
@@ -128,8 +128,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
        mOnCaptionLongClickListener = onLongClickListener;
    }

    void setCornersListener(TaskCornersListener cornersListener) {
        mCornersListener = cornersListener;
    void setExclusionRegionListener(ExclusionRegionListener exclusionRegionListener) {
        mExclusionRegionListener = exclusionRegionListener;
    }

    void setDragPositioningCallback(DragPositioningCallback dragPositioningCallback) {
@@ -229,6 +229,10 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
        }

        if (!isDragResizeable) {
            if (!mTaskInfo.positionInParent.equals(mPositionInParent)) {
                // We still want to track caption bar's exclusion region on a non-resizeable task.
                updateExclusionRegion();
            }
            closeDragResizeListener();
            return;
        }
@@ -256,13 +260,13 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
        final int resize_corner = mResult.mRootView.getResources()
                .getDimensionPixelSize(R.dimen.freeform_resize_corner);

        // If either task geometry or position have changed, update this task's cornersListener
        // If either task geometry or position have changed, update this task's
        // exclusion region listener
        if (mDragResizeListener.setGeometry(
                mResult.mWidth, mResult.mHeight, resize_handle, resize_corner, touchSlop)
                || !mTaskInfo.positionInParent.equals(mPositionInParent)) {
            mCornersListener.onTaskCornersChanged(mTaskInfo.taskId, getGlobalCornersRegion());
            updateExclusionRegion();
        }
        mPositionInParent.set(mTaskInfo.positionInParent);

        if (isMaximizeMenuActive()) {
            if (!mTaskInfo.isVisible()) {
@@ -282,8 +286,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin

        final int displayWidth = displayLayout.width();
        final int displayHeight = displayLayout.height();
        final int captionHeight = loadDimensionPixelSize(
                resources, R.dimen.freeform_decor_caption_height);
        final int captionHeight = getCaptionHeight();

        final ImageButton maximizeWindowButton =
                mResult.mRootView.findViewById(R.id.maximize_window);
@@ -537,7 +540,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
    public void close() {
        closeDragResizeListener();
        closeHandleMenu();
        mCornersListener.onTaskCornersRemoved(mTaskInfo.taskId);
        mExclusionRegionListener.onExclusionRegionDismissed(mTaskInfo.taskId);
        disposeResizeVeil();
        super.close();
    }
@@ -548,13 +551,32 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
                : R.layout.desktop_mode_focused_window_decor;
    }

    private void updatePositionInParent() {
        mPositionInParent.set(mTaskInfo.positionInParent);
    }

    private void updateExclusionRegion() {
        // An outdated position in parent is one reason for this to be called; update it here.
        updatePositionInParent();
        mExclusionRegionListener
                .onExclusionRegionChanged(mTaskInfo.taskId, getGlobalExclusionRegion());
    }

    /**
     * Create a new region out of the corner rects of this task.
     * Create a new exclusion region from the corner rects (if resizeable) and caption bounds
     * of this task.
     */
    Region getGlobalCornersRegion() {
        Region cornersRegion = mDragResizeListener.getCornersRegion();
        cornersRegion.translate(mPositionInParent.x, mPositionInParent.y);
        return cornersRegion;
    private Region getGlobalExclusionRegion() {
        Region exclusionRegion;
        if (mTaskInfo.isResizeable) {
            exclusionRegion = mDragResizeListener.getCornersRegion();
        } else {
            exclusionRegion = new Region();
        }
        exclusionRegion.union(new Rect(0, 0, mResult.mWidth,
                getCaptionHeight()));
        exclusionRegion.translate(mPositionInParent.x, mPositionInParent.y);
        return exclusionRegion;
    }

    /**
@@ -572,6 +594,10 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
        return R.dimen.freeform_decor_caption_height;
    }

    private int getCaptionHeight() {
        return loadDimensionPixelSize(mContext.getResources(), getCaptionHeightId());
    }

    /**
     * Add transition to mTransitionsPausingRelayout
     */
@@ -626,12 +652,14 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
        }
    }

    interface TaskCornersListener {
        /** Inform the implementing class of this task's change in corner resize handles */
        void onTaskCornersChanged(int taskId, Region corner);
    interface ExclusionRegionListener {
        /** Inform the implementing class of this task's change in region resize handles */
        void onExclusionRegionChanged(int taskId, Region region);

        /** Inform the implementing class that this task no longer needs its corners tracked,
         * likely due to it closing. */
        void onTaskCornersRemoved(int taskId);
        /**
         * Inform the implementing class that this task no longer needs an exclusion region,
         * likely due to it closing.
         */
        void onExclusionRegionDismissed(int taskId);
    }
}