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