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

Commit ea97f83f authored by Tiger Huang's avatar Tiger Huang
Browse files

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
parent 2e83cb0c
Loading
Loading
Loading
Loading
+8 −15
Original line number Diff line number Diff line
@@ -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,
+15 −11
Original line number Diff line number Diff line
@@ -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));
    public void testFrameDoesntOverlapWithInsets() {
        WindowInsetsAnimationControlListener controlListener =
                mock(WindowInsetsAnimationControlListener.class);
        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});
        WindowInsetsAnimationControlListener controlListener =
                mock(WindowInsetsAnimationControlListener.class);
        mController.controlWindowInsetsAnimation(0, 0 /* durationMs */, new LinearInterpolator(),
            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());
    }
+1 −1
Original line number Diff line number Diff line
@@ -88,7 +88,7 @@

        <TextView
            android:id="@+id/textViewControllableInsets"
            android:layout_width="wrap_content"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="5dp" />

+1 −1
Original line number Diff line number Diff line
@@ -22,7 +22,7 @@

    <!-- The item positions should match the flag values respectively. -->
    <string-array name="behaviors">
        <item>BEHAVIOR_SHOW_BARS_BY_TOUCH</item>
        <item>BEHAVIOR_SHOW_BARS_BY_TOUCH (deprecated)</item>
        <item>BEHAVIOR_DEFAULT</item>
        <item>BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE</item>
    </string-array>
+45 −1
Original line number Diff line number Diff line
@@ -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