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

Commit 52d5f9cc authored by Maryam Dehaini's avatar Maryam Dehaini
Browse files

Use onTouchListener to listen for long press on maximize window button

Currently, an onLongPressListener is being used in order to check if a
user long presses the maximize menu button. The issue with this approach
is that we cannot drag the window from the maximize button. So, if a
window is small or is positioned so that only the right edge of the
caption is visible, it would be very hard for the user to drag the task
without accidentally maximizing or opening the maximize window.

In this approach, we use the onTouchListener instead to check if there
is a long press. This way, we can allow the user to drag the task around
if they begin a drag from the maximize menu button and redirect the
touch to the onClickListener or onTouchListener depending on how long
they are holding the button if the task is not dragged.

Bug: 298267890
Test: Drag a task using maximize menu button

Change-Id: I96eaba90b137f65cf201654433a0d12ed6fe69bb
parent ab6db579
Loading
Loading
Loading
Loading
+29 −12
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@ import android.view.MotionEvent;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.WindowManager;
import android.window.TransitionInfo;
import android.window.WindowContainerToken;
@@ -371,6 +372,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
        private final GestureDetector mGestureDetector;

        private boolean mIsDragging;
        private boolean mHasLongClicked;
        private boolean mShouldClick;
        private int mDragPointerId = -1;

@@ -394,11 +396,9 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
                    RunningTaskInfo remainingTask = getOtherSplitTask(mTaskId);
                    mSplitScreenController.moveTaskToFullscreen(remainingTask.taskId);
                }
                decoration.closeMaximizeMenu();
            } else if (id == R.id.back_button) {
                mTaskOperations.injectBackKey();
            } else if (id == R.id.caption_handle || id == R.id.open_menu_button) {
                decoration.closeMaximizeMenu();
                if (!decoration.isHandleMenuActive()) {
                    moveTaskToFront(mTaskOrganizer.getRunningTaskInfo(mTaskId));
                    decoration.createHandleMenu();
@@ -433,7 +433,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
                    mDesktopTasksController.ifPresent(c -> c.moveToNextDisplay(mTaskId));
                }
            } else if (id == R.id.maximize_window) {
                moveTaskToFront(decoration.mTaskInfo);
                if (decoration.isMaximizeMenuActive()) {
                    decoration.closeMaximizeMenu();
                    return;
@@ -467,10 +466,26 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
        public boolean onTouch(View v, MotionEvent e) {
            final int id = v.getId();
            if (id != R.id.caption_handle && id != R.id.desktop_mode_caption
                    && id != R.id.open_menu_button && id != R.id.close_window) {
                    && id != R.id.open_menu_button && id != R.id.close_window
                    && id != R.id.maximize_window) {
                return false;
            }
            moveTaskToFront(mTaskOrganizer.getRunningTaskInfo(mTaskId));

            if (!mHasLongClicked) {
                final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId);
                decoration.closeMaximizeMenu();
            }

            final long eventDuration = e.getEventTime() - e.getDownTime();
            final boolean shouldLongClick = id == R.id.maximize_window && !mIsDragging
                    && !mHasLongClicked && eventDuration >= ViewConfiguration.getLongPressTimeout();
            if (shouldLongClick) {
                v.performLongClick();
                mHasLongClicked = true;
                return true;
            }

            return mDragDetector.onMotionEvent(v, e);
        }

@@ -483,7 +498,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
                if (decoration.isMaximizeMenuActive()) {
                    decoration.closeMaximizeMenu();
                } else {
                    decoration.closeHandleMenu();
                    decoration.createMaximizeMenu();
                }
                return true;
@@ -519,11 +533,13 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
                            e.getRawY(0));
                    mIsDragging = false;
                    mShouldClick = true;
                    mHasLongClicked = false;
                    return true;
                }
                case MotionEvent.ACTION_MOVE: {
                    final DesktopModeWindowDecoration decoration =
                            mWindowDecorByTaskId.get(mTaskId);
                    decoration.closeMaximizeMenu();
                    if (e.findPointerIndex(mDragPointerId) == -1) {
                        mDragPointerId = e.getPointerId(0);
                    }
@@ -542,7 +558,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
                case MotionEvent.ACTION_CANCEL: {
                    final boolean wasDragging = mIsDragging;
                    if (!wasDragging) {
                        if (mShouldClick && v != null) {
                        if (mShouldClick && v != null && !mHasLongClicked) {
                            v.performClick();
                            mShouldClick = false;
                            return true;
@@ -685,14 +701,16 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
    // If an UP/CANCEL action is received outside of caption bounds, turn off handle menu
    private void handleEventOutsideFocusedCaption(MotionEvent ev,
            DesktopModeWindowDecoration relevantDecor) {
        final int action = ev.getActionMasked();
        if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
            if (relevantDecor == null) {
        // Returns if event occurs within caption
        if (relevantDecor == null || relevantDecor.checkTouchEventInCaption(ev)) {
            return;
        }

        final int action = ev.getActionMasked();
        if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
            if (!mTransitionDragActive) {
                relevantDecor.closeHandleMenuIfNeeded(ev);
                relevantDecor.closeMaximizeMenuIfNeeded(ev);
            }
        }
    }
@@ -1024,7 +1042,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
        public void onDragStart(int taskId) {
            final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskId);
            decoration.closeHandleMenu();
            decoration.closeMaximizeMenu();
        }
    }

+22 −0
Original line number Diff line number Diff line
@@ -521,6 +521,20 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
        }
    }

    /**
     * Close an open maximize menu if input is outside of menu coordinates
     *
     * @param ev the tapped point to compare against
     */
    void closeMaximizeMenuIfNeeded(MotionEvent ev) {
        if (!isMaximizeMenuActive()) return;

        final PointF inputPoint = offsetCaptionLocation(ev);
        if (!mMaximizeMenu.isValidMenuInput(inputPoint)) {
            closeMaximizeMenu();
        }
    }

    boolean isFocused() {
        return mTaskInfo.isFocused;
    }
@@ -559,6 +573,13 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
        return checkEventInCaptionView(ev, R.id.caption_handle);
    }

    /**
     * Returns true if motion event is within the caption's root view's bounds.
     */
    boolean checkTouchEventInCaption(MotionEvent ev) {
        return checkEventInCaptionView(ev, getCaptionViewId());
    }

    /**
     * Check a passed MotionEvent if a click has occurred on any button on this caption
     * Note this should only be called when a regular onClick is not possible
@@ -574,6 +595,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
            clickIfPointInView(new PointF(ev.getX(), ev.getY()), handle);
        } else {
            mHandleMenu.checkClickEvent(ev);
            closeHandleMenuIfNeeded(ev);
        }
    }

+25 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.view.LayoutInflater
import android.view.SurfaceControl
import android.view.SurfaceControl.Transaction
import android.view.SurfaceControlViewHost
import android.view.View
import android.view.View.OnClickListener
import android.view.WindowManager
import android.view.WindowlessWindowManager
@@ -151,4 +152,28 @@ class MaximizeMenu(
                R.id.maximize_menu_snap_left_button
        ).setOnClickListener(onClickListener)
    }

    /**
     * A valid menu input is one of the following:
     * An input that happens in the menu views.
     * Any input before the views have been laid out.
     *
     * @param inputPoint the input to compare against.
     */
    fun isValidMenuInput(inputPoint: PointF): Boolean {
        val menuView = maximizeMenu?.mWindowViewHost?.view ?: return true
        return !viewsLaidOut() || pointInView(menuView, inputPoint.x - menuPosition.x,
                inputPoint.y - menuPosition.y)
    }

    private fun pointInView(v: View, x: Float, y: Float): Boolean {
        return v.left <= x && v.right >= x && v.top <= y && v.bottom >= y
    }

    /**
     * Check if the views for maximize menu can be seen.
     */
    private fun viewsLaidOut(): Boolean {
        return maximizeMenu?.mWindowViewHost?.view?.isLaidOut ?: false
    }
}
+1 −0
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ internal class DesktopModeAppControlsWindowDecorationViewHolder(
        openMenuButton.setOnTouchListener(onCaptionTouchListener)
        closeWindowButton.setOnClickListener(onCaptionButtonClickListener)
        maximizeWindowButton.setOnClickListener(onCaptionButtonClickListener)
        maximizeWindowButton.setOnTouchListener(onCaptionTouchListener)
        maximizeWindowButton.onLongClickListener = onLongClickListener
        closeWindowButton.setOnTouchListener(onCaptionTouchListener)
        appNameTextView.text = appName