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