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

Commit b1063793 authored by Adrian Roos's avatar Adrian Roos
Browse files

GestureNav: Fix broken exclusion rect calculation for modal windows

Fixes an issue with non-fullscreen modal windows (such as dialogs), where the touch exclusion of
the window behind was still being applied, even though the window behind did not actually
receive the touches in the exclusion, because they would go to the modal window in front.

Bug: 135522625
Test: atest testCalculateSystemGestureExclusion_modal
Change-Id: Ia99f4f601e780715abaf966f6f297fd9d555fd0b
parent 8ef731c2
Loading
Loading
Loading
Loading
+2 −4
Original line number Original line Diff line number Diff line
@@ -5142,7 +5142,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
        final int[] remainingLeftRight =
        final int[] remainingLeftRight =
                {mSystemGestureExclusionLimit, mSystemGestureExclusionLimit};
                {mSystemGestureExclusionLimit, mSystemGestureExclusionLimit};


        // Traverse all windows bottom up to assemble the gesture exclusion rects.
        // Traverse all windows top down to assemble the gesture exclusion rects.
        // For each window, we only take the rects that fall within its touchable region.
        // For each window, we only take the rects that fall within its touchable region.
        forAllWindows(w -> {
        forAllWindows(w -> {
            if (w.cantReceiveTouchInput() || !w.isVisible()
            if (w.cantReceiveTouchInput() || !w.isVisible()
@@ -5150,12 +5150,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo
                    || unhandled.isEmpty()) {
                    || unhandled.isEmpty()) {
                return;
                return;
            }
            }
            final boolean modal =
                    (w.mAttrs.flags & (FLAG_NOT_TOUCH_MODAL | FLAG_NOT_FOCUSABLE)) == 0;


            // Get the touchable region of the window, and intersect with where the screen is still
            // Get the touchable region of the window, and intersect with where the screen is still
            // touchable, i.e. touchable regions on top are not covering it yet.
            // touchable, i.e. touchable regions on top are not covering it yet.
            w.getTouchableRegion(touchableRegion);
            w.getEffectiveTouchableRegion(touchableRegion);
            touchableRegion.op(unhandled, Op.INTERSECT);
            touchableRegion.op(unhandled, Op.INTERSECT);


            if (w.isImplicitlyExcludingAllSystemGestures()) {
            if (w.isImplicitlyExcludingAllSystemGestures()) {
+19 −0
Original line number Original line Diff line number Diff line
@@ -3011,6 +3011,25 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP
        subtractTouchExcludeRegionIfNeeded(outRegion);
        subtractTouchExcludeRegionIfNeeded(outRegion);
    }
    }


    /**
     * Get the effective touchable region in global coordinates.
     *
     * In contrast to {@link #getTouchableRegion}, this takes into account
     * {@link WindowManager.LayoutParams#FLAG_NOT_TOUCH_MODAL touch modality.}
     */
    void getEffectiveTouchableRegion(Region outRegion) {
        final boolean modal = (mAttrs.flags & (FLAG_NOT_TOUCH_MODAL | FLAG_NOT_FOCUSABLE)) == 0;
        final DisplayContent dc = getDisplayContent();

        if (modal && dc != null) {
            outRegion.set(dc.getBounds());
            cropRegionToStackBoundsIfNeeded(outRegion);
            subtractTouchExcludeRegionIfNeeded(outRegion);
        } else {
            getTouchableRegion(outRegion);
        }
    }

    private void setTouchableRegionCropIfNeeded(InputWindowHandle handle) {
    private void setTouchableRegionCropIfNeeded(InputWindowHandle handle) {
        final Task task = getTask();
        final Task task = getTask();
        if (task == null || !task.cropWindowsToStackBounds()) {
        if (task == null || !task.cropWindowsToStackBounds()) {
+24 −0
Original line number Original line Diff line number Diff line
@@ -793,6 +793,30 @@ public class DisplayContentTests extends WindowTestsBase {
        assertEquals(expected, dc.calculateSystemGestureExclusion());
        assertEquals(expected, dc.calculateSystemGestureExclusion());
    }
    }


    @Test
    public void testCalculateSystemGestureExclusion_modal() throws Exception {
        final DisplayContent dc = createNewDisplay();
        final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, dc, "base");
        win.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
        win.setSystemGestureExclusion(Collections.singletonList(new Rect(0, 0, 1000, 1000)));

        final WindowState win2 = createWindow(null, TYPE_APPLICATION, dc, "modal");
        win2.getAttrs().flags |= FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
        win2.getAttrs().privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION;
        win2.getAttrs().width = 10;
        win2.getAttrs().height = 10;
        win2.setSystemGestureExclusion(Collections.emptyList());

        dc.setLayoutNeeded();
        dc.performLayout(true /* initial */, false /* updateImeWindows */);

        win.setHasSurface(true);
        win2.setHasSurface(true);

        final Region expected = Region.obtain();
        assertEquals(expected, dc.calculateSystemGestureExclusion());
    }

    @Test
    @Test
    public void testCalculateSystemGestureExclusion_immersiveStickyLegacyWindow() throws Exception {
    public void testCalculateSystemGestureExclusion_immersiveStickyLegacyWindow() throws Exception {
        synchronized (mWm.mGlobalLock) {
        synchronized (mWm.mGlobalLock) {