diff options
| author | Adrian Roos <roosa@google.com> | 2019-06-28 12:10:51 +0200 |
|---|---|---|
| committer | Adrian Roos <roosa@google.com> | 2019-07-04 17:44:07 +0200 |
| commit | b106379310783dac036088c6ef052d3ceb0754fa (patch) | |
| tree | 04aa3d4443a1c046637fbc8660e4e90575c5e8cc | |
| parent | 8ef731c2329badb9555782c47885d9c262d6df9c (diff) | |
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
3 files changed, 45 insertions, 4 deletions
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index c069b2e8da5c..675483442300 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -5142,7 +5142,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo final int[] remainingLeftRight = {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. forAllWindows(w -> { if (w.cantReceiveTouchInput() || !w.isVisible() @@ -5150,12 +5150,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo || unhandled.isEmpty()) { 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 // touchable, i.e. touchable regions on top are not covering it yet. - w.getTouchableRegion(touchableRegion); + w.getEffectiveTouchableRegion(touchableRegion); touchableRegion.op(unhandled, Op.INTERSECT); if (w.isImplicitlyExcludingAllSystemGestures()) { diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index b5586bf28751..43ad091b08c0 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -3011,6 +3011,25 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP 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) { final Task task = getTask(); if (task == null || !task.cropWindowsToStackBounds()) { diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index f2e7dc6fecae..7cd097ebdc2b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -794,6 +794,30 @@ public class DisplayContentTests extends WindowTestsBase { } @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 public void testCalculateSystemGestureExclusion_immersiveStickyLegacyWindow() throws Exception { synchronized (mWm.mGlobalLock) { mWm.mSystemGestureExcludedByPreQStickyImmersive = true; |
