From ea97f83f8fb7997d86a2fc30a5fe970d56dae317 Mon Sep 17 00:00:00 2001 From: Tiger Huang Date: Tue, 31 May 2022 20:05:40 +0800 Subject: [PATCH] Fix InsetsState#calculateUncontrollableInsetsFromFrame If a type of insets doesn't provide any insets to a window, the previous logic would think the type is controllable. This is wrong. If a type of insets provides the entire inset to a window, the previous logic would think the type is not controllable when the width or height doesn't match the display frame. This doesn't make much sense as well. This CL fixes the issues mentioned above and also refines WindowInsetsTests. It displays the name (string) of the controllable types, not the value (number). Fix: 234426300 Test: WindowInsetsTests Test: atest InsetsControllerTest Change-Id: Ice71db61cc4963c6d8489096bec9c295d58bfd78 --- core/java/android/view/InsetsState.java | 23 ++++------ .../android/view/InsetsControllerTest.java | 26 ++++++----- .../res/layout/controller_activity.xml | 2 +- .../WindowInsetsTests/res/values/strings.xml | 2 +- .../windowinsetstests/ControllerActivity.java | 46 ++++++++++++++++++- 5 files changed, 70 insertions(+), 29 deletions(-) diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java index 9d6b982c35710..8f7a15e5fbe59 100644 --- a/core/java/android/view/InsetsState.java +++ b/core/java/android/view/InsetsState.java @@ -404,27 +404,20 @@ public class InsetsState implements Parcelable { if (source == null) { continue; } - if (!canControlSide(frame, getInsetSide( - source.calculateInsets(frame, true /* ignoreVisibility */)))) { + if (!canControlSource(frame, source)) { blocked |= toPublicType(type); } } return blocked; } - private boolean canControlSide(Rect frame, int side) { - switch (side) { - case ISIDE_LEFT: - case ISIDE_RIGHT: - return frame.left == mDisplayFrame.left && frame.right == mDisplayFrame.right; - case ISIDE_TOP: - case ISIDE_BOTTOM: - return frame.top == mDisplayFrame.top && frame.bottom == mDisplayFrame.bottom; - case ISIDE_FLOATING: - return true; - default: - return false; - } + private static boolean canControlSource(Rect frame, InsetsSource source) { + final Insets insets = source.calculateInsets(frame, true /* ignoreVisibility */); + final Rect sourceFrame = source.getFrame(); + final int sourceWidth = sourceFrame.width(); + final int sourceHeight = sourceFrame.height(); + return insets.left == sourceWidth || insets.right == sourceWidth + || insets.top == sourceHeight || insets.bottom == sourceHeight; } private void processSource(InsetsSource source, Rect relativeFrame, boolean ignoreVisibility, diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java index c504f0cf2d943..dcb1835204dd4 100644 --- a/core/tests/coretests/src/android/view/InsetsControllerTest.java +++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java @@ -214,19 +214,23 @@ public class InsetsControllerTest { } @Test - public void testFrameDoesntMatchDisplay() { - mController.onFrameChanged(new Rect(0, 0, 100, 100)); - mController.getState().setDisplayFrame(new Rect(0, 0, 200, 200)); - InsetsSourceControl control = - new InsetsSourceControl( - ITYPE_STATUS_BAR, mLeash, new Point(), Insets.of(0, 10, 0, 0)); - mController.onControlsChanged(new InsetsSourceControl[] { control }); + public void testFrameDoesntOverlapWithInsets() { WindowInsetsAnimationControlListener controlListener = mock(WindowInsetsAnimationControlListener.class); - mController.controlWindowInsetsAnimation(0, 0 /* durationMs */, new LinearInterpolator(), - new CancellationSignal(), controlListener); - mController.addOnControllableInsetsChangedListener( - (controller, typeMask) -> assertEquals(0, typeMask)); + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + // The frame doesn't overlap with status bar. + mController.onFrameChanged(new Rect(0, 10, 100, 100)); + + InsetsSourceControl control = + new InsetsSourceControl( + ITYPE_STATUS_BAR, mLeash, new Point(), Insets.of(0, 10, 0, 0)); + mController.onControlsChanged(new InsetsSourceControl[]{control}); + mController.controlWindowInsetsAnimation(0, 0 /* durationMs */, + new LinearInterpolator(), + new CancellationSignal(), controlListener); + mController.addOnControllableInsetsChangedListener( + (controller, typeMask) -> assertEquals(0, typeMask)); + }); verify(controlListener).onCancelled(null); verify(controlListener, never()).onReady(any(), anyInt()); } diff --git a/tests/WindowInsetsTests/res/layout/controller_activity.xml b/tests/WindowInsetsTests/res/layout/controller_activity.xml index d51a4ddd43e8c..5550eab61a33a 100644 --- a/tests/WindowInsetsTests/res/layout/controller_activity.xml +++ b/tests/WindowInsetsTests/res/layout/controller_activity.xml @@ -88,7 +88,7 @@ diff --git a/tests/WindowInsetsTests/res/values/strings.xml b/tests/WindowInsetsTests/res/values/strings.xml index d6355f5a04645..516d4584426e0 100644 --- a/tests/WindowInsetsTests/res/values/strings.xml +++ b/tests/WindowInsetsTests/res/values/strings.xml @@ -22,7 +22,7 @@ - BEHAVIOR_SHOW_BARS_BY_TOUCH + BEHAVIOR_SHOW_BARS_BY_TOUCH (deprecated) BEHAVIOR_DEFAULT BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE diff --git a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ControllerActivity.java b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ControllerActivity.java index 95fd959e5587c..e6b60cfbe84fd 100644 --- a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ControllerActivity.java +++ b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ControllerActivity.java @@ -83,7 +83,51 @@ public class ControllerActivity extends Activity implements View.OnApplyWindowIn final View contentView = findViewById(R.id.content); contentView.setOnApplyWindowInsetsListener(this); contentView.getWindowInsetsController().addOnControllableInsetsChangedListener( - (c, types) -> mTextControllableInsets.setText("ControllableInsetsTypes=" + types)); + (c, types) -> mTextControllableInsets.setText( + "ControllableInsetsTypes:\n" + insetsTypesToString(types))); + } + + private static String insetsTypesToString(int types) { + if (types == 0) { + return "none"; + } + final StringBuilder sb = new StringBuilder(); + if ((types & Type.statusBars()) != 0) { + types &= ~Type.statusBars(); + sb.append("statusBars "); + } + if ((types & Type.navigationBars()) != 0) { + types &= ~Type.navigationBars(); + sb.append("navigationBars "); + } + if ((types & Type.captionBar()) != 0) { + types &= ~Type.captionBar(); + sb.append("captionBar "); + } + if ((types & Type.ime()) != 0) { + types &= ~Type.ime(); + sb.append("ime "); + } + if ((types & Type.systemGestures()) != 0) { + types &= ~Type.systemGestures(); + sb.append("systemGestures "); + } + if ((types & Type.mandatorySystemGestures()) != 0) { + types &= ~Type.mandatorySystemGestures(); + sb.append("mandatorySystemGestures "); + } + if ((types & Type.tappableElement()) != 0) { + types &= ~Type.tappableElement(); + sb.append("tappableElement "); + } + if ((types & Type.displayCutout()) != 0) { + types &= ~Type.displayCutout(); + sb.append("displayCutout "); + } + if (types != 0) { + sb.append("unknownTypes:").append(types); + } + return sb.toString(); } @Override