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

Commit d8ceb855 authored by Chong Zhang's avatar Chong Zhang
Browse files

Fixes for touch exclusion region

- Evaluate touch exclusion region on per-task basis, instead of per
  window. Smallest unit for exclusion is Task, if task has more than
  one app window, we still need to use the visible area of the task
  to do focus transfer properly.

- Only add back the touch region for focused task after all tasks
  are processed for eclusion, otherwise the focused area could be
  removed from exclusion incorrectly.

- Skip app windows that's exiting or hidden.

bug: 25494928

Change-Id: I972ba2149431557e7420b1095d9496a6cd821bdb
parent c6a2da07
Loading
Loading
Loading
Loading
+55 −48
Original line number Original line Diff line number Diff line
@@ -291,27 +291,29 @@ class DisplayContent {
            final ArrayList<Task> tasks = mStacks.get(stackNdx).getTasks();
            final ArrayList<Task> tasks = mStacks.get(stackNdx).getTasks();
            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
                final Task task = tasks.get(taskNdx);
                final Task task = tasks.get(taskNdx);
                // We need to use the visible frame on the window for any touch-related tests.
                final WindowState win = task.getTopVisibleAppMainWindow();
                // Can't use the task's bounds because the original task bounds might be adjusted
                if (win == null) {
                // to fit the content frame. For example, the presence of the IME adjusting the
                    continue;
                }
                // We need to use the task's dim bounds (which is derived from the visible
                // bounds of its apps windows) for any touch-related tests. Can't use
                // the task's original bounds because it might be adjusted to fit the
                // content frame. For example, the presence of the IME adjusting the
                // windows frames when the app window is the IME target.
                // windows frames when the app window is the IME target.
                final WindowState win = task.getTopAppMainWindow();
                task.getDimBounds(mTmpRect);
                if (win != null) {
                    win.getVisibleBounds(mTmpRect);
                if (mTmpRect.contains(x, y)) {
                if (mTmpRect.contains(x, y)) {
                    return task.mTaskId;
                    return task.mTaskId;
                }
                }
            }
            }
        }
        }
        }
        return -1;
        return -1;
    }
    }


    /**
    /**
     * Find the window whose outside touch area (for resizing) (x, y) falls within.
     * Find the task whose outside touch area (for resizing) (x, y) falls within.
     * Returns null if the touch doesn't fall into a resizing area.
     * Returns null if the touch doesn't fall into a resizing area.
     */
     */
    WindowState findWindowForControlPoint(int x, int y) {
    Task findTaskForControlPoint(int x, int y) {
        final int delta = mService.dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics);
        final int delta = mService.dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics);
        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
            TaskStack stack = mStacks.get(stackNdx);
            TaskStack stack = mStacks.get(stackNdx);
@@ -325,19 +327,18 @@ class DisplayContent {
                    return null;
                    return null;
                }
                }


                // We need to use the visible frame on the window for any touch-related
                // We need to use the task's dim bounds (which is derived from the visible
                // tests. Can't use the task's bounds because the original task bounds
                // bounds of its apps windows) for any touch-related tests. Can't use
                // might be adjusted to fit the content frame. (One example is when the
                // the task's original bounds because it might be adjusted to fit the
                // task is put to top-left quadrant, the actual visible frame would not
                // content frame. One example is when the task is put to top-left quadrant,
                // start at (0,0) after it's adjusted for the status bar.)
                // the actual visible area would not start at (0,0) after it's adjusted
                final WindowState win = task.getTopAppMainWindow();
                // for the status bar.
                if (win != null) {
                task.getDimBounds(mTmpRect);
                    win.getVisibleBounds(mTmpRect);
                mTmpRect.inset(-delta, -delta);
                mTmpRect.inset(-delta, -delta);
                if (mTmpRect.contains(x, y)) {
                if (mTmpRect.contains(x, y)) {
                    mTmpRect.inset(delta, delta);
                    mTmpRect.inset(delta, delta);
                    if (!mTmpRect.contains(x, y)) {
                    if (!mTmpRect.contains(x, y)) {
                            return win;
                        return task;
                    }
                    }
                    // User touched inside the task. No need to look further,
                    // User touched inside the task. No need to look further,
                    // focus transfer will be handled in ACTION_UP.
                    // focus transfer will be handled in ACTION_UP.
@@ -345,18 +346,23 @@ class DisplayContent {
                }
                }
            }
            }
        }
        }
        }
        return null;
        return null;
    }
    }


    void setTouchExcludeRegion(Task focusedTask) {
    void setTouchExcludeRegion(Task focusedTask) {
        mTouchExcludeRegion.set(mBaseDisplayRect);
        mTouchExcludeRegion.set(mBaseDisplayRect);
        WindowList windows = getWindowList();
        final int delta = mService.dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics);
        final int delta = mService.dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics);
        for (int i = windows.size() - 1; i >= 0; --i) {
        boolean addBackFocusedTask = false;
            final WindowState win = windows.get(i);
        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
            final Task task = win.getTask();
            TaskStack stack = mStacks.get(stackNdx);
            if (win.isVisibleLw() && task != null) {
            final ArrayList<Task> tasks = stack.getTasks();
            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
                final Task task = tasks.get(taskNdx);
                final WindowState win = task.getTopVisibleAppMainWindow();
                if (win == null) {
                    continue;
                }

                /**
                /**
                 * Exclusion region is the region that TapDetector doesn't care about.
                 * Exclusion region is the region that TapDetector doesn't care about.
                 * Here we want to remove all non-focused tasks from the exclusion region.
                 * Here we want to remove all non-focused tasks from the exclusion region.
@@ -368,13 +374,17 @@ class DisplayContent {
                 */
                 */
                final boolean isFreeformed = task.inFreeformWorkspace();
                final boolean isFreeformed = task.inFreeformWorkspace();
                if (task != focusedTask || isFreeformed) {
                if (task != focusedTask || isFreeformed) {
                    mTmpRect.set(win.mVisibleFrame);
                    task.getDimBounds(mTmpRect);
                    mTmpRect.intersect(win.mVisibleInsets);
                    /**
                     * If the task is freeformed, enlarge the area to account for outside
                     * touch area for resize.
                     */
                    if (isFreeformed) {
                    if (isFreeformed) {
                        // If we're removing a freeform, focused app from the exclusion region,
                        // we need to add back its touchable frame later. Remember the touchable
                        // frame now.
                        if (task == focusedTask) {
                            addBackFocusedTask = true;
                            mTmpRect2.set(mTmpRect);
                        }
                        // If the task is freeformed, enlarge the area to account for outside
                        // touch area for resize.
                        mTmpRect.inset(-delta, -delta);
                        mTmpRect.inset(-delta, -delta);
                        // Intersect with display content rect. If we have system decor (status bar/
                        // Intersect with display content rect. If we have system decor (status bar/
                        // navigation bar), we want to exclude that from the tap detection.
                        // navigation bar), we want to exclude that from the tap detection.
@@ -385,16 +395,13 @@ class DisplayContent {
                    }
                    }
                    mTouchExcludeRegion.op(mTmpRect, Region.Op.DIFFERENCE);
                    mTouchExcludeRegion.op(mTmpRect, Region.Op.DIFFERENCE);
                }
                }
                /**
                 * If we removed the focused task above, add it back and only leave its
                 * outside touch area in the exclusion. TapDectector is not interested in
                 * any touch inside the focused task itself.
                 */
                if (task == focusedTask && isFreeformed) {
                    mTmpRect.inset(delta, delta);
                    mTouchExcludeRegion.op(mTmpRect, Region.Op.UNION);
            }
            }
        }
        }
        // If we removed the focused task above, add it back and only leave its
        // outside touch area in the exclusion. TapDectector is not interested in
        // any touch inside the focused task itself.
        if (addBackFocusedTask) {
            mTouchExcludeRegion.op(mTmpRect2, Region.Op.UNION);
        }
        }
        if (mTapDetector != null) {
        if (mTapDetector != null) {
            mTapDetector.setTouchExcludeRegion(mTouchExcludeRegion);
            mTapDetector.setTouchExcludeRegion(mTouchExcludeRegion);
+18 −7
Original line number Original line Diff line number Diff line
@@ -284,7 +284,12 @@ class Task implements DimLayer.DimLayerUser {
    boolean getMaxVisibleBounds(Rect out) {
    boolean getMaxVisibleBounds(Rect out) {
        boolean foundTop = false;
        boolean foundTop = false;
        for (int i = mAppTokens.size() - 1; i >= 0; i--) {
        for (int i = mAppTokens.size() - 1; i >= 0; i--) {
            final WindowState win = mAppTokens.get(i).findMainWindow();
            final AppWindowToken token = mAppTokens.get(i);
            // skip hidden (or about to hide) apps
            if (token.mIsExiting || token.clientHidden || token.hiddenRequested) {
                continue;
            }
            final WindowState win = token.findMainWindow();
            if (win == null) {
            if (win == null) {
                continue;
                continue;
            }
            }
@@ -413,14 +418,20 @@ class Task implements DimLayer.DimLayerUser {
        return mStack != null && mStack.mStackId == DOCKED_STACK_ID;
        return mStack != null && mStack.mStackId == DOCKED_STACK_ID;
    }
    }


    WindowState getTopAppMainWindow() {
    WindowState getTopVisibleAppMainWindow() {
        final int tokensCount = mAppTokens.size();
        final AppWindowToken token = getTopVisibleAppToken();
        return tokensCount > 0 ? mAppTokens.get(tokensCount - 1).findMainWindow() : null;
        return token != null ? token.findMainWindow() : null;
    }
    }


    AppWindowToken getTopAppWindowToken() {
    AppWindowToken getTopVisibleAppToken() {
        final int tokensCount = mAppTokens.size();
        for (int i = mAppTokens.size() - 1; i >= 0; i--) {
        return tokensCount > 0 ? mAppTokens.get(tokensCount - 1) : null;
            final AppWindowToken token = mAppTokens.get(i);
            // skip hidden (or about to hide) apps
            if (!token.mIsExiting && !token.clientHidden && !token.hiddenRequested) {
                return token;
            }
        }
        return null;
    }
    }


    @Override
    @Override
+16 −12
Original line number Original line Diff line number Diff line
@@ -332,30 +332,34 @@ class TaskPositioner implements DimLayer.DimLayerUser {
                + ", {" + startX + ", " + startY + "}");
                + ", {" + startX + ", " + startY + "}");
        }
        }
        mCtrlType = CTRL_NONE;
        mCtrlType = CTRL_NONE;
        mTask = win.getTask();
        mStartDragX = startX;
        mStartDragY = startY;

        // Use the dim bounds, not the original task bounds. The cursor
        // movement should be calculated relative to the visible bounds.
        // Also, use the dim bounds of the task which accounts for
        // multiple app windows. Don't use any bounds from win itself as it
        // may not be the same size as the task.
        mTask.getDimBounds(mTmpRect);

        if (resize) {
        if (resize) {
            final Rect visibleFrame = win.mVisibleFrame;
            if (startX < mTmpRect.left) {
            if (startX < visibleFrame.left) {
                mCtrlType |= CTRL_LEFT;
                mCtrlType |= CTRL_LEFT;
            }
            }
            if (startX > visibleFrame.right) {
            if (startX > mTmpRect.right) {
                mCtrlType |= CTRL_RIGHT;
                mCtrlType |= CTRL_RIGHT;
            }
            }
            if (startY < visibleFrame.top) {
            if (startY < mTmpRect.top) {
                mCtrlType |= CTRL_TOP;
                mCtrlType |= CTRL_TOP;
            }
            }
            if (startY > visibleFrame.bottom) {
            if (startY > mTmpRect.bottom) {
                mCtrlType |= CTRL_BOTTOM;
                mCtrlType |= CTRL_BOTTOM;
            }
            }
            mResizing = true;
            mResizing = true;
        }
        }


        mTask = win.getTask();
        mWindowOriginalBounds.set(mTmpRect);
        mStartDragX = startX;
        mStartDragY = startY;

        // Use the visible bounds, not the original task bounds. The cursor
        // movement should be calculated relative to the visible bounds.
        mWindowOriginalBounds.set(win.mVisibleFrame);
    }
    }


    private void endDragLocked() {
    private void endDragLocked() {
+3 −3
Original line number Original line Diff line number Diff line
@@ -90,11 +90,11 @@ public class TaskTapPointerEventListener implements PointerEventListener {
            case MotionEvent.ACTION_HOVER_MOVE: {
            case MotionEvent.ACTION_HOVER_MOVE: {
                final int x = (int) motionEvent.getX();
                final int x = (int) motionEvent.getX();
                final int y = (int) motionEvent.getY();
                final int y = (int) motionEvent.getY();
                final WindowState window = mDisplayContent.findWindowForControlPoint(x, y);
                final Task task = mDisplayContent.findTaskForControlPoint(x, y);
                if (window == null) {
                if (task == null) {
                    break;
                    break;
                }
                }
                window.getVisibleBounds(mTmpRect);
                task.getDimBounds(mTmpRect);
                if (!mTmpRect.isEmpty() && !mTmpRect.contains(x, y)) {
                if (!mTmpRect.isEmpty() && !mTmpRect.contains(x, y)) {
                    int iconShape = STYLE_DEFAULT;
                    int iconShape = STYLE_DEFAULT;
                    if (x < mTmpRect.left) {
                    if (x < mTmpRect.left) {
+5 −4
Original line number Original line Diff line number Diff line
@@ -7069,15 +7069,16 @@ public class WindowManagerService extends IWindowManager.Stub
    }
    }


    private void startResizingTask(DisplayContent displayContent, int startX, int startY) {
    private void startResizingTask(DisplayContent displayContent, int startX, int startY) {
        WindowState win = null;
        Task task = null;
        synchronized (mWindowMap) {
        synchronized (mWindowMap) {
            win = displayContent.findWindowForControlPoint(startX, startY);
            task = displayContent.findTaskForControlPoint(startX, startY);
            if (win == null || !startPositioningLocked(win, true /*resize*/, startX, startY)) {
            if (task == null || !startPositioningLocked(
                    task.getTopVisibleAppMainWindow(), true /*resize*/, startX, startY)) {
                return;
                return;
            }
            }
        }
        }
        try {
        try {
            mActivityManager.setFocusedTask(win.getTask().mTaskId);
            mActivityManager.setFocusedTask(task.mTaskId);
        } catch(RemoteException e) {}
        } catch(RemoteException e) {}
    }
    }


Loading