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