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
This commit is contained in:
Adrian Roos
2019-06-28 12:10:51 +02:00
parent 8ef731c232
commit b106379310
3 changed files with 45 additions and 4 deletions

View File

@@ -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()) {

View File

@@ -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()) {

View File

@@ -793,6 +793,30 @@ public class DisplayContentTests extends WindowTestsBase {
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
public void testCalculateSystemGestureExclusion_immersiveStickyLegacyWindow() throws Exception {
synchronized (mWm.mGlobalLock) {