• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 
18 package android.view;
19 
20 import static android.view.Surface.ROTATION_0;
21 import static android.view.WindowInsets.Type.DISPLAY_CUTOUT;
22 import static android.view.WindowInsets.Type.FIRST;
23 import static android.view.WindowInsets.Type.IME;
24 import static android.view.WindowInsets.Type.LAST;
25 import static android.view.WindowInsets.Type.MANDATORY_SYSTEM_GESTURES;
26 import static android.view.WindowInsets.Type.NAVIGATION_BARS;
27 import static android.view.WindowInsets.Type.SIZE;
28 import static android.view.WindowInsets.Type.STATUS_BARS;
29 import static android.view.WindowInsets.Type.SYSTEM_GESTURES;
30 import static android.view.WindowInsets.Type.TAPPABLE_ELEMENT;
31 import static android.view.WindowInsets.Type.all;
32 import static android.view.WindowInsets.Type.displayCutout;
33 import static android.view.WindowInsets.Type.ime;
34 import static android.view.WindowInsets.Type.indexOf;
35 import static android.view.WindowInsets.Type.systemBars;
36 
37 import android.annotation.FlaggedApi;
38 import android.annotation.IntDef;
39 import android.annotation.IntRange;
40 import android.annotation.NonNull;
41 import android.annotation.Nullable;
42 import android.annotation.SuppressLint;
43 import android.annotation.TestApi;
44 import android.compat.annotation.UnsupportedAppUsage;
45 import android.content.Intent;
46 import android.graphics.Insets;
47 import android.graphics.Rect;
48 import android.util.Size;
49 import android.view.View.OnApplyWindowInsetsListener;
50 import android.view.WindowInsets.Type.InsetsType;
51 import android.view.flags.Flags;
52 import android.view.inputmethod.EditorInfo;
53 import android.view.inputmethod.InputMethod;
54 
55 import com.android.internal.annotations.VisibleForTesting;
56 import com.android.internal.util.Preconditions;
57 
58 import java.lang.annotation.Retention;
59 import java.lang.annotation.RetentionPolicy;
60 import java.util.ArrayList;
61 import java.util.Arrays;
62 import java.util.Collections;
63 import java.util.List;
64 import java.util.Objects;
65 
66 /**
67  * Describes a set of insets for window content.
68  *
69  * <p>WindowInsets are immutable and may be expanded to include more inset types in the future.
70  * To adjust insets, use one of the supplied clone methods to obtain a new WindowInsets instance
71  * with the adjusted properties.</p>
72  *
73  * <p>Note: Before {@link android.os.Build.VERSION_CODES#P P}, WindowInsets instances were only
74  * immutable during a single layout pass (i.e. would return the same values between
75  * {@link View#onApplyWindowInsets} and {@link View#onLayout}, but could return other values
76  * otherwise). Starting with {@link android.os.Build.VERSION_CODES#P P}, WindowInsets are
77  * always immutable and implement equality.
78  *
79  * @see View.OnApplyWindowInsetsListener
80  * @see View#onApplyWindowInsets(WindowInsets)
81  */
82 public final class WindowInsets {
83 
84     private final Insets[] mTypeInsetsMap;
85     private final Insets[] mTypeMaxInsetsMap;
86     private final boolean[] mTypeVisibilityMap;
87     private final Rect[][] mTypeBoundingRectsMap;
88     private final Rect[][] mTypeMaxBoundingRectsMap;
89 
90     @Nullable private Rect mTempRect;
91     private final boolean mIsRound;
92     @Nullable private final DisplayCutout mDisplayCutout;
93     @Nullable private final RoundedCorners mRoundedCorners;
94     @Nullable private final PrivacyIndicatorBounds mPrivacyIndicatorBounds;
95     @Nullable private final DisplayShape mDisplayShape;
96     private final int mFrameWidth;
97     private final int mFrameHeight;
98 
99     private final @InsetsType int mForceConsumingTypes;
100     private final boolean mForceConsumingOpaqueCaptionBar;
101     private final @InsetsType int mSuppressScrimTypes;
102     private final boolean mSystemWindowInsetsConsumed;
103     private final boolean mStableInsetsConsumed;
104     private final boolean mDisplayCutoutConsumed;
105 
106     private final int mCompatInsetsTypes;
107     private final boolean mCompatIgnoreVisibility;
108 
109     /**
110      * A {@link WindowInsets} instance for which {@link #isConsumed()} returns {@code true}.
111      * <p>
112      * This can be used during insets dispatch in the view hierarchy by returning this value from
113      * {@link View#onApplyWindowInsets(WindowInsets)} or
114      * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets)} to stop dispatch
115      * the insets to its children to avoid traversing the entire view hierarchy.
116      * <p>
117      * The application should return this instance once it has taken care of all insets on a certain
118      * level in the view hierarchy, and doesn't need to dispatch to its children anymore for better
119      * performance.
120      *
121      * @see #isConsumed()
122      */
123     public static final @NonNull WindowInsets CONSUMED;
124 
125     static {
126         CONSUMED = new WindowInsets(createCompatTypeMap(null), createCompatTypeMap(null),
127                 createCompatVisibilityMap(createCompatTypeMap(null)), false, 0, false, 0, null,
128                 null, null, null, systemBars(), false, null, null, 0, 0);
129     }
130 
131     /**
132      * Construct a new WindowInsets from individual insets.
133      *
134      * {@code typeInsetsMap} and {@code typeMaxInsetsMap} are a map of indexOf(type) -> insets that
135      * contain the information what kind of system bars causes how much insets. The insets in this
136      * map are non-additive; i.e. they have the same origin. In other words: If two system bars
137      * overlap on one side, the insets of the larger bar will also include the insets of the smaller
138      * bar.
139      *
140      * {@code null} type inset map indicates that the respective inset is fully consumed.
141      * @hide
142      */
WindowInsets(@ullable Insets[] typeInsetsMap, @Nullable Insets[] typeMaxInsetsMap, boolean[] typeVisibilityMap, boolean isRound, @InsetsType int forceConsumingTypes, boolean forceConsumingOpaqueCaptionBar, @InsetsType int suppressScrimTypes, DisplayCutout displayCutout, RoundedCorners roundedCorners, PrivacyIndicatorBounds privacyIndicatorBounds, DisplayShape displayShape, @InsetsType int compatInsetsTypes, boolean compatIgnoreVisibility, Rect[][] typeBoundingRectsMap, Rect[][] typeMaxBoundingRectsMap, int frameWidth, int frameHeight)143     public WindowInsets(@Nullable Insets[] typeInsetsMap,
144             @Nullable Insets[] typeMaxInsetsMap,
145             boolean[] typeVisibilityMap,
146             boolean isRound,
147             @InsetsType int forceConsumingTypes,
148             boolean forceConsumingOpaqueCaptionBar,
149             @InsetsType int suppressScrimTypes,
150             DisplayCutout displayCutout,
151             RoundedCorners roundedCorners,
152             PrivacyIndicatorBounds privacyIndicatorBounds,
153             DisplayShape displayShape,
154             @InsetsType int compatInsetsTypes, boolean compatIgnoreVisibility,
155             Rect[][] typeBoundingRectsMap,
156             Rect[][] typeMaxBoundingRectsMap,
157             int frameWidth, int frameHeight) {
158         mSystemWindowInsetsConsumed = typeInsetsMap == null;
159         mTypeInsetsMap = mSystemWindowInsetsConsumed
160                 ? new Insets[SIZE]
161                 : typeInsetsMap.clone();
162 
163         mStableInsetsConsumed = typeMaxInsetsMap == null;
164         mTypeMaxInsetsMap = mStableInsetsConsumed
165                 ? new Insets[SIZE]
166                 : typeMaxInsetsMap.clone();
167 
168         mTypeVisibilityMap = typeVisibilityMap;
169         mIsRound = isRound;
170         mForceConsumingTypes = forceConsumingTypes;
171         mForceConsumingOpaqueCaptionBar = forceConsumingOpaqueCaptionBar;
172         mSuppressScrimTypes = suppressScrimTypes;
173         mCompatInsetsTypes = compatInsetsTypes;
174         mCompatIgnoreVisibility = compatIgnoreVisibility;
175 
176         mDisplayCutoutConsumed = displayCutout == null;
177         mDisplayCutout = (mDisplayCutoutConsumed || displayCutout.isEmpty())
178                 ? null : displayCutout;
179 
180         mRoundedCorners = roundedCorners;
181         mPrivacyIndicatorBounds = privacyIndicatorBounds;
182         mDisplayShape = displayShape;
183         mTypeBoundingRectsMap = (mSystemWindowInsetsConsumed || typeBoundingRectsMap == null)
184                 ? new Rect[SIZE][]
185                 : typeBoundingRectsMap.clone();
186         mTypeMaxBoundingRectsMap = (mStableInsetsConsumed || typeMaxBoundingRectsMap == null)
187                 ? new Rect[SIZE][]
188                 : typeMaxBoundingRectsMap.clone();
189         mFrameWidth = frameWidth;
190         mFrameHeight = frameHeight;
191     }
192 
193     /**
194      * Construct a new WindowInsets, copying all values from a source WindowInsets.
195      *
196      * @param src Source to copy insets from
197      */
WindowInsets(WindowInsets src)198     public WindowInsets(WindowInsets src) {
199         this(src.mSystemWindowInsetsConsumed ? null : src.mTypeInsetsMap,
200                 src.mStableInsetsConsumed ? null : src.mTypeMaxInsetsMap,
201                 src.mTypeVisibilityMap, src.mIsRound,
202                 src.mForceConsumingTypes,
203                 src.mForceConsumingOpaqueCaptionBar,
204                 src.mSuppressScrimTypes,
205                 displayCutoutCopyConstructorArgument(src),
206                 src.mRoundedCorners,
207                 src.mPrivacyIndicatorBounds,
208                 src.mDisplayShape,
209                 src.mCompatInsetsTypes,
210                 src.mCompatIgnoreVisibility,
211                 src.mSystemWindowInsetsConsumed ? null : src.mTypeBoundingRectsMap,
212                 src.mStableInsetsConsumed ? null : src.mTypeMaxBoundingRectsMap,
213                 src.mFrameWidth,
214                 src.mFrameHeight);
215     }
216 
displayCutoutCopyConstructorArgument(WindowInsets w)217     private static DisplayCutout displayCutoutCopyConstructorArgument(WindowInsets w) {
218         if (w.mDisplayCutoutConsumed) {
219             return null;
220         } else if (w.mDisplayCutout == null) {
221             return DisplayCutout.NO_CUTOUT;
222         } else {
223             return w.mDisplayCutout;
224         }
225     }
226 
227     /**
228      * @return The insets that include system bars indicated by {@code typeMask}, taken from
229      *         {@code typeInsetsMap}.
230      */
getInsets(Insets[] typeInsetsMap, @InsetsType int typeMask)231     static Insets getInsets(Insets[] typeInsetsMap, @InsetsType int typeMask) {
232         Insets result = null;
233         for (int i = FIRST; i <= LAST; i = i << 1) {
234             if ((typeMask & i) == 0) {
235                 continue;
236             }
237             Insets insets = typeInsetsMap[indexOf(i)];
238             if (insets == null) {
239                 continue;
240             }
241             if (result == null) {
242                 result = insets;
243             } else {
244                 result = Insets.max(result, insets);
245             }
246         }
247         return result == null ? Insets.NONE : result;
248     }
249 
250     /**
251      * Sets all entries in {@code typeInsetsMap} that belong to {@code typeMask} to {@code insets},
252      */
setInsets(Insets[] typeInsetsMap, @InsetsType int typeMask, Insets insets)253     private static void setInsets(Insets[] typeInsetsMap, @InsetsType int typeMask, Insets insets) {
254         for (int i = FIRST; i <= LAST; i = i << 1) {
255             if ((typeMask & i) == 0) {
256                 continue;
257             }
258             typeInsetsMap[indexOf(i)] = insets;
259         }
260     }
261 
262     /** @hide */
263     @UnsupportedAppUsage
WindowInsets(Rect systemWindowInsets)264     public WindowInsets(Rect systemWindowInsets) {
265         this(createCompatTypeMap(systemWindowInsets), null, new boolean[SIZE], false, 0, false, 0,
266                 null, null, null, null, systemBars(), false /* compatIgnoreVisibility */,
267                 new Rect[SIZE][], null, 0, 0);
268     }
269 
270     /**
271      * Creates a indexOf(type) -> inset map for which the {@code insets} is just mapped to
272      * {@link Type#statusBars()} and {@link Type#navigationBars()}, depending on the
273      * location of the inset.
274      *
275      * @hide
276      */
277     @VisibleForTesting
createCompatTypeMap(@ullable Rect insets)278     public static Insets[] createCompatTypeMap(@Nullable Rect insets) {
279         if (insets == null) {
280             return null;
281         }
282         Insets[] typeInsetsMap = new Insets[SIZE];
283         assignCompatInsets(typeInsetsMap, insets);
284         return typeInsetsMap;
285     }
286 
287     /**
288      * @hide
289      */
290     @VisibleForTesting
assignCompatInsets(Insets[] typeInsetsMap, Rect insets)291     public static void assignCompatInsets(Insets[] typeInsetsMap, Rect insets) {
292         typeInsetsMap[indexOf(STATUS_BARS)] = Insets.of(0, insets.top, 0, 0);
293         typeInsetsMap[indexOf(NAVIGATION_BARS)] =
294                 Insets.of(insets.left, 0, insets.right, insets.bottom);
295     }
296 
297     /**
298      * @hide
299      */
300     @VisibleForTesting
createCompatVisibilityMap(@ullable Insets[] typeInsetsMap)301     private static boolean[] createCompatVisibilityMap(@Nullable Insets[] typeInsetsMap) {
302         boolean[] typeVisibilityMap = new boolean[SIZE];
303         if (typeInsetsMap == null) {
304             return typeVisibilityMap;
305         }
306         for (int i = FIRST; i <= LAST; i = i << 1) {
307             int index = indexOf(i);
308             if (!Insets.NONE.equals(typeInsetsMap[index])) {
309                 typeVisibilityMap[index] = true;
310             }
311         }
312         return typeVisibilityMap;
313     }
314 
315     /**
316      * Used to provide a safe copy of the system window insets to pass through
317      * to the existing fitSystemWindows method and other similar internals.
318      * @hide
319      *
320      * @deprecated use {@link #getSystemWindowInsets()} instead.
321      */
322     @Deprecated
323     @NonNull
getSystemWindowInsetsAsRect()324     public Rect getSystemWindowInsetsAsRect() {
325         if (mTempRect == null) {
326             mTempRect = new Rect();
327         }
328         Insets insets = getSystemWindowInsets();
329         mTempRect.set(insets.left, insets.top, insets.right, insets.bottom);
330         return mTempRect;
331     }
332 
333     /**
334      * Returns the system window insets in pixels.
335      *
336      * <p>The system window inset represents the area of a full-screen window that is
337      * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
338      * </p>
339      *
340      * @return The system window insets
341      * @deprecated Use {@link #getInsets(int)} with {@link Type#systemBars()}
342      * instead.
343      */
344     @Deprecated
345     @NonNull
getSystemWindowInsets()346     public Insets getSystemWindowInsets() {
347         Insets result = mCompatIgnoreVisibility
348                 ? getInsetsIgnoringVisibility(mCompatInsetsTypes & ~ime())
349                 : getInsets(mCompatInsetsTypes);
350 
351         // We can't query max insets for IME, so we need to add it manually after.
352         if ((mCompatInsetsTypes & ime()) != 0 && mCompatIgnoreVisibility) {
353             result = Insets.max(result, getInsets(ime()));
354         }
355         return result;
356     }
357 
358     /**
359      * Returns the insets of a specific set of windows causing insets, denoted by the
360      * {@code typeMask} bit mask of {@link Type}s.
361      *
362      * @param typeMask Bit mask of {@link Type}s to query the insets for.
363      * @return The insets.
364      */
365     @NonNull
getInsets(@nsetsType int typeMask)366     public Insets getInsets(@InsetsType int typeMask) {
367         return getInsets(mTypeInsetsMap, typeMask);
368     }
369 
370     /**
371      * Returns the insets a specific set of windows can cause, denoted by the
372      * {@code typeMask} bit mask of {@link Type}s, regardless of whether that type is
373      * currently visible or not.
374      *
375      * <p>The insets represents the area of a a window that that <b>may</b> be partially
376      * or fully obscured by the system window identified by {@code type}. This value does not
377      * change based on the visibility state of those elements. For example, if the status bar is
378      * normally shown, but temporarily hidden, the inset returned here will still provide the inset
379      * associated with the status bar being shown.</p>
380      *
381      * @param typeMask Bit mask of {@link Type}s to query the insets for.
382      * @return The insets.
383      *
384      * @throws IllegalArgumentException If the caller tries to query {@link Type#ime()}. Insets are
385      *                                  not available if the IME isn't visible as the height of the
386      *                                  IME is dynamic depending on the {@link EditorInfo} of the
387      *                                  currently focused view, as well as the UI state of the IME.
388      */
389     @NonNull
getInsetsIgnoringVisibility(@nsetsType int typeMask)390     public Insets getInsetsIgnoringVisibility(@InsetsType int typeMask) {
391         if ((typeMask & IME) != 0) {
392             throw new IllegalArgumentException("Unable to query the maximum insets for IME");
393         }
394         return getInsets(mTypeMaxInsetsMap, typeMask);
395     }
396 
397     /**
398      * Returns whether a set of windows that may cause insets is currently visible on screen,
399      * regardless of whether it actually overlaps with this window.
400      *
401      * @param typeMask Bit mask of {@link Type}s to query visibility status.
402      * @return {@code true} if and only if all windows included in {@code typeMask} are currently
403      *         visible on screen.
404      */
isVisible(@nsetsType int typeMask)405     public boolean isVisible(@InsetsType int typeMask) {
406         for (int i = FIRST; i <= LAST; i = i << 1) {
407             if ((typeMask & i) == 0) {
408                 continue;
409             }
410             if (!mTypeVisibilityMap[indexOf(i)]) {
411                 return false;
412             }
413         }
414         return true;
415     }
416 
417     /**
418      * Returns the left system window inset in pixels.
419      *
420      * <p>The system window inset represents the area of a full-screen window that is
421      * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
422      * </p>
423      *
424      * @return The left system window inset
425      * @deprecated Use {@link #getInsets(int)} with {@link Type#systemBars()}
426      * instead.
427      */
428     @Deprecated
getSystemWindowInsetLeft()429     public int getSystemWindowInsetLeft() {
430         return getSystemWindowInsets().left;
431     }
432 
433     /**
434      * Returns the top system window inset in pixels.
435      *
436      * <p>The system window inset represents the area of a full-screen window that is
437      * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
438      * </p>
439      *
440      * @return The top system window inset
441      * @deprecated Use {@link #getInsets(int)} with {@link Type#systemBars()}
442      * instead.
443      */
444     @Deprecated
getSystemWindowInsetTop()445     public int getSystemWindowInsetTop() {
446         return getSystemWindowInsets().top;
447     }
448 
449     /**
450      * Returns the right system window inset in pixels.
451      *
452      * <p>The system window inset represents the area of a full-screen window that is
453      * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
454      * </p>
455      *
456      * @return The right system window inset
457      * @deprecated Use {@link #getInsets(int)} with {@link Type#systemBars()}
458      * instead.
459      */
460     @Deprecated
getSystemWindowInsetRight()461     public int getSystemWindowInsetRight() {
462         return getSystemWindowInsets().right;
463     }
464 
465     /**
466      * Returns the bottom system window inset in pixels.
467      *
468      * <p>The system window inset represents the area of a full-screen window that is
469      * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
470      * </p>
471      *
472      * @return The bottom system window inset
473      * @deprecated Use {@link #getInsets(int)} with {@link Type#systemBars()}
474      * instead.
475      */
476     @Deprecated
getSystemWindowInsetBottom()477     public int getSystemWindowInsetBottom() {
478         return getSystemWindowInsets().bottom;
479     }
480 
481     /**
482      * Returns true if this WindowInsets has nonzero system window insets.
483      *
484      * <p>The system window inset represents the area of a full-screen window that is
485      * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
486      * </p>
487      *
488      * @return true if any of the system window inset values are nonzero
489      * @deprecated Use {@link #getInsets(int)} with {@link Type#systemBars()}
490      * instead.
491      */
492     @Deprecated
hasSystemWindowInsets()493     public boolean hasSystemWindowInsets() {
494         return !getSystemWindowInsets().equals(Insets.NONE);
495     }
496 
497     /**
498      * Returns true if this WindowInsets has any nonzero insets.
499      *
500      * @return true if any inset values are nonzero
501      */
hasInsets()502     public boolean hasInsets() {
503         return !getInsets(mTypeInsetsMap, all()).equals(Insets.NONE)
504                 || !getInsets(mTypeMaxInsetsMap, all()).equals(Insets.NONE)
505                 || mDisplayCutout != null || mRoundedCorners != null;
506     }
507 
508     /**
509      * Returns a list of {@link Rect}s, each of which is the bounding rectangle for an area
510      * that is being partially or fully obscured inside the window.
511      *
512      * <p>
513      * May be used with or instead of {@link Insets} for finer avoidance of regions that may be
514      * partially obscuring the window but may be smaller than those provided by
515      * {@link #getInsets(int)}.
516      * </p>
517      *
518      * <p>
519      * The {@link Rect}s returned are always cropped to the bounds of the window frame and their
520      * coordinate values are relative to the {@link #getFrame()}, regardless of the window's
521      * position on screen.
522      * </p>
523      *
524      * <p>
525      * If inset by {@link #inset(Insets)}, bounding rects that intersect with the provided insets
526      * will be resized to only include the intersection with the remaining frame. Bounding rects
527      * may be completely removed if they no longer intersect with the new instance.
528      * </p>
529      *
530      * @param typeMask the insets type for which to obtain the bounding rectangles
531      * @return the bounding rectangles
532      */
533     @FlaggedApi(Flags.FLAG_CUSTOMIZABLE_WINDOW_HEADERS)
534     @NonNull
getBoundingRects(@nsetsType int typeMask)535     public List<Rect> getBoundingRects(@InsetsType int typeMask) {
536         return getBoundingRects(mTypeBoundingRectsMap, typeMask);
537     }
538 
539     /**
540      * Returns a list of {@link Rect}s, each of which is the bounding rectangle for an area that
541      * can be partially or fully obscured inside the window, regardless of whether
542      * that type is currently visible or not.
543      *
544      * <p> The bounding rects represent areas of a window that <b>may</b> be partially or fully
545      * obscured by the {@code type}. This value does not change based on the visibility state of
546      * those elements. For example, if the status bar is normally shown, but temporarily hidden,
547      * the bounding rects returned here will provide the rects associated with the status bar being
548      * shown.</p>
549      *
550      * <p>
551      * May be used with or instead of {@link Insets} for finer avoidance of regions that may be
552      * partially obscuring the window but may be smaller than those provided by
553      * {@link #getInsetsIgnoringVisibility(int)}.
554      * </p>
555      *
556      * <p>
557      * The {@link Rect}s returned are always cropped to the bounds of the window frame and their
558      * coordinate values are relative to the {@link #getFrame()}, regardless of the window's
559      * position on screen.
560      * </p>
561      *
562      * @param typeMask the insets type for which to obtain the bounding rectangles
563      * @return the bounding rectangles
564      * @throws IllegalArgumentException If the caller tries to query {@link Type#ime()}. Bounding
565      *                                  rects are not available if the IME isn't visible as the
566      *                                  height of the IME is dynamic depending on the
567      *                                  {@link EditorInfo} of the currently focused view, as well
568      *                                  as the UI state of the IME.
569      */
570     @FlaggedApi(Flags.FLAG_CUSTOMIZABLE_WINDOW_HEADERS)
571     @NonNull
getBoundingRectsIgnoringVisibility(@nsetsType int typeMask)572     public List<Rect> getBoundingRectsIgnoringVisibility(@InsetsType int typeMask) {
573         if ((typeMask & IME) != 0) {
574             throw new IllegalArgumentException("Unable to query the bounding rects for IME");
575         }
576         return getBoundingRects(mTypeMaxBoundingRectsMap, typeMask);
577     }
578 
getBoundingRects(Rect[][] typeBoundingRectsMap, @InsetsType int typeMask)579     private List<Rect> getBoundingRects(Rect[][] typeBoundingRectsMap, @InsetsType int typeMask) {
580         Rect[] allRects = null;
581         for (int i = FIRST; i <= LAST; i = i << 1) {
582             if ((typeMask & i) == 0) {
583                 continue;
584             }
585             final Rect[] rects = typeBoundingRectsMap[indexOf(i)];
586             if (rects == null) {
587                 continue;
588             }
589             if (allRects == null) {
590                 allRects = rects;
591             } else {
592                 final Rect[] concat = new Rect[allRects.length + rects.length];
593                 System.arraycopy(allRects, 0, concat, 0, allRects.length);
594                 System.arraycopy(rects, 0, concat, allRects.length, rects.length);
595                 allRects = concat;
596             }
597         }
598         if (allRects == null) {
599             return Collections.emptyList();
600         }
601         return Arrays.asList(allRects);
602     }
603 
604     /**
605      * Returns the display cutout if there is one.
606      *
607      * <p>Note: the display cutout will already be {@link #consumeDisplayCutout consumed} during
608      * dispatch to {@link View#onApplyWindowInsets}, unless the window has requested a
609      * {@link WindowManager.LayoutParams#layoutInDisplayCutoutMode} other than
610      * {@link WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER never} or
611      * {@link WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT default}.
612      *
613      * @return the display cutout or null if there is none
614      * @see DisplayCutout
615      */
616     @Nullable
getDisplayCutout()617     public DisplayCutout getDisplayCutout() {
618         return mDisplayCutout;
619     }
620 
621     /**
622      * Returns the {@link RoundedCorner} of the given position if there is one.
623      *
624      * @param position the position of the rounded corner on the display. The value should be one of
625      *                 the following:
626      *                 {@link RoundedCorner#POSITION_TOP_LEFT},
627      *                 {@link RoundedCorner#POSITION_TOP_RIGHT},
628      *                 {@link RoundedCorner#POSITION_BOTTOM_RIGHT},
629      *                 {@link RoundedCorner#POSITION_BOTTOM_LEFT}.
630      * @return the rounded corner of the given position. Returns {@code null} if there is none or
631      *         the rounded corner area is not inside the application's bounds.
632      */
633     @Nullable
getRoundedCorner(@oundedCorner.Position int position)634     public RoundedCorner getRoundedCorner(@RoundedCorner.Position int position) {
635         return mRoundedCorners == null ? null : mRoundedCorners.getRoundedCorner(position);
636     }
637 
638     /**
639      * Returns the {@link Rect} of the maximum bounds of the system privacy indicator, for the
640      * current orientation, in relative coordinates, or null if the bounds have not been loaded yet.
641      * <p>
642      * The privacy indicator bounds are determined by SystemUI, and subsequently loaded once the
643      * StatusBar window has been created and attached. The bounds for all rotations are calculated
644      * and loaded at once, and this value is only expected to ever change on display or font scale
645      * changes. As long as there is a StatusBar window, this value should not be expected to be
646      * null.
647      * <p>
648      * The privacy indicator shows over apps when an app uses the microphone or camera permissions,
649      * while an app is in immersive mode.
650      *
651      * @return A rectangle representing the maximum bounds of the indicator
652      */
getPrivacyIndicatorBounds()653     public @Nullable Rect getPrivacyIndicatorBounds() {
654         return mPrivacyIndicatorBounds == null ? null
655                 : mPrivacyIndicatorBounds.getStaticPrivacyIndicatorBounds();
656     }
657 
658     /**
659      * Returns the display shape in the coordinate space of the window.
660      *
661      * @return the display shape
662      * @see DisplayShape
663      */
664     @Nullable
getDisplayShape()665     public DisplayShape getDisplayShape() {
666         return mDisplayShape;
667     }
668 
669     /**
670      * Returns a copy of this WindowInsets with the cutout fully consumed.
671      *
672      * @return A modified copy of this WindowInsets
673      * @deprecated Consuming of different parts individually of a {@link WindowInsets} instance is
674      * deprecated, since {@link WindowInsets} contains many different insets. Use {@link #CONSUMED}
675      * instead to stop dispatching insets.
676      */
677     @Deprecated
678     @NonNull
consumeDisplayCutout()679     public WindowInsets consumeDisplayCutout() {
680         return new WindowInsets(mSystemWindowInsetsConsumed ? null : mTypeInsetsMap,
681                 mStableInsetsConsumed ? null : mTypeMaxInsetsMap,
682                 mTypeVisibilityMap,
683                 mIsRound, mForceConsumingTypes, mForceConsumingOpaqueCaptionBar,
684                 mSuppressScrimTypes, null /* displayCutout */, mRoundedCorners,
685                 mPrivacyIndicatorBounds, mDisplayShape, mCompatInsetsTypes,
686                 mCompatIgnoreVisibility, mSystemWindowInsetsConsumed ? null : mTypeBoundingRectsMap,
687                 mStableInsetsConsumed ? null : mTypeMaxBoundingRectsMap,
688                 mFrameWidth, mFrameHeight);
689     }
690 
691 
692     /**
693      * Check if these insets have been fully consumed.
694      *
695      * <p>Insets are considered "consumed" if the applicable <code>consume*</code> methods
696      * have been called such that all insets have been set to zero. This affects propagation of
697      * insets through the view hierarchy; insets that have not been fully consumed will continue
698      * to propagate down to child views.</p>
699      *
700      * <p>The result of this method is equivalent to the return value of
701      * {@link View#fitSystemWindows(android.graphics.Rect)}.</p>
702      *
703      * @return true if the insets have been fully consumed.
704      */
isConsumed()705     public boolean isConsumed() {
706         return mSystemWindowInsetsConsumed && mStableInsetsConsumed
707                 && mDisplayCutoutConsumed;
708     }
709 
710     /**
711      * Returns true if the associated window has a round shape.
712      *
713      * <p>A round window's left, top, right and bottom edges reach all the way to the
714      * associated edges of the window but the corners may not be visible. Views responding
715      * to round insets should take care to not lay out critical elements within the corners
716      * where they may not be accessible.</p>
717      *
718      * @return True if the window is round
719      */
isRound()720     public boolean isRound() {
721         return mIsRound;
722     }
723 
724     /**
725      * Returns a copy of this WindowInsets with the system window insets fully consumed.
726      *
727      * @return A modified copy of this WindowInsets
728      * @deprecated Consuming of different parts individually of a {@link WindowInsets} instance is
729      * deprecated, since {@link WindowInsets} contains many different insets. Use {@link #CONSUMED}
730      * instead to stop dispatching insets.
731      */
732     @Deprecated
733     @NonNull
consumeSystemWindowInsets()734     public WindowInsets consumeSystemWindowInsets() {
735         return new WindowInsets(null, null,
736                 mTypeVisibilityMap,
737                 mIsRound, mForceConsumingTypes, mForceConsumingOpaqueCaptionBar,
738                 mSuppressScrimTypes,
739                 // If the system window insets types contain displayCutout, we should also consume
740                 // it.
741                 (mCompatInsetsTypes & displayCutout()) != 0
742                         ? null : displayCutoutCopyConstructorArgument(this),
743                 mRoundedCorners, mPrivacyIndicatorBounds, mDisplayShape, mCompatInsetsTypes,
744                 mCompatIgnoreVisibility, null, null, mFrameWidth, mFrameHeight);
745     }
746 
747     // TODO(b/119190588): replace @code with @link below
748     /**
749      * Returns a copy of this WindowInsets with selected system window insets replaced
750      * with new values.
751      *
752      * <p>Note: If the system window insets are already consumed, this method will return them
753      * unchanged on {@link android.os.Build.VERSION_CODES#Q Q} and later. Prior to
754      * {@link android.os.Build.VERSION_CODES#Q Q}, the new values were applied regardless of
755      * whether they were consumed, and this method returns invalid non-zero consumed insets.
756      *
757      * @param left New left inset in pixels
758      * @param top New top inset in pixels
759      * @param right New right inset in pixels
760      * @param bottom New bottom inset in pixels
761      * @return A modified copy of this WindowInsets
762      * @deprecated use {@code Builder#Builder(WindowInsets)} with
763      *             {@link Builder#setSystemWindowInsets(Insets)} instead.
764      */
765     @Deprecated
766     @NonNull
replaceSystemWindowInsets(int left, int top, int right, int bottom)767     public WindowInsets replaceSystemWindowInsets(int left, int top, int right, int bottom) {
768         // Compat edge case: what should this do if the insets have already been consumed?
769         // On platforms prior to Q, the behavior was to override the insets with non-zero values,
770         // but leave them consumed, which is invalid (consumed insets must be zero).
771         // The behavior is now keeping them consumed and discarding the new insets.
772         if (mSystemWindowInsetsConsumed) {
773             return this;
774         }
775         return new Builder(this).setSystemWindowInsets(Insets.of(left, top, right, bottom)).build();
776     }
777 
778     // TODO(b/119190588): replace @code with @link below
779     /**
780      * Returns a copy of this WindowInsets with selected system window insets replaced
781      * with new values.
782      *
783      * <p>Note: If the system window insets are already consumed, this method will return them
784      * unchanged on {@link android.os.Build.VERSION_CODES#Q Q} and later. Prior to
785      * {@link android.os.Build.VERSION_CODES#Q Q}, the new values were applied regardless of
786      * whether they were consumed, and this method returns invalid non-zero consumed insets.
787      *
788      * @param systemWindowInsets New system window insets. Each field is the inset in pixels
789      *                           for that edge
790      * @return A modified copy of this WindowInsets
791      * @deprecated use {@code Builder#Builder(WindowInsets)} with
792      *             {@link Builder#setSystemWindowInsets(Insets)} instead.
793      */
794     @Deprecated
795     @NonNull
replaceSystemWindowInsets(Rect systemWindowInsets)796     public WindowInsets replaceSystemWindowInsets(Rect systemWindowInsets) {
797         return replaceSystemWindowInsets(systemWindowInsets.left, systemWindowInsets.top,
798                 systemWindowInsets.right, systemWindowInsets.bottom);
799     }
800 
801     /**
802      * Returns the stable insets in pixels.
803      *
804      * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
805      * partially or fully obscured by the system UI elements.  This value does not change
806      * based on the visibility state of those elements; for example, if the status bar is
807      * normally shown, but temporarily hidden, the stable inset will still provide the inset
808      * associated with the status bar being shown.</p>
809      *
810      * @return The stable insets
811      * @deprecated Use {@link #getInsetsIgnoringVisibility(int)} with {@link Type#systemBars()}
812      * instead.
813      */
814     @Deprecated
815     @NonNull
getStableInsets()816     public Insets getStableInsets() {
817         return getInsets(mTypeMaxInsetsMap, systemBars());
818     }
819 
820     /**
821      * Returns the top stable inset in pixels.
822      *
823      * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
824      * partially or fully obscured by the system UI elements.  This value does not change
825      * based on the visibility state of those elements; for example, if the status bar is
826      * normally shown, but temporarily hidden, the stable inset will still provide the inset
827      * associated with the status bar being shown.</p>
828      *
829      * @return The top stable inset
830      * @deprecated Use {@link #getInsetsIgnoringVisibility(int)} with {@link Type#systemBars()}
831      * instead.
832      */
833     @Deprecated
getStableInsetTop()834     public int getStableInsetTop() {
835         return getStableInsets().top;
836     }
837 
838     /**
839      * Returns the left stable inset in pixels.
840      *
841      * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
842      * partially or fully obscured by the system UI elements.  This value does not change
843      * based on the visibility state of those elements; for example, if the status bar is
844      * normally shown, but temporarily hidden, the stable inset will still provide the inset
845      * associated with the status bar being shown.</p>
846      *
847      * @return The left stable inset
848      * @deprecated Use {@link #getInsetsIgnoringVisibility(int)} with {@link Type#systemBars()}
849      * instead.
850      */
851     @Deprecated
getStableInsetLeft()852     public int getStableInsetLeft() {
853         return getStableInsets().left;
854     }
855 
856     /**
857      * Returns the right stable inset in pixels.
858      *
859      * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
860      * partially or fully obscured by the system UI elements.  This value does not change
861      * based on the visibility state of those elements; for example, if the status bar is
862      * normally shown, but temporarily hidden, the stable inset will still provide the inset
863      * associated with the status bar being shown.</p>
864      *
865      * @return The right stable inset
866      * @deprecated Use {@link #getInsetsIgnoringVisibility(int)} with {@link Type#systemBars()}
867      * instead.
868      */
869     @Deprecated
getStableInsetRight()870     public int getStableInsetRight() {
871         return getStableInsets().right;
872     }
873 
874     /**
875      * Returns the bottom stable inset in pixels.
876      *
877      * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
878      * partially or fully obscured by the system UI elements.  This value does not change
879      * based on the visibility state of those elements; for example, if the status bar is
880      * normally shown, but temporarily hidden, the stable inset will still provide the inset
881      * associated with the status bar being shown.</p>
882      *
883      * @return The bottom stable inset
884      * @deprecated Use {@link #getInsetsIgnoringVisibility(int)} with {@link Type#systemBars()}
885      * instead.
886      */
887     @Deprecated
getStableInsetBottom()888     public int getStableInsetBottom() {
889         return getStableInsets().bottom;
890     }
891 
892     /**
893      * Returns true if this WindowInsets has nonzero stable insets.
894      *
895      * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
896      * partially or fully obscured by the system UI elements.  This value does not change
897      * based on the visibility state of those elements; for example, if the status bar is
898      * normally shown, but temporarily hidden, the stable inset will still provide the inset
899      * associated with the status bar being shown.</p>
900      *
901      * @return true if any of the stable inset values are nonzero
902      * @deprecated Use {@link #getInsetsIgnoringVisibility(int)} with {@link Type#systemBars()}
903      * instead.
904      */
905     @Deprecated
hasStableInsets()906     public boolean hasStableInsets() {
907         return !getStableInsets().equals(Insets.NONE);
908     }
909 
910     /**
911      * Returns the system gesture insets.
912      *
913      * <p>The system gesture insets represent the area of a window where system gestures have
914      * priority and may consume some or all touch input, e.g. due to the a system bar
915      * occupying it, or it being reserved for touch-only gestures.
916      *
917      * <p>An app can declare priority over system gestures with
918      * {@link View#setSystemGestureExclusionRects} outside of the
919      * {@link #getMandatorySystemGestureInsets() mandatory system gesture insets}.
920      *
921      * <p>Note: the system will put a limit of <code>200dp</code> on the vertical extent of the
922      * exclusions it takes into account. The limit does not apply while the navigation
923      * bar is {@link View#SYSTEM_UI_FLAG_IMMERSIVE_STICKY stickily} hidden, nor to the
924      * {@link android.inputmethodservice.InputMethodService input method} and
925      * {@link Intent#CATEGORY_HOME home activity}.
926      * </p>
927      *
928      *
929      * <p>Simple taps are guaranteed to reach the window even within the system gesture insets,
930      * as long as they are outside the {@link #getTappableElementInsets() system window insets}.
931      *
932      * <p>When {@link View#SYSTEM_UI_FLAG_LAYOUT_STABLE} is requested, an inset will be returned
933      * even when the system gestures are inactive due to
934      * {@link View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} or
935      * {@link View#SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}.
936      *
937      * <p>This inset is consumed together with the {@link #getSystemWindowInsets()
938      * system window insets} by {@link #consumeSystemWindowInsets()}.
939      *
940      * @see #getMandatorySystemGestureInsets
941      * @deprecated Use {@link #getInsets(int)} with {@link Type#systemGestures()} instead.
942      */
943     @Deprecated
944     @NonNull
getSystemGestureInsets()945     public Insets getSystemGestureInsets() {
946         return getInsets(mTypeInsetsMap, SYSTEM_GESTURES);
947     }
948 
949     /**
950      * Returns the mandatory system gesture insets.
951      *
952      * <p>The mandatory system gesture insets represent the area of a window where mandatory system
953      * gestures have priority and may consume some or all touch input, e.g. due to the a system bar
954      * occupying it, or it being reserved for touch-only gestures.
955      *
956      * <p>In contrast to {@link #getSystemGestureInsets regular system gestures}, <b>mandatory</b>
957      * system gestures cannot be overriden by {@link View#setSystemGestureExclusionRects}.
958      *
959      * <p>Simple taps are guaranteed to reach the window even within the system gesture insets,
960      * as long as they are outside the {@link #getTappableElementInsets() system window insets}.
961      *
962      * <p>When {@link View#SYSTEM_UI_FLAG_LAYOUT_STABLE} is requested, an inset will be returned
963      * even when the system gestures are inactive due to
964      * {@link View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} or
965      * {@link View#SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}.
966      *
967      * <p>This inset is consumed together with the {@link #getSystemWindowInsets()
968      * system window insets} by {@link #consumeSystemWindowInsets()}.
969      *
970      * @see #getSystemGestureInsets
971      * @deprecated Use {@link #getInsets(int)} with {@link Type#mandatorySystemGestures()} instead.
972      */
973     @Deprecated
974     @NonNull
getMandatorySystemGestureInsets()975     public Insets getMandatorySystemGestureInsets() {
976         return getInsets(mTypeInsetsMap, MANDATORY_SYSTEM_GESTURES);
977     }
978 
979     /**
980      * Returns the tappable element insets.
981      *
982      * <p>The tappable element insets represent how much tappable elements <b>must at least</b> be
983      * inset to remain both tappable and visually unobstructed by persistent system windows.
984      *
985      * <p>This may be smaller than {@link #getSystemWindowInsets()} if the system window is
986      * largely transparent and lets through simple taps (but not necessarily more complex gestures).
987      *
988      * <p>Note that generally, tappable elements <strong>should</strong> be aligned with the
989      * {@link #getSystemWindowInsets() system window insets} instead to avoid overlapping with the
990      * system bars.
991      *
992      * <p>When {@link View#SYSTEM_UI_FLAG_LAYOUT_STABLE} is requested, an inset will be returned
993      * even when the area covered by the inset would be tappable due to
994      * {@link View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} or
995      * {@link View#SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}.
996      *
997      * <p>This inset is consumed together with the {@link #getSystemWindowInsets()
998      * system window insets} by {@link #consumeSystemWindowInsets()}.
999      *
1000      * @deprecated Use {@link #getInsets(int)} with {@link Type#tappableElement()} instead.
1001      */
1002     @Deprecated
1003     @NonNull
getTappableElementInsets()1004     public Insets getTappableElementInsets() {
1005         return getInsets(mTypeInsetsMap, TAPPABLE_ELEMENT);
1006     }
1007 
1008     /**
1009      * Returns a copy of this WindowInsets with the stable insets fully consumed.
1010      *
1011      * @return A modified copy of this WindowInsets
1012      * @deprecated Consuming of different parts individually of a {@link WindowInsets} instance is
1013      * deprecated, since {@link WindowInsets} contains many different insets. Use {@link #CONSUMED}
1014      * instead to stop dispatching insets. On {@link android.os.Build.VERSION_CODES#R R}, this
1015      * method has no effect.
1016      */
1017     @Deprecated
1018     @NonNull
consumeStableInsets()1019     public WindowInsets consumeStableInsets() {
1020         return this;
1021     }
1022 
1023     /**
1024      * @hide
1025      */
getForceConsumingTypes()1026     public @InsetsType int getForceConsumingTypes() {
1027         return mForceConsumingTypes;
1028     }
1029 
1030     /**
1031      * @hide
1032      */
isForceConsumingOpaqueCaptionBar()1033     public boolean isForceConsumingOpaqueCaptionBar() {
1034         return mForceConsumingOpaqueCaptionBar;
1035     }
1036 
1037     /**
1038      * @hide
1039      */
getSuppressScrimTypes()1040     public @InsetsType int getSuppressScrimTypes() {
1041         return mSuppressScrimTypes;
1042     }
1043 
1044     @Override
toString()1045     public String toString() {
1046         StringBuilder result = new StringBuilder("WindowInsets{\n    ");
1047         for (int i = 0; i < SIZE; i++) {
1048             Insets insets = mTypeInsetsMap[i];
1049             Insets maxInsets = mTypeMaxInsetsMap[i];
1050             boolean visible = mTypeVisibilityMap[i];
1051             if (!Insets.NONE.equals(insets) || !Insets.NONE.equals(maxInsets) || visible) {
1052                 result.append(Type.toString(1 << i)).append("=").append(insets)
1053                         .append(" max=").append(maxInsets)
1054                         .append(" vis=").append(visible)
1055                         .append(" boundingRects=")
1056                         .append(Arrays.toString(mTypeBoundingRectsMap[i]))
1057                         .append(" maxBoundingRects=")
1058                         .append(Arrays.toString(mTypeMaxBoundingRectsMap[i]))
1059                         .append("\n    ");
1060             }
1061         }
1062 
1063         result.append(mDisplayCutout != null ? "cutout=" + mDisplayCutout : "");
1064         result.append("\n    ");
1065         result.append(mRoundedCorners != null ? "roundedCorners=" + mRoundedCorners : "");
1066         result.append("\n    ");
1067         result.append(mPrivacyIndicatorBounds != null ? "privacyIndicatorBounds="
1068                 + mPrivacyIndicatorBounds : "");
1069         result.append("\n    ");
1070         result.append(mDisplayShape != null ? "displayShape=" + mDisplayShape : "");
1071         result.append("\n    ");
1072         result.append("forceConsumingTypes=" + Type.toString(mForceConsumingTypes));
1073         result.append("\n    ");
1074         result.append("forceConsumingOpaqueCaptionBar=" + mForceConsumingOpaqueCaptionBar);
1075         result.append("\n    ");
1076         result.append("suppressScrimTypes=" + Type.toString(mSuppressScrimTypes));
1077         result.append("\n    ");
1078         result.append("compatInsetsTypes=" + Type.toString(mCompatInsetsTypes));
1079         result.append("\n    ");
1080         result.append("compatIgnoreVisibility=" + mCompatIgnoreVisibility);
1081         result.append("\n    ");
1082         result.append("systemWindowInsetsConsumed=" + mSystemWindowInsetsConsumed);
1083         result.append("\n    ");
1084         result.append("stableInsetsConsumed=" + mStableInsetsConsumed);
1085         result.append("\n    ");
1086         result.append("displayCutoutConsumed=" + mDisplayCutoutConsumed);
1087         result.append("\n    ");
1088         result.append(isRound() ? "round" : "");
1089         result.append("\n    ");
1090         result.append("frameWidth=" + mFrameWidth);
1091         result.append("\n    ");
1092         result.append("frameHeight=" + mFrameHeight);
1093         result.append("}");
1094         return result.toString();
1095     }
1096 
1097     /**
1098      * Returns a copy of this instance inset in the given directions.
1099      *
1100      * @see #inset(int, int, int, int)
1101      * @deprecated use {@link #inset(Insets)}
1102      * @hide
1103      */
1104     @Deprecated
1105     @NonNull
inset(Rect r)1106     public WindowInsets inset(Rect r) {
1107         return inset(r.left, r.top, r.right, r.bottom);
1108     }
1109 
1110     /**
1111      * Returns a copy of this instance inset in the given directions.
1112      *
1113      * This is intended for dispatching insets to areas of the window that are smaller than the
1114      * current area.
1115      *
1116      * <p>Example:
1117      * <pre>
1118      * childView.dispatchApplyWindowInsets(insets.inset(childMargins));
1119      * </pre>
1120      *
1121      * @param insets the amount of insets to remove from all sides.
1122      *
1123      * @see #inset(int, int, int, int)
1124      */
1125     @NonNull
inset(@onNull Insets insets)1126     public WindowInsets inset(@NonNull Insets insets) {
1127         Objects.requireNonNull(insets);
1128         return inset(insets.left, insets.top, insets.right, insets.bottom);
1129     }
1130 
1131     /**
1132      * Returns a copy of this instance inset in the given directions.
1133      *
1134      * This is intended for dispatching insets to areas of the window that are smaller than the
1135      * current area.
1136      *
1137      * <p>Example:
1138      * <pre>
1139      * childView.dispatchApplyWindowInsets(insets.inset(
1140      *         childMarginLeft, childMarginTop, childMarginBottom, childMarginRight));
1141      * </pre>
1142      *
1143      * @param left the amount of insets to remove from the left. Must be non-negative.
1144      * @param top the amount of insets to remove from the top. Must be non-negative.
1145      * @param right the amount of insets to remove from the right. Must be non-negative.
1146      * @param bottom the amount of insets to remove from the bottom. Must be non-negative.
1147      *
1148      * @return the inset insets
1149      *
1150      * @see #inset(Insets)
1151      */
1152     @NonNull
inset(@ntRangefrom = 0) int left, @IntRange(from = 0) int top, @IntRange(from = 0) int right, @IntRange(from = 0) int bottom)1153     public WindowInsets inset(@IntRange(from = 0) int left, @IntRange(from = 0) int top,
1154             @IntRange(from = 0) int right, @IntRange(from = 0) int bottom) {
1155         Preconditions.checkArgumentNonnegative(left);
1156         Preconditions.checkArgumentNonnegative(top);
1157         Preconditions.checkArgumentNonnegative(right);
1158         Preconditions.checkArgumentNonnegative(bottom);
1159 
1160         return insetUnchecked(left, top, right, bottom);
1161     }
1162 
1163     /**
1164      * Returns the assumed size of the window, relative to which the {@link #getInsets} and
1165      * {@link #getBoundingRects} have been calculated.
1166      *
1167      * <p> May be used with {@link #getBoundingRects} to better understand their position within
1168      * the window, such as the area between the edge of a bounding rect and the edge of the window.
1169      *
1170      * <p>Note: the size may not match the actual size of the window, which is determined during
1171      * the layout pass - as {@link WindowInsets} are dispatched before layout.
1172      *
1173      * <p>Caution: using this value in determining the actual window size may make the result of
1174      * layout passes unstable and should be avoided.
1175      *
1176      * @return the assumed size of the window during the inset calculation
1177      */
1178     @FlaggedApi(Flags.FLAG_CUSTOMIZABLE_WINDOW_HEADERS)
1179     @NonNull
getFrame()1180     public Size getFrame() {
1181         return new Size(mFrameWidth, mFrameHeight);
1182     }
1183 
1184     /**
1185      * @see #inset(int, int, int, int)
1186      * @hide
1187      */
1188     @NonNull
insetUnchecked(int left, int top, int right, int bottom)1189     public WindowInsets insetUnchecked(int left, int top, int right, int bottom) {
1190         return new WindowInsets(
1191                 mSystemWindowInsetsConsumed
1192                         ? null
1193                         : insetInsets(mTypeInsetsMap, left, top, right, bottom),
1194                 mStableInsetsConsumed
1195                         ? null
1196                         : insetInsets(mTypeMaxInsetsMap, left, top, right, bottom),
1197                 mTypeVisibilityMap,
1198                 mIsRound, mForceConsumingTypes, mForceConsumingOpaqueCaptionBar,
1199                 mSuppressScrimTypes,
1200                 mDisplayCutoutConsumed
1201                         ? null
1202                         : mDisplayCutout == null
1203                                 ? DisplayCutout.NO_CUTOUT
1204                                 : mDisplayCutout.inset(left, top, right, bottom),
1205                 mRoundedCorners == null
1206                         ? RoundedCorners.NO_ROUNDED_CORNERS
1207                         : mRoundedCorners.inset(left, top, right, bottom),
1208                 mPrivacyIndicatorBounds == null
1209                         ? null
1210                         : mPrivacyIndicatorBounds.inset(left, top, right, bottom),
1211                 mDisplayShape,
1212                 mCompatInsetsTypes, mCompatIgnoreVisibility,
1213                 mSystemWindowInsetsConsumed
1214                         ? null
1215                         : insetBoundingRects(mTypeBoundingRectsMap, left, top, right, bottom,
1216                                 mFrameWidth, mFrameHeight),
1217                 mStableInsetsConsumed
1218                         ? null
1219                         : insetBoundingRects(mTypeMaxBoundingRectsMap, left, top, right, bottom,
1220                                 mFrameWidth, mFrameHeight),
1221                 Math.max(0, mFrameWidth - left - right),
1222                 Math.max(0, mFrameHeight - top - bottom));
1223     }
1224 
1225     @Override
equals(@ullable Object o)1226     public boolean equals(@Nullable Object o) {
1227         if (this == o) return true;
1228         if (o == null || !(o instanceof WindowInsets)) return false;
1229         WindowInsets that = (WindowInsets) o;
1230 
1231         return mIsRound == that.mIsRound
1232                 && mForceConsumingTypes == that.mForceConsumingTypes
1233                 && mForceConsumingOpaqueCaptionBar == that.mForceConsumingOpaqueCaptionBar
1234                 && mSuppressScrimTypes == that.mSuppressScrimTypes
1235                 && mSystemWindowInsetsConsumed == that.mSystemWindowInsetsConsumed
1236                 && mStableInsetsConsumed == that.mStableInsetsConsumed
1237                 && mDisplayCutoutConsumed == that.mDisplayCutoutConsumed
1238                 && Arrays.equals(mTypeInsetsMap, that.mTypeInsetsMap)
1239                 && Arrays.equals(mTypeMaxInsetsMap, that.mTypeMaxInsetsMap)
1240                 && Arrays.equals(mTypeVisibilityMap, that.mTypeVisibilityMap)
1241                 && Objects.equals(mDisplayCutout, that.mDisplayCutout)
1242                 && Objects.equals(mRoundedCorners, that.mRoundedCorners)
1243                 && Objects.equals(mPrivacyIndicatorBounds, that.mPrivacyIndicatorBounds)
1244                 && Objects.equals(mDisplayShape, that.mDisplayShape)
1245                 && Arrays.deepEquals(mTypeBoundingRectsMap, that.mTypeBoundingRectsMap)
1246                 && Arrays.deepEquals(mTypeMaxBoundingRectsMap, that.mTypeMaxBoundingRectsMap)
1247                 && mFrameWidth == that.mFrameWidth
1248                 && mFrameHeight == that.mFrameHeight;
1249     }
1250 
1251     @Override
hashCode()1252     public int hashCode() {
1253         return Objects.hash(Arrays.hashCode(mTypeInsetsMap), Arrays.hashCode(mTypeMaxInsetsMap),
1254                 Arrays.hashCode(mTypeVisibilityMap), mIsRound, mDisplayCutout, mRoundedCorners,
1255                 mForceConsumingTypes, mForceConsumingOpaqueCaptionBar, mSuppressScrimTypes,
1256                 mSystemWindowInsetsConsumed, mStableInsetsConsumed, mDisplayCutoutConsumed,
1257                 mPrivacyIndicatorBounds, mDisplayShape, Arrays.deepHashCode(mTypeBoundingRectsMap),
1258                 Arrays.deepHashCode(mTypeMaxBoundingRectsMap), mFrameWidth, mFrameHeight);
1259     }
1260 
1261 
1262     /**
1263      * Insets every inset in {@code typeInsetsMap} by the specified left, top, right, bottom.
1264      *
1265      * @return {@code typeInsetsMap} if no inset was modified; a copy of the map with the modified
1266      *          insets otherwise.
1267      */
insetInsets( Insets[] typeInsetsMap, int left, int top, int right, int bottom)1268     private static Insets[] insetInsets(
1269             Insets[] typeInsetsMap, int left, int top, int right, int bottom) {
1270         boolean cloned = false;
1271         for (int i = 0; i < SIZE; i++) {
1272             Insets insets = typeInsetsMap[i];
1273             if (insets == null) {
1274                 continue;
1275             }
1276             Insets insetInsets = insetInsets(insets, left, top, right, bottom);
1277             if (insetInsets != insets) {
1278                 if (!cloned) {
1279                     typeInsetsMap = typeInsetsMap.clone();
1280                     cloned = true;
1281                 }
1282                 typeInsetsMap[i] = insetInsets;
1283             }
1284         }
1285         return typeInsetsMap;
1286     }
1287 
insetInsets(Insets insets, int left, int top, int right, int bottom)1288     static Insets insetInsets(Insets insets, int left, int top, int right, int bottom) {
1289         int newLeft = Math.max(0, insets.left - left);
1290         int newTop = Math.max(0, insets.top - top);
1291         int newRight = Math.max(0, insets.right - right);
1292         int newBottom = Math.max(0, insets.bottom - bottom);
1293         if (newLeft == insets.left && newTop == insets.top
1294                 && newRight == insets.right && newBottom == insets.bottom) {
1295             return insets;
1296         }
1297         return Insets.of(newLeft, newTop, newRight, newBottom);
1298     }
1299 
insetBoundingRects(Rect[][] typeBoundingRectsMap, int insetLeft, int insetTop, int insetRight, int insetBottom, int frameWidth, int frameHeight)1300     static Rect[][] insetBoundingRects(Rect[][] typeBoundingRectsMap,
1301             int insetLeft, int insetTop, int insetRight, int insetBottom, int frameWidth,
1302             int frameHeight) {
1303         if (insetLeft == 0 && insetTop == 0 && insetRight == 0 && insetBottom == 0) {
1304             return typeBoundingRectsMap;
1305         }
1306         boolean cloned = false;
1307         for (int i = 0; i < SIZE; i++) {
1308             final Rect[] boundingRects = typeBoundingRectsMap[i];
1309             if (boundingRects == null) {
1310                 continue;
1311             }
1312             final Rect[] insetBoundingRects = insetBoundingRects(boundingRects,
1313                     insetLeft, insetTop, insetRight, insetBottom, frameWidth, frameHeight);
1314             if (!Arrays.equals(insetBoundingRects, boundingRects)) {
1315                 if (!cloned) {
1316                     typeBoundingRectsMap = typeBoundingRectsMap.clone();
1317                     cloned = true;
1318                 }
1319                 typeBoundingRectsMap[i] = insetBoundingRects;
1320             }
1321         }
1322         return typeBoundingRectsMap;
1323     }
1324 
insetBoundingRects(Rect[] boundingRects, int left, int top, int right, int bottom, int frameWidth, int frameHeight)1325     static Rect[] insetBoundingRects(Rect[] boundingRects,
1326             int left, int top, int right, int bottom, int frameWidth, int frameHeight) {
1327         final List<Rect> insetBoundingRectsList = new ArrayList<>();
1328         for (int i = 0; i < boundingRects.length; i++) {
1329             final Rect insetRect = insetRect(boundingRects[i], left, top, right, bottom,
1330                     frameWidth, frameHeight);
1331             if (insetRect != null) {
1332                 insetBoundingRectsList.add(insetRect);
1333             }
1334         }
1335         return insetBoundingRectsList.toArray(new Rect[0]);
1336     }
1337 
insetRect(Rect orig, int insetLeft, int insetTop, int insetRight, int insetBottom, int frameWidth, int frameHeight)1338     private static Rect insetRect(Rect orig, int insetLeft, int insetTop, int insetRight,
1339             int insetBottom, int frameWidth, int frameHeight) {
1340         if (orig == null) {
1341             return null;
1342         }
1343 
1344         // Calculate the inset frame, and leave it in that coordinate space for easier comparison
1345         // against the |orig| rect.
1346         final Rect insetFrame = new Rect(insetLeft, insetTop, frameWidth - insetRight,
1347                 frameHeight - insetBottom);
1348         // Then the intersecting portion of |orig| with the inset |insetFrame|.
1349         final Rect insetRect = new Rect();
1350         if (insetRect.setIntersect(insetFrame, orig)) {
1351             // The intersection is the inset rect, but its position must be shifted to be relative
1352             // to the frame. Since the new frame will start at left=|insetLeft| and top=|insetTop|,
1353             // just offset that much back in the direction of the origin of the frame.
1354             insetRect.offset(-insetLeft, -insetTop);
1355             return insetRect;
1356         } else {
1357             // The |orig| rect does not intersect with the new frame at all, so don't report it.
1358             return null;
1359         }
1360     }
1361 
1362     /**
1363      * @return whether system window insets have been consumed.
1364      */
isSystemWindowInsetsConsumed()1365     boolean isSystemWindowInsetsConsumed() {
1366         return mSystemWindowInsetsConsumed;
1367     }
1368 
1369     /**
1370      * Builder for WindowInsets.
1371      */
1372     public static final class Builder {
1373 
1374         private final Insets[] mTypeInsetsMap;
1375         private final Insets[] mTypeMaxInsetsMap;
1376         private final boolean[] mTypeVisibilityMap;
1377         private final Rect[][] mTypeBoundingRectsMap;
1378         private final Rect[][] mTypeMaxBoundingRectsMap;
1379         private boolean mSystemInsetsConsumed = true;
1380         private boolean mStableInsetsConsumed = true;
1381 
1382         private DisplayCutout mDisplayCutout;
1383         private RoundedCorners mRoundedCorners = RoundedCorners.NO_ROUNDED_CORNERS;
1384         private DisplayShape mDisplayShape = DisplayShape.NONE;
1385 
1386         private boolean mIsRound;
1387         private @InsetsType int mForceConsumingTypes;
1388         private boolean mForceConsumingOpaqueCaptionBar;
1389         private @InsetsType int mSuppressScrimTypes;
1390 
1391         private PrivacyIndicatorBounds mPrivacyIndicatorBounds = new PrivacyIndicatorBounds();
1392         private int mFrameWidth;
1393         private int mFrameHeight;
1394 
1395         /**
1396          * Creates a builder where all insets are initially consumed.
1397          */
Builder()1398         public Builder() {
1399             mTypeInsetsMap = new Insets[SIZE];
1400             mTypeMaxInsetsMap = new Insets[SIZE];
1401             mTypeVisibilityMap = new boolean[SIZE];
1402             mTypeBoundingRectsMap = new Rect[SIZE][];
1403             mTypeMaxBoundingRectsMap = new Rect[SIZE][];
1404         }
1405 
1406         /**
1407          * Creates a builder where all insets are initialized from {@link WindowInsets}.
1408          *
1409          * @param insets the instance to initialize from.
1410          */
Builder(@onNull WindowInsets insets)1411         public Builder(@NonNull WindowInsets insets) {
1412             mTypeInsetsMap = insets.mTypeInsetsMap.clone();
1413             mTypeMaxInsetsMap = insets.mTypeMaxInsetsMap.clone();
1414             mTypeVisibilityMap = insets.mTypeVisibilityMap.clone();
1415             mSystemInsetsConsumed = insets.mSystemWindowInsetsConsumed;
1416             mStableInsetsConsumed = insets.mStableInsetsConsumed;
1417             mDisplayCutout = displayCutoutCopyConstructorArgument(insets);
1418             mRoundedCorners = insets.mRoundedCorners;
1419             mIsRound = insets.mIsRound;
1420             mForceConsumingTypes = insets.mForceConsumingTypes;
1421             mForceConsumingOpaqueCaptionBar = insets.mForceConsumingOpaqueCaptionBar;
1422             mSuppressScrimTypes = insets.mSuppressScrimTypes;
1423             mPrivacyIndicatorBounds = insets.mPrivacyIndicatorBounds;
1424             mDisplayShape = insets.mDisplayShape;
1425             mTypeBoundingRectsMap = insets.mTypeBoundingRectsMap.clone();
1426             mTypeMaxBoundingRectsMap = insets.mTypeMaxBoundingRectsMap.clone();
1427             mFrameWidth = insets.mFrameWidth;
1428             mFrameHeight = insets.mFrameHeight;
1429         }
1430 
1431         /**
1432          * Sets system window insets in pixels.
1433          *
1434          * <p>The system window inset represents the area of a full-screen window that is
1435          * partially or fully obscured by the status bar, navigation bar, IME or other system
1436          * windows.</p>
1437          *
1438          * @see #getSystemWindowInsets()
1439          * @return itself
1440          * @deprecated Use {@link #setInsets(int, Insets)} with {@link Type#systemBars()}.
1441          */
1442         @Deprecated
1443         @NonNull
setSystemWindowInsets(@onNull Insets systemWindowInsets)1444         public Builder setSystemWindowInsets(@NonNull Insets systemWindowInsets) {
1445             Preconditions.checkNotNull(systemWindowInsets);
1446             assignCompatInsets(mTypeInsetsMap, systemWindowInsets.toRect());
1447             mSystemInsetsConsumed = false;
1448             return this;
1449         }
1450 
1451         /**
1452          * Sets system gesture insets in pixels.
1453          *
1454          * <p>The system gesture insets represent the area of a window where system gestures have
1455          * priority and may consume some or all touch input, e.g. due to the a system bar
1456          * occupying it, or it being reserved for touch-only gestures.
1457          *
1458          * @see #getSystemGestureInsets()
1459          * @return itself
1460          * @deprecated Use {@link #setInsets(int, Insets)} with {@link Type#systemGestures()}.
1461          */
1462         @Deprecated
1463         @NonNull
setSystemGestureInsets(@onNull Insets insets)1464         public Builder setSystemGestureInsets(@NonNull Insets insets) {
1465             WindowInsets.setInsets(mTypeInsetsMap, SYSTEM_GESTURES, insets);
1466             return this;
1467         }
1468 
1469         /**
1470          * Sets mandatory system gesture insets in pixels.
1471          *
1472          * <p>The mandatory system gesture insets represent the area of a window where mandatory
1473          * system gestures have priority and may consume some or all touch input, e.g. due to the a
1474          * system bar occupying it, or it being reserved for touch-only gestures.
1475          *
1476          * <p>In contrast to {@link #setSystemGestureInsets regular system gestures},
1477          * <b>mandatory</b> system gestures cannot be overriden by
1478          * {@link View#setSystemGestureExclusionRects}.
1479          *
1480          * @see #getMandatorySystemGestureInsets()
1481          * @return itself
1482          * @deprecated Use {@link #setInsets(int, Insets)} with
1483          *             {@link Type#mandatorySystemGestures()}.
1484          */
1485         @Deprecated
1486         @NonNull
setMandatorySystemGestureInsets(@onNull Insets insets)1487         public Builder setMandatorySystemGestureInsets(@NonNull Insets insets) {
1488             WindowInsets.setInsets(mTypeInsetsMap, MANDATORY_SYSTEM_GESTURES, insets);
1489             return this;
1490         }
1491 
1492         /**
1493          * Sets tappable element insets in pixels.
1494          *
1495          * <p>The tappable element insets represent how much tappable elements <b>must at least</b>
1496          * be inset to remain both tappable and visually unobstructed by persistent system windows.
1497          *
1498          * @see #getTappableElementInsets()
1499          * @return itself
1500          * @deprecated Use {@link #setInsets(int, Insets)} with {@link Type#tappableElement()}.
1501          */
1502         @Deprecated
1503         @NonNull
setTappableElementInsets(@onNull Insets insets)1504         public Builder setTappableElementInsets(@NonNull Insets insets) {
1505             WindowInsets.setInsets(mTypeInsetsMap, TAPPABLE_ELEMENT, insets);
1506             return this;
1507         }
1508 
1509         /**
1510          * Sets the insets of a specific window type in pixels.
1511          *
1512          * <p>The insets represents the area of a a window that is partially or fully obscured by
1513          * the system windows identified by {@code typeMask}.
1514          * </p>
1515          *
1516          * @see #getInsets(int)
1517          *
1518          * @param typeMask The bitmask of {@link Type} to set the insets for.
1519          * @param insets The insets to set.
1520          *
1521          * @return itself
1522          */
1523         @NonNull
setInsets(@nsetsType int typeMask, @NonNull Insets insets)1524         public Builder setInsets(@InsetsType int typeMask, @NonNull Insets insets) {
1525             Preconditions.checkNotNull(insets);
1526             WindowInsets.setInsets(mTypeInsetsMap, typeMask, insets);
1527             mSystemInsetsConsumed = false;
1528             return this;
1529         }
1530 
1531         /**
1532          * Sets the insets a specific window type in pixels, while ignoring its visibility state.
1533          *
1534          * <p>The insets represents the area of a a window that that <b>may</b> be partially
1535          * or fully obscured by the system window identified by {@code type}. This value does not
1536          * change based on the visibility state of those elements. For example, if the status bar is
1537          * normally shown, but temporarily hidden, the inset returned here will still provide the
1538          * inset associated with the status bar being shown.</p>
1539          *
1540          * @see #getInsetsIgnoringVisibility(int)
1541          *
1542          * @param typeMask The bitmask of {@link Type} to set the insets for.
1543          * @param insets The insets to set.
1544          *
1545          * @return itself
1546          *
1547          * @throws IllegalArgumentException If {@code typeMask} contains {@link Type#ime()}. Maximum
1548          *                                  insets are not available for this type as the height of
1549          *                                  the IME is dynamic depending on the {@link EditorInfo}
1550          *                                  of the currently focused view, as well as the UI
1551          *                                  state of the IME.
1552          */
1553         @NonNull
setInsetsIgnoringVisibility(@nsetsType int typeMask, @NonNull Insets insets)1554         public Builder setInsetsIgnoringVisibility(@InsetsType int typeMask, @NonNull Insets insets)
1555                 throws IllegalArgumentException{
1556             if (typeMask == IME) {
1557                 throw new IllegalArgumentException("Maximum inset not available for IME");
1558             }
1559             Preconditions.checkNotNull(insets);
1560             WindowInsets.setInsets(mTypeMaxInsetsMap, typeMask, insets);
1561             mStableInsetsConsumed = false;
1562             return this;
1563         }
1564 
1565         /**
1566          * Sets whether windows that can cause insets are currently visible on screen.
1567          *
1568          *
1569          * @see #isVisible(int)
1570          *
1571          * @param typeMask The bitmask of {@link Type} to set the visibility for.
1572          * @param visible Whether to mark the windows as visible or not.
1573          *
1574          * @return itself
1575          */
1576         @NonNull
setVisible(@nsetsType int typeMask, boolean visible)1577         public Builder setVisible(@InsetsType int typeMask, boolean visible) {
1578             for (int i = FIRST; i <= LAST; i = i << 1) {
1579                 if ((typeMask & i) == 0) {
1580                     continue;
1581                 }
1582                 mTypeVisibilityMap[indexOf(i)] = visible;
1583             }
1584             return this;
1585         }
1586 
1587         /**
1588          * Sets the stable insets in pixels.
1589          *
1590          * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
1591          * partially or fully obscured by the system UI elements.  This value does not change
1592          * based on the visibility state of those elements; for example, if the status bar is
1593          * normally shown, but temporarily hidden, the stable inset will still provide the inset
1594          * associated with the status bar being shown.</p>
1595          *
1596          * @see #getStableInsets()
1597          * @return itself
1598          * @deprecated Use {@link #setInsetsIgnoringVisibility(int, Insets)} with
1599          *             {@link Type#systemBars()}.
1600          */
1601         @Deprecated
1602         @NonNull
setStableInsets(@onNull Insets stableInsets)1603         public Builder setStableInsets(@NonNull Insets stableInsets) {
1604             Preconditions.checkNotNull(stableInsets);
1605             assignCompatInsets(mTypeMaxInsetsMap, stableInsets.toRect());
1606             mStableInsetsConsumed = false;
1607             return this;
1608         }
1609 
1610         /**
1611          * Sets the display cutout.
1612          *
1613          * @see #getDisplayCutout()
1614          * @param displayCutout the display cutout or null if there is none
1615          * @return itself
1616          */
1617         @NonNull
setDisplayCutout(@ullable DisplayCutout displayCutout)1618         public Builder setDisplayCutout(@Nullable DisplayCutout displayCutout) {
1619             mDisplayCutout = displayCutout != null ? displayCutout : DisplayCutout.NO_CUTOUT;
1620             if (!mDisplayCutout.isEmpty()) {
1621                 final Insets safeInsets = Insets.of(mDisplayCutout.getSafeInsets());
1622                 final int index = indexOf(DISPLAY_CUTOUT);
1623                 mTypeInsetsMap[index] = safeInsets;
1624                 mTypeMaxInsetsMap[index] = safeInsets;
1625                 mTypeVisibilityMap[index] = true;
1626             }
1627             return this;
1628         }
1629 
1630         /** @hide */
1631         @NonNull
setRoundedCorners(RoundedCorners roundedCorners)1632         public Builder setRoundedCorners(RoundedCorners roundedCorners) {
1633             mRoundedCorners = roundedCorners != null
1634                     ? roundedCorners : RoundedCorners.NO_ROUNDED_CORNERS;
1635             return this;
1636         }
1637 
1638         /**
1639          * Sets the rounded corner of given position.
1640          *
1641          * @see #getRoundedCorner(int)
1642          * @param position the position of this rounded corner
1643          * @param roundedCorner the rounded corner or null if there is none
1644          * @return itself
1645          */
1646         @NonNull
setRoundedCorner(@oundedCorner.Position int position, @Nullable RoundedCorner roundedCorner)1647         public Builder setRoundedCorner(@RoundedCorner.Position int position,
1648                 @Nullable RoundedCorner roundedCorner) {
1649             mRoundedCorners.setRoundedCorner(position, roundedCorner);
1650             return this;
1651         }
1652 
1653         /** @hide */
1654         @NonNull
setPrivacyIndicatorBounds(@ullable PrivacyIndicatorBounds bounds)1655         public Builder setPrivacyIndicatorBounds(@Nullable PrivacyIndicatorBounds bounds) {
1656             mPrivacyIndicatorBounds = bounds;
1657             return this;
1658         }
1659 
1660         /**
1661          * Sets the bounds of the system privacy indicator.
1662          *
1663          * @param bounds The bounds of the system privacy indicator
1664          */
1665         @NonNull
setPrivacyIndicatorBounds(@ullable Rect bounds)1666         public Builder setPrivacyIndicatorBounds(@Nullable Rect bounds) {
1667             //TODO 188788786: refactor the indicator bounds
1668             Rect[] boundsArr = { bounds, bounds, bounds, bounds };
1669             mPrivacyIndicatorBounds = new PrivacyIndicatorBounds(boundsArr, ROTATION_0);
1670             return this;
1671         }
1672 
1673         /**
1674          * Sets the display shape.
1675          *
1676          * @see #getDisplayShape().
1677          * @param displayShape the display shape.
1678          * @return itself.
1679          */
1680         @NonNull
setDisplayShape(@onNull DisplayShape displayShape)1681         public Builder setDisplayShape(@NonNull DisplayShape displayShape) {
1682             mDisplayShape = displayShape;
1683             return this;
1684         }
1685 
1686         /** @hide */
1687         @NonNull
setRound(boolean round)1688         public Builder setRound(boolean round) {
1689             mIsRound = round;
1690             return this;
1691         }
1692 
1693         /** @hide */
1694         @NonNull
setAlwaysConsumeSystemBars(boolean alwaysConsumeSystemBars)1695         public Builder setAlwaysConsumeSystemBars(boolean alwaysConsumeSystemBars) {
1696             // TODO (b/277891341): Remove this and related usages. This has been replaced by
1697             //                     #setForceConsumingTypes.
1698             return this;
1699         }
1700 
1701         /** @hide */
1702         @NonNull
setForceConsumingTypes(@nsetsType int forceConsumingTypes)1703         public Builder setForceConsumingTypes(@InsetsType int forceConsumingTypes) {
1704             mForceConsumingTypes = forceConsumingTypes;
1705             return this;
1706         }
1707 
1708         /** @hide */
1709         @NonNull
setForceConsumingOpaqueCaptionBar(boolean forceConsumingOpaqueCaptionBar)1710         public Builder setForceConsumingOpaqueCaptionBar(boolean forceConsumingOpaqueCaptionBar) {
1711             mForceConsumingOpaqueCaptionBar = forceConsumingOpaqueCaptionBar;
1712             return this;
1713         }
1714 
1715         /** @hide */
1716         @NonNull
setSuppressScrimTypes(@nsetsType int suppressScrimTypes)1717         public Builder setSuppressScrimTypes(@InsetsType int suppressScrimTypes) {
1718             mSuppressScrimTypes = suppressScrimTypes;
1719             return this;
1720         }
1721 
1722         /**
1723          * Sets the bounding rects.
1724          *
1725          * @param typeMask the inset types to which these rects apply.
1726          * @param rects the bounding rects.
1727          * @return itself.
1728          */
1729         @FlaggedApi(Flags.FLAG_CUSTOMIZABLE_WINDOW_HEADERS)
1730         @NonNull
setBoundingRects(@nsetsType int typeMask, @NonNull List<Rect> rects)1731         public Builder setBoundingRects(@InsetsType int typeMask, @NonNull List<Rect> rects) {
1732             for (int i = FIRST; i <= LAST; i = i << 1) {
1733                 if ((typeMask & i) == 0) {
1734                     continue;
1735                 }
1736                 mTypeBoundingRectsMap[indexOf(i)] = rects.toArray(new Rect[0]);
1737             }
1738             mSystemInsetsConsumed = false;
1739             return this;
1740         }
1741 
1742         /**
1743          * Sets the bounding rects while ignoring their visibility state.
1744          *
1745          * @param typeMask the inset types to which these rects apply.
1746          * @param rects the bounding rects.
1747          * @return itself.
1748          *
1749          * @throws IllegalArgumentException If {@code typeMask} contains {@link Type#ime()}.
1750          * Maximum bounding rects are not available for this type as the height of the IME is
1751          * dynamic depending on the {@link EditorInfo} of the currently focused view, as well as
1752          * the UI state of the IME.
1753          */
1754         @FlaggedApi(Flags.FLAG_CUSTOMIZABLE_WINDOW_HEADERS)
1755         @NonNull
setBoundingRectsIgnoringVisibility(@nsetsType int typeMask, @NonNull List<Rect> rects)1756         public Builder setBoundingRectsIgnoringVisibility(@InsetsType int typeMask,
1757                 @NonNull List<Rect> rects) {
1758             if (typeMask == IME) {
1759                 throw new IllegalArgumentException("Maximum bounding rects not available for IME");
1760             }
1761             for (int i = FIRST; i <= LAST; i = i << 1) {
1762                 if ((typeMask & i) == 0) {
1763                     continue;
1764                 }
1765                 mTypeMaxBoundingRectsMap[indexOf(i)] = rects.toArray(new Rect[0]);
1766             }
1767             mStableInsetsConsumed = false;
1768             return this;
1769         }
1770 
1771         /**
1772          * Set the frame size.
1773          *
1774          * @param width the width of the frame.
1775          * @param height the height of the frame.
1776          * @return itself.
1777          */
1778         @FlaggedApi(Flags.FLAG_CUSTOMIZABLE_WINDOW_HEADERS)
1779         @NonNull
setFrame(int width, int height)1780         public Builder setFrame(int width, int height) {
1781             mFrameWidth = width;
1782             mFrameHeight = height;
1783             return this;
1784         }
1785 
1786         /**
1787          * Builds a {@link WindowInsets} instance.
1788          *
1789          * @return the {@link WindowInsets} instance.
1790          */
1791         @NonNull
build()1792         public WindowInsets build() {
1793             return new WindowInsets(mSystemInsetsConsumed ? null : mTypeInsetsMap,
1794                     mStableInsetsConsumed ? null : mTypeMaxInsetsMap, mTypeVisibilityMap,
1795                     mIsRound, mForceConsumingTypes, mForceConsumingOpaqueCaptionBar,
1796                     mSuppressScrimTypes, mDisplayCutout, mRoundedCorners, mPrivacyIndicatorBounds,
1797                     mDisplayShape, systemBars(), false /* compatIgnoreVisibility */,
1798                     mSystemInsetsConsumed ? null : mTypeBoundingRectsMap,
1799                     mStableInsetsConsumed ? null : mTypeMaxBoundingRectsMap,
1800                     mFrameWidth, mFrameHeight);
1801         }
1802     }
1803 
1804     /**
1805      * Class that defines different types of sources causing window insets.
1806      */
1807     public static final class Type {
1808 
1809         static final int FIRST = 1 << 0;
1810         static final int STATUS_BARS = FIRST;
1811         static final int NAVIGATION_BARS = 1 << 1;
1812         static final int CAPTION_BAR = 1 << 2;
1813 
1814         static final int IME = 1 << 3;
1815 
1816         static final int SYSTEM_GESTURES = 1 << 4;
1817         static final int MANDATORY_SYSTEM_GESTURES = 1 << 5;
1818         static final int TAPPABLE_ELEMENT = 1 << 6;
1819 
1820         static final int DISPLAY_CUTOUT = 1 << 7;
1821 
1822         static final int WINDOW_DECOR = 1 << 8;
1823 
1824         static final int SYSTEM_OVERLAYS = 1 << 9;
1825         static final int LAST = SYSTEM_OVERLAYS;
1826         static final int SIZE = 10;
1827 
1828         static final int DEFAULT_VISIBLE = ~IME;
1829 
indexOf(@nsetsType int type)1830         static int indexOf(@InsetsType int type) {
1831             switch (type) {
1832                 case STATUS_BARS:
1833                     return 0;
1834                 case NAVIGATION_BARS:
1835                     return 1;
1836                 case CAPTION_BAR:
1837                     return 2;
1838                 case IME:
1839                     return 3;
1840                 case SYSTEM_GESTURES:
1841                     return 4;
1842                 case MANDATORY_SYSTEM_GESTURES:
1843                     return 5;
1844                 case TAPPABLE_ELEMENT:
1845                     return 6;
1846                 case DISPLAY_CUTOUT:
1847                     return 7;
1848                 case WINDOW_DECOR:
1849                     return 8;
1850                 case SYSTEM_OVERLAYS:
1851                     return 9;
1852                 default:
1853                     throw new IllegalArgumentException("type needs to be >= FIRST and <= LAST,"
1854                             + " type=" + type);
1855             }
1856         }
1857 
1858         /** @hide */
1859         @TestApi
1860         @NonNull
1861         @SuppressLint("UnflaggedApi") // @TestApi without associated feature.
toString(@nsetsType int types)1862         public static String toString(@InsetsType int types) {
1863             StringBuilder result = new StringBuilder();
1864             if ((types & STATUS_BARS) != 0) {
1865                 result.append("statusBars ");
1866             }
1867             if ((types & NAVIGATION_BARS) != 0) {
1868                 result.append("navigationBars ");
1869             }
1870             if ((types & CAPTION_BAR) != 0) {
1871                 result.append("captionBar ");
1872             }
1873             if ((types & IME) != 0) {
1874                 result.append("ime ");
1875             }
1876             if ((types & SYSTEM_GESTURES) != 0) {
1877                 result.append("systemGestures ");
1878             }
1879             if ((types & MANDATORY_SYSTEM_GESTURES) != 0) {
1880                 result.append("mandatorySystemGestures ");
1881             }
1882             if ((types & TAPPABLE_ELEMENT) != 0) {
1883                 result.append("tappableElement ");
1884             }
1885             if ((types & DISPLAY_CUTOUT) != 0) {
1886                 result.append("displayCutout ");
1887             }
1888             if ((types & WINDOW_DECOR) != 0) {
1889                 result.append("windowDecor ");
1890             }
1891             if ((types & SYSTEM_OVERLAYS) != 0) {
1892                 result.append("systemOverlays ");
1893             }
1894             if (result.length() > 0) {
1895                 result.delete(result.length() - 1, result.length());
1896             }
1897             return result.toString();
1898         }
1899 
Type()1900         private Type() {
1901         }
1902 
1903         /** @hide */
1904         @Retention(RetentionPolicy.SOURCE)
1905         @IntDef(flag = true, value = {STATUS_BARS, NAVIGATION_BARS, CAPTION_BAR, IME, WINDOW_DECOR,
1906                 SYSTEM_GESTURES, MANDATORY_SYSTEM_GESTURES, TAPPABLE_ELEMENT, DISPLAY_CUTOUT,
1907                 SYSTEM_OVERLAYS})
1908         public @interface InsetsType {
1909         }
1910 
1911         /**
1912          * @return An insets type representing any system bars for displaying status.
1913          */
statusBars()1914         public static @InsetsType int statusBars() {
1915             return STATUS_BARS;
1916         }
1917 
1918         /**
1919          * @return An insets type representing any system bars for navigation.
1920          */
navigationBars()1921         public static @InsetsType int navigationBars() {
1922             return NAVIGATION_BARS;
1923         }
1924 
1925         /**
1926          * @return An insets type representing the window of a caption bar.
1927          */
captionBar()1928         public static @InsetsType int captionBar() {
1929             return CAPTION_BAR;
1930         }
1931 
1932         /**
1933          * @return An insets type representing the window of an {@link InputMethod}.
1934          */
ime()1935         public static @InsetsType int ime() {
1936             return IME;
1937         }
1938 
1939         /**
1940          * Returns an insets type representing the system gesture insets.
1941          *
1942          * <p>The system gesture insets represent the area of a window where system gestures have
1943          * priority and may consume some or all touch input, e.g. due to the a system bar
1944          * occupying it, or it being reserved for touch-only gestures.
1945          *
1946          * <p>Simple taps are guaranteed to reach the window even within the system gesture insets,
1947          * as long as they are outside the {@link #getSystemWindowInsets() system window insets}.
1948          *
1949          * <p>When {@link View#SYSTEM_UI_FLAG_LAYOUT_STABLE} is requested, an inset will be returned
1950          * even when the system gestures are inactive due to
1951          * {@link View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} or
1952          * {@link View#SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}.
1953          *
1954          * @see #getSystemGestureInsets()
1955          */
systemGestures()1956         public static @InsetsType int systemGestures() {
1957             return SYSTEM_GESTURES;
1958         }
1959 
1960         /**
1961          * @see #getMandatorySystemGestureInsets
1962          */
mandatorySystemGestures()1963         public static @InsetsType int mandatorySystemGestures() {
1964             return MANDATORY_SYSTEM_GESTURES;
1965         }
1966 
1967         /**
1968          * @see #getTappableElementInsets
1969          */
tappableElement()1970         public static @InsetsType int tappableElement() {
1971             return TAPPABLE_ELEMENT;
1972         }
1973 
1974         /**
1975          * Returns an insets type representing the area that used by {@link DisplayCutout}.
1976          *
1977          * <p>This is equivalent to the safe insets on {@link #getDisplayCutout()}.
1978          *
1979          * <p>Note: During dispatch to {@link View#onApplyWindowInsets}, if the window is using
1980          * the {@link WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT default}
1981          * {@link WindowManager.LayoutParams#layoutInDisplayCutoutMode}, {@link #getDisplayCutout()}
1982          * will return {@code null} even if the window overlaps a display cutout area, in which case
1983          * the {@link #displayCutout() displayCutout() inset} will still report the accurate value.
1984          *
1985          * @see DisplayCutout#getSafeInsetLeft()
1986          * @see DisplayCutout#getSafeInsetTop()
1987          * @see DisplayCutout#getSafeInsetRight()
1988          * @see DisplayCutout#getSafeInsetBottom()
1989          */
displayCutout()1990         public static @InsetsType int displayCutout() {
1991             return DISPLAY_CUTOUT;
1992         }
1993 
1994         /**
1995          * System overlays represent the insets caused by the system visible elements. Unlike
1996          * {@link #navigationBars()} or {@link #statusBars()}, system overlays might not be
1997          * hidden by the client.
1998          *
1999          * For compatibility reasons, this type is included in {@link #systemBars()}. In this
2000          * way, views which fit {@link #systemBars()} fit {@link #systemOverlays()}.
2001          *
2002          * Examples include climate controls, multi-tasking affordances, etc.
2003          *
2004          * @return An insets type representing the system overlays.
2005          */
systemOverlays()2006         public static @InsetsType int systemOverlays() {
2007             return SYSTEM_OVERLAYS;
2008         }
2009 
2010         /**
2011          * @return All system bars. Includes {@link #statusBars()}, {@link #captionBar()} as well as
2012          *         {@link #navigationBars()}, {@link #systemOverlays()}, but not {@link #ime()}.
2013          */
systemBars()2014         public static @InsetsType int systemBars() {
2015             return STATUS_BARS | NAVIGATION_BARS | CAPTION_BAR | SYSTEM_OVERLAYS;
2016         }
2017 
2018         /**
2019          * @return Default visible types.
2020          *
2021          * @hide
2022          */
defaultVisible()2023         public static @InsetsType int defaultVisible() {
2024             return DEFAULT_VISIBLE;
2025         }
2026 
2027         /**
2028          * @return All inset types combined.
2029          *
2030          * @hide
2031          */
all()2032         public static @InsetsType int all() {
2033             return 0xFFFFFFFF;
2034         }
2035 
2036         /**
2037          * @return System bars which can be controlled by {@link View.SystemUiVisibility}.
2038          *
2039          * @hide
2040          */
hasCompatSystemBars(@nsetsType int types)2041         public static boolean hasCompatSystemBars(@InsetsType int types) {
2042             return (types & (STATUS_BARS | NAVIGATION_BARS)) != 0;
2043         }
2044     }
2045 
2046     /**
2047      * Class that defines different sides for insets.
2048      */
2049     public static final class Side {
2050 
2051         public static final int LEFT = 1 << 0;
2052         public static final int TOP = 1 << 1;
2053         public static final int RIGHT = 1 << 2;
2054         public static final int BOTTOM = 1 << 3;
2055 
Side()2056         private Side() {
2057         }
2058 
2059         /** @hide */
2060         @Retention(RetentionPolicy.SOURCE)
2061         @IntDef(flag = true, value = {LEFT, TOP, RIGHT, BOTTOM})
2062         public @interface InsetsSide {}
2063 
2064         /**
2065          * @return all four sides.
2066          */
all()2067         public static @InsetsSide int all() {
2068             return LEFT | TOP | RIGHT | BOTTOM;
2069         }
2070     }
2071 }
2072