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

Commit 082f0faa authored by mattsziklay's avatar mattsziklay
Browse files

Add HANDLE_OUTSIDE_TOUCH flag to decor menus.

Adds the flag HANDLE_OUTSIDE_TOUCH to maximize menu and handle menu and
uses the available ACTION_OUTSIDE event to close menus on external
touch, reducing the need for the global InputMonitor.

Additionally, adds a touch listener to the maximize menu root view to
support listening for outside touches.

Bug: 349135068
Test: Manual, outside touches still work in both menus with and without
the additional windows above status bar flag.
Flag: EXEMPT refactor

Change-Id: I8e4a6f8e9571fa3d64e9d3c95074e306c747ea0f
parent 5d1dd879
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/handle_menu"
    android:layout_width="@dimen/desktop_mode_handle_menu_width"
    android:layout_height="wrap_content"
    android:clipChildren="false"
+13 −14
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_HOVER_ENTER;
import static android.view.MotionEvent.ACTION_HOVER_EXIT;
import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_OUTSIDE;
import static android.view.MotionEvent.ACTION_UP;
import static android.view.WindowInsets.Type.statusBars;

@@ -502,8 +503,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
                if (!decoration.isHandleMenuActive()) {
                    moveTaskToFront(decoration.mTaskInfo);
                    decoration.createHandleMenu(mSplitScreenController);
                } else {
                    decoration.closeHandleMenu();
                }
            } else if (id == R.id.desktop_button) {
                final WindowContainerTransaction wct = new WindowContainerTransaction();
@@ -549,6 +548,17 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
        @Override
        public boolean onTouch(View v, MotionEvent e) {
            final int id = v.getId();
            final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId);
            if (e.getActionMasked() == ACTION_OUTSIDE) {
                if (id == R.id.handle_menu) {
                    // Close handle menu on outside touch if menu is directly touchable; if not,
                    // it will be handled by handleEventOutsideCaption.
                    if (decoration.mTaskInfo.isFreeform()
                            || Flags.enableAdditionalWindowsAboveStatusBar()) {
                        decoration.closeHandleMenu();
                    }
                }
            }
            if ((e.getSource() & SOURCE_TOUCHSCREEN) == SOURCE_TOUCHSCREEN) {
                mTouchscreenInUse = e.getActionMasked() != ACTION_UP
                        && e.getActionMasked() != ACTION_CANCEL;
@@ -558,7 +568,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
                    && id != R.id.maximize_window) {
                return false;
            }
            final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(mTaskId);
            moveTaskToFront(decoration.mTaskInfo);

            final int actionMasked = e.getActionMasked();
@@ -587,7 +596,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
                mShouldPilferCaptionEvents = !(downInCustomizableCaptionRegion
                        && downInExclusionRegion && isTransparentCaption) && !isResizeEvent;
            }

            if (!mShouldPilferCaptionEvents) {
                // The event will be handled by a window below or pilfered by resize handler.
                return false;
@@ -601,9 +609,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
                // Gesture is finished, reset state.
                mShouldPilferCaptionEvents = false;
            }
            if (!mHasLongClicked && id != R.id.maximize_window) {
                decoration.closeMaximizeMenuIfNeeded(e);
            }
            return mDragDetector.onMotionEvent(v, e);
        }

@@ -896,10 +901,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
     *
     * @param relevantDecor the window decoration of the focused task's caption. This method only
     *                      handles motion events outside this caption's bounds.
     * TODO(b/349135068): Outside-touch detection no longer works with the
     *  enableAdditionalWindowsAboveStatusBar flag enabled. This
     *  will be fixed once we can add FLAG_WATCH_OUTSIDE_TOUCH to relevant menus,
     *  at which point, all EventReceivers and external touch logic should be removed.
     */
    private void handleEventOutsideCaption(MotionEvent ev,
            DesktopModeWindowDecoration relevantDecor) {
@@ -910,9 +911,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
        relevantDecor.updateHoverAndPressStatus(ev);
        final int action = ev.getActionMasked();
        if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
            if (!mTransitionDragActive) {
            if (!mTransitionDragActive && !Flags.enableAdditionalWindowsAboveStatusBar()) {
                relevantDecor.closeHandleMenuIfNeeded(ev);
                relevantDecor.closeMaximizeMenuIfNeeded(ev);
            }
        }
    }
@@ -1250,7 +1250,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
        }
    }


    private class DragStartListenerImpl
            implements DragPositioningCallbackUtility.DragStartListener {
        @Override
+11 −2
Original line number Diff line number Diff line
@@ -904,6 +904,10 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
                    mIsMaximizeMenuHovered = hovered;
                    onMaximizeHoverStateChanged();
                    return null;
                },
                () -> {
                    closeMaximizeMenu();
                    return null;
                }
        );
    }
@@ -1114,10 +1118,15 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
            handle.performClick();
        }
        if (isHandleMenuActive()) {
            // If the whole handle menu can be touched directly, rely on FLAG_WATCH_OUTSIDE_TOUCH.
            // This is for the case that some of the handle menu is underneath the status bar.
            if (isAppHandle(mWindowDecorViewHolder)
                    && !Flags.enableAdditionalWindowsAboveStatusBar()) {
                mHandleMenu.checkMotionEvent(ev);
                closeHandleMenuIfNeeded(ev);
            }
        }
    }

    /**
     * Updates hover and pressed status of views in this decoration. Should only be called
+4 −1
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import android.net.Uri
import android.view.MotionEvent
import android.view.SurfaceControl
import android.view.View
import android.view.WindowManager
import android.widget.Button
import android.widget.ImageButton
import android.widget.ImageView
@@ -140,7 +141,9 @@ class HandleMenu(
                    x = x,
                    y = y,
                    width = menuWidth,
                    height = menuHeight
                    height = menuHeight,
                    flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
                        WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
                )
            } else {
                parentDecor.addWindow(
+19 −4
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ import android.view.MotionEvent
import android.view.MotionEvent.ACTION_HOVER_ENTER
import android.view.MotionEvent.ACTION_HOVER_EXIT
import android.view.MotionEvent.ACTION_HOVER_MOVE
import android.view.MotionEvent.ACTION_OUTSIDE
import android.view.SurfaceControl
import android.view.SurfaceControl.Transaction
import android.view.SurfaceControlViewHost
@@ -104,14 +105,16 @@ class MaximizeMenu(
        onMaximizeClickListener: OnTaskActionClickListener,
        onLeftSnapClickListener: OnTaskActionClickListener,
        onRightSnapClickListener: OnTaskActionClickListener,
        onHoverListener: (Boolean) -> Unit
        onHoverListener: (Boolean) -> Unit,
        onOutsideTouchListener: () -> Unit,
    ) {
        if (maximizeMenu != null) return
        createMaximizeMenu(
            onMaximizeClickListener = onMaximizeClickListener,
            onLeftSnapClickListener = onLeftSnapClickListener,
            onRightSnapClickListener = onRightSnapClickListener,
            onHoverListener = onHoverListener
            onHoverListener = onHoverListener,
            onOutsideTouchListener = onOutsideTouchListener
        )
        maximizeMenuView?.animateOpenMenu()
    }
@@ -129,7 +132,8 @@ class MaximizeMenu(
        onMaximizeClickListener: OnTaskActionClickListener,
        onLeftSnapClickListener: OnTaskActionClickListener,
        onRightSnapClickListener: OnTaskActionClickListener,
        onHoverListener: (Boolean) -> Unit
        onHoverListener: (Boolean) -> Unit,
        onOutsideTouchListener: () -> Unit
    ) {
        val t = transactionSupplier.get()
        val builder = SurfaceControl.Builder()
@@ -142,7 +146,8 @@ class MaximizeMenu(
                menuWidth,
                menuHeight,
                WindowManager.LayoutParams.TYPE_APPLICATION,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                        or WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
                PixelFormat.TRANSPARENT
        )
        lp.title = "Maximize Menu for Task=" + taskInfo.taskId
@@ -172,6 +177,7 @@ class MaximizeMenu(
                onRightSnapClickListener.onClick(taskId, "right_snap_option")
            }
            menuView.onMenuHoverListener = onHoverListener
            menuView.onOutsideTouchListener = onOutsideTouchListener
            viewHost.setView(menuView.rootView, lp)
        }

@@ -268,6 +274,8 @@ class MaximizeMenu(
        var onRightSnapClickListener: (() -> Unit)? = null
        /** Invoked whenever the hover state of the menu changes. */
        var onMenuHoverListener: ((Boolean) -> Unit)? = null
        /** Invoked whenever a click occurs outside the menu */
        var onOutsideTouchListener: (() -> Unit)? = null

        init {
            overlay.setOnHoverListener { _, event ->
@@ -312,6 +320,13 @@ class MaximizeMenu(
            maximizeButton.setOnClickListener { onMaximizeClickListener?.invoke() }
            snapRightButton.setOnClickListener { onRightSnapClickListener?.invoke() }
            snapLeftButton.setOnClickListener { onLeftSnapClickListener?.invoke() }
            rootView.setOnTouchListener { _, event ->
                if (event.actionMasked == ACTION_OUTSIDE) {
                    onOutsideTouchListener?.invoke()
                    false
                }
                true
            }

            // To prevent aliasing.
            maximizeButton.setLayerType(View.LAYER_TYPE_SOFTWARE, null)
Loading