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

Commit 19c7b531 authored by Cosmin Băieș's avatar Cosmin Băieș
Browse files

Create array of all insets types

This replaces the current insets type iteration based on first and last
values with an array iteration, enabling IntDef flag value checks, and
making the code more readable.

Flag: EXEMPT refactor
Bug: 281029564
Test: atest WindowInsetsTest InsetsSourceTest
Change-Id: I034197f61e2e44a33f35be8b6130bc8760479f19
parent 67860870
Loading
Loading
Loading
Loading
+3 −4
Original line number Diff line number Diff line
@@ -22,8 +22,7 @@ import static android.internal.perfetto.protos.Insetscontroller.InsetsController
import static android.view.InsetsSource.ID_IME;
import static android.view.InsetsSource.ID_IME_CAPTION_BAR;
import static android.view.ViewProtoLogGroups.IME_INSETS_CONTROLLER;
import static android.view.WindowInsets.Type.FIRST;
import static android.view.WindowInsets.Type.LAST;
import static android.view.WindowInsets.Type.TYPES;
import static android.view.WindowInsets.Type.all;
import static android.view.WindowInsets.Type.captionBar;
import static android.view.WindowInsets.Type.ime;
@@ -1204,7 +1203,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
        int typesReady = 0;
        final boolean imeVisible = mState.isSourceOrDefaultVisible(
                mImeSourceConsumer.getId(), ime());
        for (@InsetsType int type = FIRST; type <= LAST; type = type << 1) {
        for (@InsetsType int type : TYPES) {
            if ((types & type) == 0) {
                continue;
            }
@@ -1287,7 +1286,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation

        @InsetsType
        int typesReady = 0;
        for (@InsetsType int type = FIRST; type <= LAST; type = type << 1) {
        for (@InsetsType int type : TYPES) {
            if ((types & type) == 0) {
                continue;
            }
+6 −6
Original line number Diff line number Diff line
@@ -26,7 +26,7 @@ import static android.internal.perfetto.protos.Insetsstate.InsetsStateProto.DISP
import static android.internal.perfetto.protos.Insetsstate.InsetsStateProto.DISPLAY_FRAME;
import static android.internal.perfetto.protos.Insetsstate.InsetsStateProto.SOURCES;
import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
import static android.view.WindowInsets.Type.SIZE;
import static android.view.WindowInsets.Type.TYPES;
import static android.view.WindowInsets.Type.captionBar;
import static android.view.WindowInsets.Type.defaultCompatible;
import static android.view.WindowInsets.Type.displayCutout;
@@ -142,9 +142,9 @@ public class InsetsState implements Parcelable {
            int legacySoftInputMode, int legacyWindowFlags, int legacySystemUiFlags,
            @WindowType int windowType, @ActivityType int activityType,
            @Nullable @InternalInsetsSide SparseIntArray idSideMap) {
        final Insets[] typeInsetsMap = new Insets[SIZE];
        final Insets[] typeMaxInsetsMap = new Insets[SIZE];
        final boolean[] typeVisibilityMap = new boolean[SIZE];
        final Insets[] typeInsetsMap = new Insets[TYPES.length];
        final Insets[] typeMaxInsetsMap = new Insets[TYPES.length];
        final boolean[] typeVisibilityMap = new boolean[TYPES.length];
        final Rect relativeFrame = new Rect(frame);
        final Rect relativeFrameMax = new Rect(frame);
        @InsetsType
@@ -152,8 +152,8 @@ public class InsetsState implements Parcelable {
        boolean forceConsumingOpaqueCaptionBar = false;
        @InsetsType
        int suppressScrimTypes = 0;
        final Rect[][] typeBoundingRectsMap = new Rect[SIZE][];
        final Rect[][] typeMaxBoundingRectsMap = new Rect[SIZE][];
        final Rect[][] typeBoundingRectsMap = new Rect[TYPES.length][];
        final Rect[][] typeMaxBoundingRectsMap = new Rect[TYPES.length][];
        for (int i = mSources.size() - 1; i >= 0; i--) {
            final InsetsSource source = mSources.valueAt(i);
            @InsetsType
+87 −63
Original line number Diff line number Diff line
@@ -19,15 +19,13 @@ package android.view;

import static android.view.Surface.ROTATION_0;
import static android.view.WindowInsets.Type.DISPLAY_CUTOUT;
import static android.view.WindowInsets.Type.FIRST;
import static android.view.WindowInsets.Type.IME;
import static android.view.WindowInsets.Type.LAST;
import static android.view.WindowInsets.Type.MANDATORY_SYSTEM_GESTURES;
import static android.view.WindowInsets.Type.NAVIGATION_BARS;
import static android.view.WindowInsets.Type.SIZE;
import static android.view.WindowInsets.Type.STATUS_BARS;
import static android.view.WindowInsets.Type.SYSTEM_GESTURES;
import static android.view.WindowInsets.Type.TAPPABLE_ELEMENT;
import static android.view.WindowInsets.Type.TYPES;
import static android.view.WindowInsets.Type.all;
import static android.view.WindowInsets.Type.defaultCompatible;
import static android.view.WindowInsets.Type.displayCutout;
@@ -173,12 +171,12 @@ public final class WindowInsets {
            int frameWidth, int frameHeight) {
        mSystemWindowInsetsConsumed = typeInsetsMap == null;
        mTypeInsetsMap = mSystemWindowInsetsConsumed
                ? new Insets[SIZE]
                ? new Insets[TYPES.length]
                : typeInsetsMap.clone();

        mStableInsetsConsumed = typeMaxInsetsMap == null;
        mTypeMaxInsetsMap = mStableInsetsConsumed
                ? new Insets[SIZE]
                ? new Insets[TYPES.length]
                : typeMaxInsetsMap.clone();

        mTypeVisibilityMap = typeVisibilityMap;
@@ -197,10 +195,10 @@ public final class WindowInsets {
        mPrivacyIndicatorBounds = privacyIndicatorBounds;
        mDisplayShape = displayShape;
        mTypeBoundingRectsMap = (mSystemWindowInsetsConsumed || typeBoundingRectsMap == null)
                ? new Rect[SIZE][]
                ? new Rect[TYPES.length][]
                : typeBoundingRectsMap.clone();
        mTypeMaxBoundingRectsMap = (mStableInsetsConsumed || typeMaxBoundingRectsMap == null)
                ? new Rect[SIZE][]
                ? new Rect[TYPES.length][]
                : typeMaxBoundingRectsMap.clone();
        mFrameWidth = frameWidth;
        mFrameHeight = frameHeight;
@@ -248,11 +246,11 @@ public final class WindowInsets {
    @NonNull
    static Insets getInsets(@NonNull Insets[] typeInsetsMap, @InsetsType int typeMask) {
        Insets result = null;
        for (int i = FIRST; i <= LAST; i = i << 1) {
            if ((typeMask & i) == 0) {
        for (@InsetsType int type : TYPES) {
            if ((typeMask & type) == 0) {
                continue;
            }
            Insets insets = typeInsetsMap[indexOf(i)];
            Insets insets = typeInsetsMap[indexOf(type)];
            if (insets == null) {
                continue;
            }
@@ -270,20 +268,20 @@ public final class WindowInsets {
     */
    private static void setInsets(@NonNull Insets[] typeInsetsMap, @InsetsType int typeMask,
            @NonNull Insets insets) {
        for (int i = FIRST; i <= LAST; i = i << 1) {
            if ((typeMask & i) == 0) {
        for (@InsetsType int type : TYPES) {
            if ((typeMask & type) == 0) {
                continue;
            }
            typeInsetsMap[indexOf(i)] = insets;
            typeInsetsMap[indexOf(type)] = insets;
        }
    }

    /** @hide */
    @UnsupportedAppUsage
    public WindowInsets(@Nullable Rect systemWindowInsets) {
        this(createCompatTypeMap(systemWindowInsets), null, new boolean[SIZE], false, 0, false, 0,
                null, null, null, null, defaultCompatible(), false /* compatIgnoreVisibility */,
                new Rect[SIZE][], null, 0, 0);
        this(createCompatTypeMap(systemWindowInsets), null, new boolean[TYPES.length], false, 0,
                false, 0, null, null, null, null, defaultCompatible(),
                false /* compatIgnoreVisibility */, new Rect[TYPES.length][], null, 0, 0);
    }

    /**
@@ -299,7 +297,7 @@ public final class WindowInsets {
        if (insets == null) {
            return null;
        }
        Insets[] typeInsetsMap = new Insets[SIZE];
        Insets[] typeInsetsMap = new Insets[TYPES.length];
        assignCompatInsets(typeInsetsMap, insets);
        return typeInsetsMap;
    }
@@ -320,12 +318,12 @@ public final class WindowInsets {
    @VisibleForTesting
    @NonNull
    private static boolean[] createCompatVisibilityMap(@Nullable Insets[] typeInsetsMap) {
        boolean[] typeVisibilityMap = new boolean[SIZE];
        final boolean[] typeVisibilityMap = new boolean[TYPES.length];
        if (typeInsetsMap == null) {
            return typeVisibilityMap;
        }
        for (int i = FIRST; i <= LAST; i = i << 1) {
            int index = indexOf(i);
        for (@InsetsType int type : TYPES) {
            final int index = indexOf(type);
            if (!Insets.NONE.equals(typeInsetsMap[index])) {
                typeVisibilityMap[index] = true;
            }
@@ -424,11 +422,11 @@ public final class WindowInsets {
     *         visible on screen.
     */
    public boolean isVisible(@InsetsType int typeMask) {
        for (int i = FIRST; i <= LAST; i = i << 1) {
            if ((typeMask & i) == 0) {
        for (@InsetsType int type : TYPES) {
            if ((typeMask & type) == 0) {
                continue;
            }
            if (!mTypeVisibilityMap[indexOf(i)]) {
            if (!mTypeVisibilityMap[indexOf(type)]) {
                return false;
            }
        }
@@ -601,11 +599,11 @@ public final class WindowInsets {
    private List<Rect> getBoundingRects(@NonNull Rect[][] typeBoundingRectsMap,
            @InsetsType int typeMask) {
        Rect[] allRects = null;
        for (int i = FIRST; i <= LAST; i = i << 1) {
            if ((typeMask & i) == 0) {
        for (@InsetsType int type : TYPES) {
            if ((typeMask & type) == 0) {
                continue;
            }
            final Rect[] rects = typeBoundingRectsMap[indexOf(i)];
            final Rect[] rects = typeBoundingRectsMap[indexOf(type)];
            if (rects == null) {
                continue;
            }
@@ -1069,19 +1067,20 @@ public final class WindowInsets {

    @Override
    public String toString() {
        StringBuilder result = new StringBuilder("WindowInsets{\n    ");
        for (int i = 0; i < SIZE; i++) {
            Insets insets = mTypeInsetsMap[i];
            Insets maxInsets = mTypeMaxInsetsMap[i];
            boolean visible = mTypeVisibilityMap[i];
        final var result = new StringBuilder("WindowInsets{\n    ");
        for (@InsetsType int type : TYPES) {
            final int index = indexOf(type);
            final Insets insets = mTypeInsetsMap[index];
            final Insets maxInsets = mTypeMaxInsetsMap[index];
            final boolean visible = mTypeVisibilityMap[index];
            if (!Insets.NONE.equals(insets) || !Insets.NONE.equals(maxInsets) || visible) {
                result.append(Type.toString(1 << i)).append("=").append(insets)
                result.append(Type.toString(type)).append("=").append(insets)
                        .append(" max=").append(maxInsets)
                        .append(" vis=").append(visible)
                        .append(" boundingRects=")
                        .append(Arrays.toString(mTypeBoundingRectsMap[i]))
                        .append(Arrays.toString(mTypeBoundingRectsMap[index]))
                        .append(" maxBoundingRects=")
                        .append(Arrays.toString(mTypeMaxBoundingRectsMap[i]))
                        .append(Arrays.toString(mTypeMaxBoundingRectsMap[index]))
                        .append("\n    ");
            }
        }
@@ -1295,8 +1294,9 @@ public final class WindowInsets {
    private static Insets[] insetInsets(
            @NonNull Insets[] typeInsetsMap, int left, int top, int right, int bottom) {
        boolean cloned = false;
        for (int i = 0; i < SIZE; i++) {
            Insets insets = typeInsetsMap[i];
        for (@InsetsType int type : TYPES) {
            final int index = indexOf(type);
            final Insets insets = typeInsetsMap[index];
            if (insets == null) {
                continue;
            }
@@ -1306,7 +1306,7 @@ public final class WindowInsets {
                    typeInsetsMap = typeInsetsMap.clone();
                    cloned = true;
                }
                typeInsetsMap[i] = insetInsets;
                typeInsetsMap[index] = insetInsets;
            }
        }
        return typeInsetsMap;
@@ -1333,8 +1333,9 @@ public final class WindowInsets {
            return typeBoundingRectsMap;
        }
        boolean cloned = false;
        for (int i = 0; i < SIZE; i++) {
            final Rect[] boundingRects = typeBoundingRectsMap[i];
        for (@InsetsType int type : TYPES) {
            final int index = indexOf(type);
            final Rect[] boundingRects = typeBoundingRectsMap[index];
            if (boundingRects == null) {
                continue;
            }
@@ -1345,7 +1346,7 @@ public final class WindowInsets {
                    typeBoundingRectsMap = typeBoundingRectsMap.clone();
                    cloned = true;
                }
                typeBoundingRectsMap[i] = insetBoundingRects;
                typeBoundingRectsMap[index] = insetBoundingRects;
            }
        }
        return typeBoundingRectsMap;
@@ -1440,11 +1441,11 @@ public final class WindowInsets {
         * Creates a builder where all insets are initially consumed.
         */
        public Builder() {
            mTypeInsetsMap = new Insets[SIZE];
            mTypeMaxInsetsMap = new Insets[SIZE];
            mTypeVisibilityMap = new boolean[SIZE];
            mTypeBoundingRectsMap = new Rect[SIZE][];
            mTypeMaxBoundingRectsMap = new Rect[SIZE][];
            mTypeInsetsMap = new Insets[TYPES.length];
            mTypeMaxInsetsMap = new Insets[TYPES.length];
            mTypeVisibilityMap = new boolean[TYPES.length];
            mTypeBoundingRectsMap = new Rect[TYPES.length][];
            mTypeMaxBoundingRectsMap = new Rect[TYPES.length][];
            mCompatInsetTypes = defaultCompatible();
            mCompatIgnoreVisibility = false;
        }
@@ -1624,11 +1625,11 @@ public final class WindowInsets {
         */
        @NonNull
        public Builder setVisible(@InsetsType int typeMask, boolean visible) {
            for (int i = FIRST; i <= LAST; i = i << 1) {
                if ((typeMask & i) == 0) {
            for (@InsetsType int type : TYPES) {
                if ((typeMask & type) == 0) {
                    continue;
                }
                mTypeVisibilityMap[indexOf(i)] = visible;
                mTypeVisibilityMap[indexOf(type)] = visible;
            }
            return this;
        }
@@ -1770,11 +1771,11 @@ public final class WindowInsets {
        @FlaggedApi(Flags.FLAG_CUSTOMIZABLE_WINDOW_HEADERS)
        @NonNull
        public Builder setBoundingRects(@InsetsType int typeMask, @NonNull List<Rect> rects) {
            for (int i = FIRST; i <= LAST; i = i << 1) {
                if ((typeMask & i) == 0) {
            for (@InsetsType int type : TYPES) {
                if ((typeMask & type) == 0) {
                    continue;
                }
                mTypeBoundingRectsMap[indexOf(i)] = rects.toArray(new Rect[0]);
                mTypeBoundingRectsMap[indexOf(type)] = rects.toArray(new Rect[0]);
            }
            mSystemInsetsConsumed = false;
            return this;
@@ -1799,11 +1800,11 @@ public final class WindowInsets {
            if (typeMask == IME) {
                throw new IllegalArgumentException("Maximum bounding rects not available for IME");
            }
            for (int i = FIRST; i <= LAST; i = i << 1) {
                if ((typeMask & i) == 0) {
            for (@InsetsType int type : TYPES) {
                if ((typeMask & type) == 0) {
                    continue;
                }
                mTypeMaxBoundingRectsMap[indexOf(i)] = rects.toArray(new Rect[0]);
                mTypeMaxBoundingRectsMap[indexOf(type)] = rects.toArray(new Rect[0]);
            }
            mStableInsetsConsumed = false;
            return this;
@@ -1856,18 +1857,42 @@ public final class WindowInsets {
        static final int TAPPABLE_ELEMENT = 1 << 6;
        static final int DISPLAY_CUTOUT = 1 << 7;
        static final int SYSTEM_OVERLAYS = 1 << 8;
        @InsetsType
        static final int FIRST = STATUS_BARS;
        @InsetsType
        static final int LAST = SYSTEM_OVERLAYS;
        static final int SIZE = 9;

        /**
         * The array of all insets types.
         *
         * @hide
         */
        @NonNull
        public static final int[] TYPES = {
                STATUS_BARS,
                NAVIGATION_BARS,
                CAPTION_BAR,
                IME,
                SYSTEM_GESTURES,
                MANDATORY_SYSTEM_GESTURES,
                TAPPABLE_ELEMENT,
                DISPLAY_CUTOUT,
                SYSTEM_OVERLAYS,
        };

        /** The bitmask of all insets types combined. */
        @InsetsType
        static final int ALL = ((1 << SIZE) - 1);
        static final int ALL = STATUS_BARS | NAVIGATION_BARS | CAPTION_BAR | IME | SYSTEM_GESTURES
                | MANDATORY_SYSTEM_GESTURES | TAPPABLE_ELEMENT | DISPLAY_CUTOUT | SYSTEM_OVERLAYS;

        /** The bitmask of default visible insets types. */
        @InsetsType
        static final int DEFAULT_VISIBLE = ALL & ~IME;

        static int indexOf(@InsetsType int type) {
        /**
         * Gets the index of the bit corresponding to the given type.
         *
         * @param type the type to get the bit index of.
         *
         * @hide
         */
        public static int indexOf(@InsetsType int type) {
            switch (type) {
                case STATUS_BARS:
                    return 0;
@@ -1888,8 +1913,7 @@ public final class WindowInsets {
                case SYSTEM_OVERLAYS:
                    return 8;
                default:
                    throw new IllegalArgumentException("type needs to be >= FIRST and <= LAST,"
                            + " type=" + type);
                    throw new IllegalArgumentException("Unknown insets type: " + type);
            }
        }

+6 −7
Original line number Diff line number Diff line
@@ -17,9 +17,7 @@
package android.view;

import static android.view.InsetsSource.ID_IME_CAPTION_BAR;
import static android.view.WindowInsets.Type.FIRST;
import static android.view.WindowInsets.Type.LAST;
import static android.view.WindowInsets.Type.SIZE;
import static android.view.WindowInsets.Type.TYPES;
import static android.view.WindowInsets.Type.captionBar;
import static android.view.WindowInsets.Type.ime;
import static android.view.WindowInsets.Type.navigationBars;
@@ -31,6 +29,7 @@ import android.graphics.Insets;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.util.SparseArray;
import android.view.WindowInsets.Type.InsetsType;

import androidx.test.ext.junit.runners.AndroidJUnit4;

@@ -367,11 +366,11 @@ public class InsetsSourceTest {
    @Test
    public void testCreateId() {
        final int numSourcePerType = 2048;
        final int numTotalSources = SIZE * numSourcePerType;
        final int numTotalSources = TYPES.length * numSourcePerType;
        final SparseArray<InsetsSource> sources = new SparseArray<>(numTotalSources);
        final Object owner = new Object();
        for (int index = 0; index < numSourcePerType; index++) {
            for (int type = FIRST; type <= LAST; type = type << 1) {
            for (@InsetsType int type : TYPES) {
                final int id = InsetsSource.createId(owner, index, type);
                assertNull("Must not create the same ID.", sources.get(id));
                sources.append(id, new InsetsSource(id, type));
@@ -385,7 +384,7 @@ public class InsetsSourceTest {
        // Here doesn't iterate all the owners, or the test cannot be done before timeout.
        for (int owner = 0; owner < 100; owner++) {
            for (int index = 0; index < 2048; index++) {
                for (int type = FIRST; type <= LAST; type = type << 1) {
                for (@InsetsType int type : TYPES) {
                    final int id = InsetsSource.createId(owner, index, type);
                    final int indexFromId = InsetsSource.getIndex(id);
                    assertEquals("index and indexFromId must be the same. id=" + id
@@ -403,7 +402,7 @@ public class InsetsSourceTest {
        // Here doesn't iterate all the owners, or the test cannot be done before timeout.
        for (int owner = 0; owner < 100; owner++) {
            for (int index = 0; index < 2048; index++) {
                for (int type = FIRST; type <= LAST; type = type << 1) {
                for (@InsetsType int type : TYPES) {
                    final int id = InsetsSource.createId(owner, index, type);
                    final int typeFromId = InsetsSource.getType(id);
                    assertEquals("type and typeFromId must be the same. id=" + id
+103 −10
Original line number Diff line number Diff line
@@ -16,7 +16,8 @@

package android.view;

import static android.view.WindowInsets.Type.SIZE;
import static android.view.WindowInsets.Type.ALL;
import static android.view.WindowInsets.Type.TYPES;
import static android.view.WindowInsets.Type.captionBar;
import static android.view.WindowInsets.Type.displayCutout;
import static android.view.WindowInsets.Type.ime;
@@ -25,11 +26,14 @@ import static android.view.WindowInsets.Type.statusBars;
import static android.view.WindowInsets.Type.systemBars;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;

import android.graphics.Insets;
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.view.WindowInsets.Type.InsetsType;

import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -44,6 +48,95 @@ import java.util.List;
@Presubmit
public class WindowInsetsTest {

    /**
     * Verifies that all the values in {@link WindowInsets.Type#TYPES} are included in
     * {@link WindowInsets.Type#ALL}.
     */
    @Test
    public void testTypesInAll() {
        int combinedTypes = 0;
        for (@InsetsType int type : TYPES) {
            assertTrue("type in TYPES should be included in ALL", (type & ALL) != 0);
            combinedTypes |= type;
        }
        assertEquals("ALL should match bitmask of combined types", ALL, combinedTypes);
    }

    /**
     * Verifies that all the values in {@link WindowInsets.Type#ALL} are included in
     * {@link WindowInsets.Type#TYPES}.
     */
    @Test
    public void testAllInTypes() {
        for (int index = 0; index < Integer.SIZE; index++) {
            final int type = 1 << index;
            if ((type & WindowInsets.Type.ALL) != 0) {
                assertTrue("index of bit in ALL should be less than number of TYPES",
                        index < TYPES.length);
                assertEquals("type in ALL should be included in TYPES", type, TYPES[index]);
            }
        }
    }

    /**
     * Verifies that all the values in {@link WindowInsets.Type#TYPES} are included in
     * {@link WindowInsets.Type#indexOf}.
     */
    @Test
    public void testTypesInIndexOf() {
        for (@InsetsType int type : TYPES) {
            assertEquals("type should match", type, TYPES[WindowInsets.Type.indexOf(type)]);
        }
        assertThrows(IllegalArgumentException.class, () -> WindowInsets.Type.indexOf(-1));
    }

    /**
     * Verifies that all the values returned by {@link WindowInsets.Type#indexOf} are included in
     * {@link WindowInsets.Type#TYPES}.
     */
    @Test
    public void testIndexOfInTypes() {
        for (int i = 0; i < Integer.SIZE; i++) {
            final int type = 1 << i;
            try {
                final int index = WindowInsets.Type.indexOf(type);
                assertTrue("index should be non-negative", index >= 0);
                assertTrue("index should be less than number of TYPES", index < TYPES.length);
                assertEquals(type, TYPES[index]);
            } catch (IllegalArgumentException e) {
                // ignore undefined indexOf case, handled through testTypesInIndexOf above.
            }
        }
    }

    /**
     * Verifies that all the values in {@link WindowInsets.Type#TYPES} are included in
     * {@link WindowInsets.Type#toString}.
     */
    @Test
    public void testTypesInToString() {
        for (@InsetsType int type : TYPES) {
            assertFalse("type toString should not be empty",
                    WindowInsets.Type.toString(type).isEmpty());
        }
        assertTrue("invalid type toString should be empty",
                WindowInsets.Type.toString(0).isEmpty());
    }

    /**
     * Verifies that all the values accepted by {@link WindowInsets.Type#toString} are included in
     * {@link WindowInsets.Type#TYPES}.
     */
    @Test
    public void testToStringInTypes() {
        for (int i = 0; i < Integer.SIZE; i++) {
            final int type = 1 << i;
            if (!WindowInsets.Type.toString(type).isEmpty()) {
                assertEquals("type should match", type, TYPES[i]);
            }
        }
    }

    @Test
    public void systemWindowInsets_afterConsuming_isConsumed() {
        assertTrue(new WindowInsets(WindowInsets.createCompatTypeMap(new Rect(1, 2, 3, 4)), null,
@@ -65,9 +158,9 @@ public class WindowInsetsTest {

    @Test
    public void compatInsets_layoutStable() {
        Insets[] insets = new Insets[SIZE];
        Insets[] maxInsets = new Insets[SIZE];
        boolean[] visible = new boolean[SIZE];
        Insets[] insets = new Insets[TYPES.length];
        Insets[] maxInsets = new Insets[TYPES.length];
        boolean[] visible = new boolean[TYPES.length];
        WindowInsets.assignCompatInsets(maxInsets, new Rect(0, 10, 0, 0));
        WindowInsets.assignCompatInsets(insets, new Rect(0, 0, 0, 0));
        WindowInsets windowInsets = new WindowInsets(insets, maxInsets, visible, false, 0,
@@ -78,9 +171,9 @@ public class WindowInsetsTest {

    @Test
    public void builder_copy_compatInsetTypes() {
        final Insets[] insets = new Insets[SIZE];
        final Insets[] maxInsets = new Insets[SIZE];
        final boolean[] visible = new boolean[SIZE];
        final Insets[] insets = new Insets[TYPES.length];
        final Insets[] maxInsets = new Insets[TYPES.length];
        final boolean[] visible = new boolean[TYPES.length];
        final int compatInsetTypes = systemBars() | displayCutout() | ime();
        final WindowInsets windowInsets = new WindowInsets(insets, maxInsets, visible, false, 0,
                false, 0, null, null, null, DisplayShape.NONE, compatInsetTypes,
@@ -96,9 +189,9 @@ public class WindowInsetsTest {

    @Test
    public void builder_copy_compatIgnoreVisibility() {
        final Insets[] insets = new Insets[SIZE];
        final Insets[] maxInsets = new Insets[SIZE];
        final boolean[] visible = new boolean[SIZE];
        final Insets[] insets = new Insets[TYPES.length];
        final Insets[] maxInsets = new Insets[TYPES.length];
        final boolean[] visible = new boolean[TYPES.length];
        final int compatInsetTypes = systemBars() | displayCutout();
        final WindowInsets windowInsets = new WindowInsets(insets, maxInsets, visible, false, 0,
                false, 0, null, null, null, DisplayShape.NONE, compatInsetTypes,