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.WindowInsets.Type.FIRST;
21 import static android.view.WindowInsets.Type.IME;
22 import static android.view.WindowInsets.Type.LAST;
23 import static android.view.WindowInsets.Type.MANDATORY_SYSTEM_GESTURES;
24 import static android.view.WindowInsets.Type.SIDE_BARS;
25 import static android.view.WindowInsets.Type.SIZE;
26 import static android.view.WindowInsets.Type.SYSTEM_GESTURES;
27 import static android.view.WindowInsets.Type.TAPPABLE_ELEMENT;
28 import static android.view.WindowInsets.Type.TOP_BAR;
29 import static android.view.WindowInsets.Type.all;
30 import static android.view.WindowInsets.Type.compatSystemInsets;
31 import static android.view.WindowInsets.Type.indexOf;
32 
33 import android.annotation.IntDef;
34 import android.annotation.IntRange;
35 import android.annotation.NonNull;
36 import android.annotation.Nullable;
37 import android.compat.annotation.UnsupportedAppUsage;
38 import android.content.Intent;
39 import android.graphics.Insets;
40 import android.graphics.Rect;
41 import android.util.SparseArray;
42 import android.view.WindowInsets.Type.InsetType;
43 import android.view.inputmethod.EditorInfo;
44 import android.view.inputmethod.InputMethod;
45 
46 import com.android.internal.util.Preconditions;
47 
48 import java.lang.annotation.Retention;
49 import java.lang.annotation.RetentionPolicy;
50 import java.util.Arrays;
51 import java.util.Objects;
52 
53 /**
54  * Describes a set of insets for window content.
55  *
56  * <p>WindowInsets are immutable and may be expanded to include more inset types in the future.
57  * To adjust insets, use one of the supplied clone methods to obtain a new WindowInsets instance
58  * with the adjusted properties.</p>
59  *
60  * <p>Note: Before {@link android.os.Build.VERSION_CODES#P P}, WindowInsets instances were only
61  * immutable during a single layout pass (i.e. would return the same values between
62  * {@link View#onApplyWindowInsets} and {@link View#onLayout}, but could return other values
63  * otherwise). Starting with {@link android.os.Build.VERSION_CODES#P P}, WindowInsets are
64  * always immutable and implement equality.
65  *
66  * @see View.OnApplyWindowInsetsListener
67  * @see View#onApplyWindowInsets(WindowInsets)
68  */
69 public final class WindowInsets {
70 
71     private final Insets[] mTypeInsetsMap;
72     private final Insets[] mTypeMaxInsetsMap;
73     private final boolean[] mTypeVisibilityMap;
74 
75     @Nullable private Rect mTempRect;
76     private final boolean mIsRound;
77     @Nullable private final DisplayCutout mDisplayCutout;
78 
79     /**
80      * In multi-window we force show the navigation bar. Because we don't want that the surface size
81      * changes in this mode, we instead have a flag whether the navigation bar size should always
82      * be consumed, so the app is treated like there is no virtual navigation bar at all.
83      */
84     private final boolean mAlwaysConsumeSystemBars;
85 
86     private final boolean mSystemWindowInsetsConsumed;
87     private final boolean mStableInsetsConsumed;
88     private final boolean mDisplayCutoutConsumed;
89 
90     /**
91      * Since new insets may be added in the future that existing apps couldn't
92      * know about, this fully empty constant shouldn't be made available to apps
93      * since it would allow them to inadvertently consume unknown insets by returning it.
94      * @hide
95      */
96     @UnsupportedAppUsage
97     public static final WindowInsets CONSUMED;
98 
99     static {
100         CONSUMED = new WindowInsets((Rect) null, null, false, false, null);
101     }
102 
103     /**
104      * Construct a new WindowInsets from individual insets.
105      *
106      * A {@code null} inset indicates that the respective inset is consumed.
107      *
108      * @hide
109      * @deprecated Use {@link WindowInsets(SparseArray, SparseArray, boolean, boolean, DisplayCutout)}
110      */
WindowInsets(Rect systemWindowInsetsRect, Rect stableInsetsRect, boolean isRound, boolean alwaysConsumeSystemBars, DisplayCutout displayCutout)111     public WindowInsets(Rect systemWindowInsetsRect, Rect stableInsetsRect,
112             boolean isRound, boolean alwaysConsumeSystemBars, DisplayCutout displayCutout) {
113         this(createCompatTypeMap(systemWindowInsetsRect), createCompatTypeMap(stableInsetsRect),
114                 createCompatVisibilityMap(createCompatTypeMap(systemWindowInsetsRect)),
115                 isRound, alwaysConsumeSystemBars, displayCutout);
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, boolean alwaysConsumeSystemBars, DisplayCutout displayCutout)130     public WindowInsets(@Nullable Insets[] typeInsetsMap,
131             @Nullable Insets[] typeMaxInsetsMap,
132             boolean[] typeVisibilityMap,
133             boolean isRound,
134             boolean alwaysConsumeSystemBars, DisplayCutout displayCutout) {
135         mSystemWindowInsetsConsumed = typeInsetsMap == null;
136         mTypeInsetsMap = mSystemWindowInsetsConsumed
137                 ? new Insets[SIZE]
138                 : typeInsetsMap.clone();
139 
140         mStableInsetsConsumed = typeMaxInsetsMap == null;
141         mTypeMaxInsetsMap = mStableInsetsConsumed
142                 ? new Insets[SIZE]
143                 : typeMaxInsetsMap.clone();
144 
145         mTypeVisibilityMap = typeVisibilityMap;
146         mIsRound = isRound;
147         mAlwaysConsumeSystemBars = alwaysConsumeSystemBars;
148 
149         mDisplayCutoutConsumed = displayCutout == null;
150         mDisplayCutout = (mDisplayCutoutConsumed || displayCutout.isEmpty())
151                 ? null : displayCutout;
152     }
153 
154     /**
155      * Construct a new WindowInsets, copying all values from a source WindowInsets.
156      *
157      * @param src Source to copy insets from
158      */
WindowInsets(WindowInsets src)159     public WindowInsets(WindowInsets src) {
160         this(src.mSystemWindowInsetsConsumed ? null : src.mTypeInsetsMap,
161                 src.mStableInsetsConsumed ? null : src.mTypeMaxInsetsMap,
162                 src.mTypeVisibilityMap, src.mIsRound,
163                 src.mAlwaysConsumeSystemBars, displayCutoutCopyConstructorArgument(src));
164     }
165 
displayCutoutCopyConstructorArgument(WindowInsets w)166     private static DisplayCutout displayCutoutCopyConstructorArgument(WindowInsets w) {
167         if (w.mDisplayCutoutConsumed) {
168             return null;
169         } else if (w.mDisplayCutout == null) {
170             return DisplayCutout.NO_CUTOUT;
171         } else {
172             return w.mDisplayCutout;
173         }
174     }
175 
176     /**
177      * @return The insets that include system bars indicated by {@code typeMask}, taken from
178      *         {@code typeInsetMap}.
179      */
getInsets(Insets[] typeInsetsMap, @InsetType int typeMask)180     private static Insets getInsets(Insets[] typeInsetsMap, @InsetType int typeMask) {
181         Insets result = null;
182         for (int i = FIRST; i <= LAST; i = i << 1) {
183             if ((typeMask & i) == 0) {
184                 continue;
185             }
186             Insets insets = typeInsetsMap[indexOf(i)];
187             if (insets == null) {
188                 continue;
189             }
190             if (result == null) {
191                 result = insets;
192             } else {
193                 result = Insets.max(result, insets);
194             }
195         }
196         return result == null ? Insets.NONE : result;
197     }
198 
199     /**
200      * Sets all entries in {@code typeInsetsMap} that belong to {@code typeMask} to {@code insets},
201      */
setInsets(Insets[] typeInsetsMap, @InsetType int typeMask, Insets insets)202     private static void setInsets(Insets[] typeInsetsMap, @InsetType int typeMask, Insets insets) {
203         for (int i = FIRST; i <= LAST; i = i << 1) {
204             if ((typeMask & i) == 0) {
205                 continue;
206             }
207             typeInsetsMap[indexOf(i)] = insets;
208         }
209     }
210 
211     /** @hide */
212     @UnsupportedAppUsage
WindowInsets(Rect systemWindowInsets)213     public WindowInsets(Rect systemWindowInsets) {
214         this(createCompatTypeMap(systemWindowInsets), null, new boolean[SIZE], false, false, null);
215     }
216 
217     /**
218      * Creates a indexOf(type) -> inset map for which the {@code insets} is just mapped to
219      * {@link InsetType#topBar()} and {@link InsetType#sideBars()}, depending on the location of the
220      * inset.
221      */
createCompatTypeMap(@ullable Rect insets)222     private static Insets[] createCompatTypeMap(@Nullable Rect insets) {
223         if (insets == null) {
224             return null;
225         }
226         Insets[] typeInsetMap = new Insets[SIZE];
227         assignCompatInsets(typeInsetMap, insets);
228         return typeInsetMap;
229     }
230 
231     /**
232      * @hide
233      */
assignCompatInsets(Insets[] typeInsetMap, Rect insets)234     static void assignCompatInsets(Insets[] typeInsetMap, Rect insets) {
235         typeInsetMap[indexOf(TOP_BAR)] = Insets.of(0, insets.top, 0, 0);
236         typeInsetMap[indexOf(SIDE_BARS)] = Insets.of(insets.left, 0, insets.right, insets.bottom);
237     }
238 
createCompatVisibilityMap(@ullable Insets[] typeInsetMap)239     private static boolean[] createCompatVisibilityMap(@Nullable Insets[] typeInsetMap) {
240         boolean[] typeVisibilityMap = new boolean[SIZE];
241         if (typeInsetMap == null) {
242             return typeVisibilityMap;
243         }
244         for (int i = FIRST; i <= LAST; i = i << 1) {
245             int index = indexOf(i);
246             if (!Insets.NONE.equals(typeInsetMap[index])) {
247                 typeVisibilityMap[index] = true;
248             }
249         }
250         return typeVisibilityMap;
251     }
252 
253     /**
254      * Used to provide a safe copy of the system window insets to pass through
255      * to the existing fitSystemWindows method and other similar internals.
256      * @hide
257      *
258      * @deprecated use {@link #getSystemWindowInsets()} instead.
259      */
260     @Deprecated
261     @NonNull
getSystemWindowInsetsAsRect()262     public Rect getSystemWindowInsetsAsRect() {
263         if (mTempRect == null) {
264             mTempRect = new Rect();
265         }
266         Insets insets = getSystemWindowInsets();
267         mTempRect.set(insets.left, insets.top, insets.right, insets.bottom);
268         return mTempRect;
269     }
270 
271     /**
272      * Returns the system window insets in pixels.
273      *
274      * <p>The system window inset represents the area of a full-screen window that is
275      * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
276      * </p>
277      *
278      * @return The system window insets
279      */
280     @NonNull
getSystemWindowInsets()281     public Insets getSystemWindowInsets() {
282         return getInsets(mTypeInsetsMap, compatSystemInsets());
283     }
284 
285     /**
286      * Returns the insets of a specific set of windows causing insets, denoted by the
287      * {@code typeMask} bit mask of {@link InsetType}s.
288      *
289      * @param typeMask Bit mask of {@link InsetType}s to query the insets for.
290      * @return The insets.
291      *
292      * @hide pending unhide
293      */
getInsets(@nsetType int typeMask)294     public Insets getInsets(@InsetType int typeMask) {
295         return getInsets(mTypeInsetsMap, typeMask);
296     }
297 
298     /**
299      * Returns the maximum amount of insets a specific set of windows can cause, denoted by the
300      * {@code typeMask} bit mask of {@link InsetType}s.
301      *
302      * <p>The maximum insets represents the area of a a window that that <b>may</b> be partially
303      * or fully obscured by the system window identified by {@code type}. This value does not
304      * change based on the visibility state of those elements. for example, if the status bar is
305      * normally shown, but temporarily hidden, the maximum inset will still provide the inset
306      * associated with the status bar being shown.</p>
307      *
308      * @param typeMask Bit mask of {@link InsetType}s to query the insets for.
309      * @return The insets.
310      *
311      * @throws IllegalArgumentException If the caller tries to query {@link Type#ime()}. Maximum
312      *                                  insets are not available for this type as the height of the
313      *                                  IME is dynamic depending on the {@link EditorInfo} of the
314      *                                  currently focused view, as well as the UI state of the IME.
315      * @hide pending unhide
316      */
getMaxInsets(@nsetType int typeMask)317     public Insets getMaxInsets(@InsetType int typeMask) throws IllegalArgumentException {
318         if ((typeMask & IME) != 0) {
319             throw new IllegalArgumentException("Unable to query the maximum insets for IME");
320         }
321         return getInsets(mTypeMaxInsetsMap, typeMask);
322     }
323 
324     /**
325      * Returns whether a set of windows that may cause insets is currently visible on screen,
326      * regardless of whether it actually overlaps with this window.
327      *
328      * @param typeMask Bit mask of {@link InsetType}s to query visibility status.
329      * @return {@code true} if and only if all windows included in {@code typeMask} are currently
330      *         visible on screen.
331      * @hide pending unhide
332      */
isVisible(@nsetType int typeMask)333     public boolean isVisible(@InsetType int typeMask) {
334         for (int i = FIRST; i <= LAST; i = i << 1) {
335             if ((typeMask & i) == 0) {
336                 continue;
337             }
338             if (!mTypeVisibilityMap[indexOf(i)]) {
339                 return false;
340             }
341         }
342         return true;
343     }
344 
345     /**
346      * Returns the left system window inset in pixels.
347      *
348      * <p>The system window inset represents the area of a full-screen window that is
349      * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
350      * </p>
351      *
352      * @return The left system window inset
353      */
getSystemWindowInsetLeft()354     public int getSystemWindowInsetLeft() {
355         return getSystemWindowInsets().left;
356     }
357 
358     /**
359      * Returns the top system window inset in pixels.
360      *
361      * <p>The system window inset represents the area of a full-screen window that is
362      * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
363      * </p>
364      *
365      * @return The top system window inset
366      */
getSystemWindowInsetTop()367     public int getSystemWindowInsetTop() {
368         return getSystemWindowInsets().top;
369     }
370 
371     /**
372      * Returns the right system window inset in pixels.
373      *
374      * <p>The system window inset represents the area of a full-screen window that is
375      * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
376      * </p>
377      *
378      * @return The right system window inset
379      */
getSystemWindowInsetRight()380     public int getSystemWindowInsetRight() {
381         return getSystemWindowInsets().right;
382     }
383 
384     /**
385      * Returns the bottom 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 bottom system window inset
392      */
getSystemWindowInsetBottom()393     public int getSystemWindowInsetBottom() {
394         return getSystemWindowInsets().bottom;
395     }
396 
397     /**
398      * Returns true if this WindowInsets has nonzero system window insets.
399      *
400      * <p>The system window inset represents the area of a full-screen window that is
401      * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
402      * </p>
403      *
404      * @return true if any of the system window inset values are nonzero
405      */
hasSystemWindowInsets()406     public boolean hasSystemWindowInsets() {
407         return !getSystemWindowInsets().equals(Insets.NONE);
408     }
409 
410     /**
411      * Returns true if this WindowInsets has any nonzero insets.
412      *
413      * @return true if any inset values are nonzero
414      */
hasInsets()415     public boolean hasInsets() {
416         return !getInsets(mTypeInsetsMap, all()).equals(Insets.NONE)
417                 || !getInsets(mTypeMaxInsetsMap, all()).equals(Insets.NONE)
418                 || mDisplayCutout != null;
419     }
420 
421     /**
422      * Returns the display cutout if there is one.
423      *
424      * @return the display cutout or null if there is none
425      * @see DisplayCutout
426      */
427     @Nullable
getDisplayCutout()428     public DisplayCutout getDisplayCutout() {
429         return mDisplayCutout;
430     }
431 
432     /**
433      * Returns a copy of this WindowInsets with the cutout fully consumed.
434      *
435      * @return A modified copy of this WindowInsets
436      */
437     @NonNull
consumeDisplayCutout()438     public WindowInsets consumeDisplayCutout() {
439         return new WindowInsets(mSystemWindowInsetsConsumed ? null : mTypeInsetsMap,
440                 mStableInsetsConsumed ? null : mTypeMaxInsetsMap,
441                 mTypeVisibilityMap,
442                 mIsRound, mAlwaysConsumeSystemBars,
443                 null /* displayCutout */);
444     }
445 
446 
447     /**
448      * Check if these insets have been fully consumed.
449      *
450      * <p>Insets are considered "consumed" if the applicable <code>consume*</code> methods
451      * have been called such that all insets have been set to zero. This affects propagation of
452      * insets through the view hierarchy; insets that have not been fully consumed will continue
453      * to propagate down to child views.</p>
454      *
455      * <p>The result of this method is equivalent to the return value of
456      * {@link View#fitSystemWindows(android.graphics.Rect)}.</p>
457      *
458      * @return true if the insets have been fully consumed.
459      */
isConsumed()460     public boolean isConsumed() {
461         return mSystemWindowInsetsConsumed && mStableInsetsConsumed
462                 && mDisplayCutoutConsumed;
463     }
464 
465     /**
466      * Returns true if the associated window has a round shape.
467      *
468      * <p>A round window's left, top, right and bottom edges reach all the way to the
469      * associated edges of the window but the corners may not be visible. Views responding
470      * to round insets should take care to not lay out critical elements within the corners
471      * where they may not be accessible.</p>
472      *
473      * @return True if the window is round
474      */
isRound()475     public boolean isRound() {
476         return mIsRound;
477     }
478 
479     /**
480      * Returns a copy of this WindowInsets with the system window insets fully consumed.
481      *
482      * @return A modified copy of this WindowInsets
483      */
484     @NonNull
consumeSystemWindowInsets()485     public WindowInsets consumeSystemWindowInsets() {
486         return new WindowInsets(null, mStableInsetsConsumed ? null : mTypeMaxInsetsMap,
487                 mTypeVisibilityMap,
488                 mIsRound, mAlwaysConsumeSystemBars,
489                 displayCutoutCopyConstructorArgument(this));
490     }
491 
492     // TODO(b/119190588): replace @code with @link below
493     /**
494      * Returns a copy of this WindowInsets with selected system window insets replaced
495      * with new values.
496      *
497      * <p>Note: If the system window insets are already consumed, this method will return them
498      * unchanged on {@link android.os.Build.VERSION_CODES#Q Q} and later. Prior to
499      * {@link android.os.Build.VERSION_CODES#Q Q}, the new values were applied regardless of
500      * whether they were consumed, and this method returns invalid non-zero consumed insets.
501      *
502      * @param left New left inset in pixels
503      * @param top New top inset in pixels
504      * @param right New right inset in pixels
505      * @param bottom New bottom inset in pixels
506      * @return A modified copy of this WindowInsets
507      * @deprecated use {@code Builder#Builder(WindowInsets)} with
508      *             {@link Builder#setSystemWindowInsets(Insets)} instead.
509      */
510     @Deprecated
511     @NonNull
replaceSystemWindowInsets(int left, int top, int right, int bottom)512     public WindowInsets replaceSystemWindowInsets(int left, int top, int right, int bottom) {
513         // Compat edge case: what should this do if the insets have already been consumed?
514         // On platforms prior to Q, the behavior was to override the insets with non-zero values,
515         // but leave them consumed, which is invalid (consumed insets must be zero).
516         // The behavior is now keeping them consumed and discarding the new insets.
517         if (mSystemWindowInsetsConsumed) {
518             return this;
519         }
520         return new Builder(this).setSystemWindowInsets(Insets.of(left, top, right, bottom)).build();
521     }
522 
523     // TODO(b/119190588): replace @code with @link below
524     /**
525      * Returns a copy of this WindowInsets with selected system window insets replaced
526      * with new values.
527      *
528      * <p>Note: If the system window insets are already consumed, this method will return them
529      * unchanged on {@link android.os.Build.VERSION_CODES#Q Q} and later. Prior to
530      * {@link android.os.Build.VERSION_CODES#Q Q}, the new values were applied regardless of
531      * whether they were consumed, and this method returns invalid non-zero consumed insets.
532      *
533      * @param systemWindowInsets New system window insets. Each field is the inset in pixels
534      *                           for that edge
535      * @return A modified copy of this WindowInsets
536      * @deprecated use {@code Builder#Builder(WindowInsets)} with
537      *             {@link Builder#setSystemWindowInsets(Insets)} instead.
538      */
539     @Deprecated
540     @NonNull
replaceSystemWindowInsets(Rect systemWindowInsets)541     public WindowInsets replaceSystemWindowInsets(Rect systemWindowInsets) {
542         return replaceSystemWindowInsets(systemWindowInsets.left, systemWindowInsets.top,
543                 systemWindowInsets.right, systemWindowInsets.bottom);
544     }
545 
546     /**
547      * Returns the stable insets in pixels.
548      *
549      * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
550      * partially or fully obscured by the system UI elements.  This value does not change
551      * based on the visibility state of those elements; for example, if the status bar is
552      * normally shown, but temporarily hidden, the stable inset will still provide the inset
553      * associated with the status bar being shown.</p>
554      *
555      * @return The stable insets
556      */
557     @NonNull
getStableInsets()558     public Insets getStableInsets() {
559         return getInsets(mTypeMaxInsetsMap, compatSystemInsets());
560     }
561 
562     /**
563      * Returns the top stable inset in pixels.
564      *
565      * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
566      * partially or fully obscured by the system UI elements.  This value does not change
567      * based on the visibility state of those elements; for example, if the status bar is
568      * normally shown, but temporarily hidden, the stable inset will still provide the inset
569      * associated with the status bar being shown.</p>
570      *
571      * @return The top stable inset
572      */
getStableInsetTop()573     public int getStableInsetTop() {
574         return getStableInsets().top;
575     }
576 
577     /**
578      * Returns the left stable inset in pixels.
579      *
580      * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
581      * partially or fully obscured by the system UI elements.  This value does not change
582      * based on the visibility state of those elements; for example, if the status bar is
583      * normally shown, but temporarily hidden, the stable inset will still provide the inset
584      * associated with the status bar being shown.</p>
585      *
586      * @return The left stable inset
587      */
getStableInsetLeft()588     public int getStableInsetLeft() {
589         return getStableInsets().left;
590     }
591 
592     /**
593      * Returns the right stable inset in pixels.
594      *
595      * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
596      * partially or fully obscured by the system UI elements.  This value does not change
597      * based on the visibility state of those elements; for example, if the status bar is
598      * normally shown, but temporarily hidden, the stable inset will still provide the inset
599      * associated with the status bar being shown.</p>
600      *
601      * @return The right stable inset
602      */
getStableInsetRight()603     public int getStableInsetRight() {
604         return getStableInsets().right;
605     }
606 
607     /**
608      * Returns the bottom stable inset in pixels.
609      *
610      * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
611      * partially or fully obscured by the system UI elements.  This value does not change
612      * based on the visibility state of those elements; for example, if the status bar is
613      * normally shown, but temporarily hidden, the stable inset will still provide the inset
614      * associated with the status bar being shown.</p>
615      *
616      * @return The bottom stable inset
617      */
getStableInsetBottom()618     public int getStableInsetBottom() {
619         return getStableInsets().bottom;
620     }
621 
622     /**
623      * Returns true if this WindowInsets has nonzero stable insets.
624      *
625      * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
626      * partially or fully obscured by the system UI elements.  This value does not change
627      * based on the visibility state of those elements; for example, if the status bar is
628      * normally shown, but temporarily hidden, the stable inset will still provide the inset
629      * associated with the status bar being shown.</p>
630      *
631      * @return true if any of the stable inset values are nonzero
632      */
hasStableInsets()633     public boolean hasStableInsets() {
634         return !getStableInsets().equals(Insets.NONE);
635     }
636 
637     /**
638      * Returns the system gesture insets.
639      *
640      * <p>The system gesture insets represent the area of a window where system gestures have
641      * priority and may consume some or all touch input, e.g. due to the a system bar
642      * occupying it, or it being reserved for touch-only gestures.
643      *
644      * <p>An app can declare priority over system gestures with
645      * {@link View#setSystemGestureExclusionRects} outside of the
646      * {@link #getMandatorySystemGestureInsets() mandatory system gesture insets}.
647      *
648      * <p>Note: the system will put a limit of <code>200dp</code> on the vertical extent of the
649      * exclusions it takes into account. The limit does not apply while the navigation
650      * bar is {@link View#SYSTEM_UI_FLAG_IMMERSIVE_STICKY stickily} hidden, nor to the
651      * {@link android.inputmethodservice.InputMethodService input method} and
652      * {@link Intent#CATEGORY_HOME home activity}.
653      * </p>
654      *
655      *
656      * <p>Simple taps are guaranteed to reach the window even within the system gesture insets,
657      * as long as they are outside the {@link #getTappableElementInsets() system window insets}.
658      *
659      * <p>When {@link View#SYSTEM_UI_FLAG_LAYOUT_STABLE} is requested, an inset will be returned
660      * even when the system gestures are inactive due to
661      * {@link View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} or
662      * {@link View#SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}.
663      *
664      * <p>This inset is consumed together with the {@link #getSystemWindowInsets()
665      * system window insets} by {@link #consumeSystemWindowInsets()}.
666      *
667      * @see #getMandatorySystemGestureInsets
668      */
669     @NonNull
getSystemGestureInsets()670     public Insets getSystemGestureInsets() {
671         return getInsets(mTypeInsetsMap, SYSTEM_GESTURES);
672     }
673 
674     /**
675      * Returns the mandatory system gesture insets.
676      *
677      * <p>The mandatory system gesture insets represent the area of a window where mandatory system
678      * gestures have priority and may consume some or all touch input, e.g. due to the a system bar
679      * occupying it, or it being reserved for touch-only gestures.
680      *
681      * <p>In contrast to {@link #getSystemGestureInsets regular system gestures}, <b>mandatory</b>
682      * system gestures cannot be overriden by {@link View#setSystemGestureExclusionRects}.
683      *
684      * <p>Simple taps are guaranteed to reach the window even within the system gesture insets,
685      * as long as they are outside the {@link #getTappableElementInsets() system window insets}.
686      *
687      * <p>When {@link View#SYSTEM_UI_FLAG_LAYOUT_STABLE} is requested, an inset will be returned
688      * even when the system gestures are inactive due to
689      * {@link View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} or
690      * {@link View#SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}.
691      *
692      * <p>This inset is consumed together with the {@link #getSystemWindowInsets()
693      * system window insets} by {@link #consumeSystemWindowInsets()}.
694      *
695      * @see #getSystemGestureInsets
696      */
697     @NonNull
getMandatorySystemGestureInsets()698     public Insets getMandatorySystemGestureInsets() {
699         return getInsets(mTypeInsetsMap, MANDATORY_SYSTEM_GESTURES);
700     }
701 
702     /**
703      * Returns the tappable element insets.
704      *
705      * <p>The tappable element insets represent how much tappable elements <b>must at least</b> be
706      * inset to remain both tappable and visually unobstructed by persistent system windows.
707      *
708      * <p>This may be smaller than {@link #getSystemWindowInsets()} if the system window is
709      * largely transparent and lets through simple taps (but not necessarily more complex gestures).
710      *
711      * <p>Note that generally, tappable elements <strong>should</strong> be aligned with the
712      * {@link #getSystemWindowInsets() system window insets} instead to avoid overlapping with the
713      * system bars.
714      *
715      * <p>When {@link View#SYSTEM_UI_FLAG_LAYOUT_STABLE} is requested, an inset will be returned
716      * even when the area covered by the inset would be tappable due to
717      * {@link View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} or
718      * {@link View#SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}.
719      *
720      * <p>This inset is consumed together with the {@link #getSystemWindowInsets()
721      * system window insets} by {@link #consumeSystemWindowInsets()}.
722      */
723     @NonNull
getTappableElementInsets()724     public Insets getTappableElementInsets() {
725         return getInsets(mTypeInsetsMap, TAPPABLE_ELEMENT);
726     }
727 
728     /**
729      * Returns a copy of this WindowInsets with the stable insets fully consumed.
730      *
731      * @return A modified copy of this WindowInsets
732      */
733     @NonNull
consumeStableInsets()734     public WindowInsets consumeStableInsets() {
735         return new WindowInsets(mSystemWindowInsetsConsumed ? null : mTypeInsetsMap, null,
736                 mTypeVisibilityMap, mIsRound, mAlwaysConsumeSystemBars,
737                 displayCutoutCopyConstructorArgument(this));
738     }
739 
740     /**
741      * @hide
742      */
shouldAlwaysConsumeSystemBars()743     public boolean shouldAlwaysConsumeSystemBars() {
744         return mAlwaysConsumeSystemBars;
745     }
746 
747     @Override
toString()748     public String toString() {
749         return "WindowInsets{systemWindowInsets=" + getSystemWindowInsets()
750                 + " stableInsets=" + getStableInsets()
751                 + " sysGestureInsets=" + getSystemGestureInsets()
752                 + (mDisplayCutout != null ? " cutout=" + mDisplayCutout : "")
753                 + (isRound() ? " round" : "")
754                 + "}";
755     }
756 
757     /**
758      * Returns a copy of this instance inset in the given directions.
759      *
760      * @see #inset(int, int, int, int)
761      * @deprecated use {@link #inset(Insets)}
762      * @hide
763      */
764     @Deprecated
765     @NonNull
inset(Rect r)766     public WindowInsets inset(Rect r) {
767         return inset(r.left, r.top, r.right, r.bottom);
768     }
769 
770     /**
771      * Returns a copy of this instance inset in the given directions.
772      *
773      * @see #inset(int, int, int, int)
774      * @hide
775      */
776     @NonNull
inset(Insets insets)777     public WindowInsets inset(Insets insets) {
778         return inset(insets.left, insets.top, insets.right, insets.bottom);
779     }
780 
781     /**
782      * Returns a copy of this instance inset in the given directions.
783      *
784      * This is intended for dispatching insets to areas of the window that are smaller than the
785      * current area.
786      *
787      * <p>Example:
788      * <pre>
789      * childView.dispatchApplyWindowInsets(insets.inset(
790      *         childMarginLeft, childMarginTop, childMarginBottom, childMarginRight));
791      * </pre>
792      *
793      * @param left the amount of insets to remove from the left. Must be non-negative.
794      * @param top the amount of insets to remove from the top. Must be non-negative.
795      * @param right the amount of insets to remove from the right. Must be non-negative.
796      * @param bottom the amount of insets to remove from the bottom. Must be non-negative.
797      *
798      * @return the inset insets
799      */
800     @NonNull
inset(@ntRangefrom = 0) int left, @IntRange(from = 0) int top, @IntRange(from = 0) int right, @IntRange(from = 0) int bottom)801     public WindowInsets inset(@IntRange(from = 0) int left, @IntRange(from = 0) int top,
802             @IntRange(from = 0) int right, @IntRange(from = 0) int bottom) {
803         Preconditions.checkArgumentNonnegative(left);
804         Preconditions.checkArgumentNonnegative(top);
805         Preconditions.checkArgumentNonnegative(right);
806         Preconditions.checkArgumentNonnegative(bottom);
807 
808         return new WindowInsets(
809                 mSystemWindowInsetsConsumed
810                         ? null
811                         : insetInsets(mTypeInsetsMap, left, top, right, bottom),
812                 mStableInsetsConsumed
813                         ? null
814                         : insetInsets(mTypeMaxInsetsMap, left, top, right, bottom),
815                 mTypeVisibilityMap,
816                 mIsRound, mAlwaysConsumeSystemBars,
817                 mDisplayCutoutConsumed
818                         ? null
819                         : mDisplayCutout == null
820                                 ? DisplayCutout.NO_CUTOUT
821                                 : mDisplayCutout.inset(left, top, right, bottom));
822     }
823 
824     @Override
equals(Object o)825     public boolean equals(Object o) {
826         if (this == o) return true;
827         if (o == null || !(o instanceof WindowInsets)) return false;
828         WindowInsets that = (WindowInsets) o;
829 
830         return mIsRound == that.mIsRound
831                 && mAlwaysConsumeSystemBars == that.mAlwaysConsumeSystemBars
832                 && mSystemWindowInsetsConsumed == that.mSystemWindowInsetsConsumed
833                 && mStableInsetsConsumed == that.mStableInsetsConsumed
834                 && mDisplayCutoutConsumed == that.mDisplayCutoutConsumed
835                 && Arrays.equals(mTypeInsetsMap, that.mTypeInsetsMap)
836                 && Arrays.equals(mTypeMaxInsetsMap, that.mTypeMaxInsetsMap)
837                 && Arrays.equals(mTypeVisibilityMap, that.mTypeVisibilityMap)
838                 && Objects.equals(mDisplayCutout, that.mDisplayCutout);
839     }
840 
841     @Override
hashCode()842     public int hashCode() {
843         return Objects.hash(Arrays.hashCode(mTypeInsetsMap), Arrays.hashCode(mTypeMaxInsetsMap),
844                 Arrays.hashCode(mTypeVisibilityMap), mIsRound, mDisplayCutout,
845                 mAlwaysConsumeSystemBars, mSystemWindowInsetsConsumed, mStableInsetsConsumed,
846                 mDisplayCutoutConsumed);
847     }
848 
849 
850     /**
851      * Insets every inset in {@code typeInsetsMap} by the specified left, top, right, bottom.
852      *
853      * @return {@code typeInsetsMap} if no inset was modified; a copy of the map with the modified
854      *          insets otherwise.
855      */
insetInsets( Insets[] typeInsetsMap, int left, int top, int right, int bottom)856     private static Insets[] insetInsets(
857             Insets[] typeInsetsMap, int left, int top, int right, int bottom) {
858         boolean cloned = false;
859         for (int i = 0; i < SIZE; i++) {
860             Insets insets = typeInsetsMap[i];
861             if (insets == null) {
862                 continue;
863             }
864             Insets insetInsets = insetInsets(insets, left, top, right, bottom);
865             if (insetInsets != insets) {
866                 if (!cloned) {
867                     typeInsetsMap = typeInsetsMap.clone();
868                     cloned = true;
869                 }
870                 typeInsetsMap[i] = insetInsets;
871             }
872         }
873         return typeInsetsMap;
874     }
875 
insetInsets(Insets insets, int left, int top, int right, int bottom)876     private static Insets insetInsets(Insets insets, int left, int top, int right, int bottom) {
877         int newLeft = Math.max(0, insets.left - left);
878         int newTop = Math.max(0, insets.top - top);
879         int newRight = Math.max(0, insets.right - right);
880         int newBottom = Math.max(0, insets.bottom - bottom);
881         if (newLeft == left && newTop == top && newRight == right && newBottom == bottom) {
882             return insets;
883         }
884         return Insets.of(newLeft, newTop, newRight, newBottom);
885     }
886 
887     /**
888      * @return whether system window insets have been consumed.
889      */
isSystemWindowInsetsConsumed()890     boolean isSystemWindowInsetsConsumed() {
891         return mSystemWindowInsetsConsumed;
892     }
893 
894     /**
895      * Builder for WindowInsets.
896      */
897     public static final class Builder {
898 
899         private final Insets[] mTypeInsetsMap;
900         private final Insets[] mTypeMaxInsetsMap;
901         private final boolean[] mTypeVisibilityMap;
902         private boolean mSystemInsetsConsumed = true;
903         private boolean mStableInsetsConsumed = true;
904 
905         private DisplayCutout mDisplayCutout;
906 
907         private boolean mIsRound;
908         private boolean mAlwaysConsumeSystemBars;
909 
910         /**
911          * Creates a builder where all insets are initially consumed.
912          */
Builder()913         public Builder() {
914             mTypeInsetsMap = new Insets[SIZE];
915             mTypeMaxInsetsMap = new Insets[SIZE];
916             mTypeVisibilityMap = new boolean[SIZE];
917         }
918 
919         /**
920          * Creates a builder where all insets are initialized from {@link WindowInsets}.
921          *
922          * @param insets the instance to initialize from.
923          */
Builder(@onNull WindowInsets insets)924         public Builder(@NonNull WindowInsets insets) {
925             mTypeInsetsMap = insets.mTypeInsetsMap.clone();
926             mTypeMaxInsetsMap = insets.mTypeMaxInsetsMap.clone();
927             mTypeVisibilityMap = insets.mTypeVisibilityMap.clone();
928             mSystemInsetsConsumed = insets.mSystemWindowInsetsConsumed;
929             mStableInsetsConsumed = insets.mStableInsetsConsumed;
930             mDisplayCutout = displayCutoutCopyConstructorArgument(insets);
931             mIsRound = insets.mIsRound;
932             mAlwaysConsumeSystemBars = insets.mAlwaysConsumeSystemBars;
933         }
934 
935         /**
936          * Sets system window insets in pixels.
937          *
938          * <p>The system window inset represents the area of a full-screen window that is
939          * partially or fully obscured by the status bar, navigation bar, IME or other system
940          * windows.</p>
941          *
942          * @see #getSystemWindowInsets()
943          * @return itself
944          */
945         @NonNull
setSystemWindowInsets(@onNull Insets systemWindowInsets)946         public Builder setSystemWindowInsets(@NonNull Insets systemWindowInsets) {
947             Preconditions.checkNotNull(systemWindowInsets);
948             assignCompatInsets(mTypeInsetsMap, systemWindowInsets.toRect());
949             mSystemInsetsConsumed = false;
950             return this;
951         }
952 
953         /**
954          * Sets system gesture insets in pixels.
955          *
956          * <p>The system gesture insets represent the area of a window where system gestures have
957          * priority and may consume some or all touch input, e.g. due to the a system bar
958          * occupying it, or it being reserved for touch-only gestures.
959          *
960          * @see #getSystemGestureInsets()
961          * @return itself
962          */
963         @NonNull
setSystemGestureInsets(@onNull Insets insets)964         public Builder setSystemGestureInsets(@NonNull Insets insets) {
965             WindowInsets.setInsets(mTypeInsetsMap, SYSTEM_GESTURES, insets);
966             return this;
967         }
968 
969         /**
970          * Sets mandatory system gesture insets in pixels.
971          *
972          * <p>The mandatory system gesture insets represent the area of a window where mandatory
973          * system gestures have priority and may consume some or all touch input, e.g. due to the a
974          * system bar occupying it, or it being reserved for touch-only gestures.
975          *
976          * <p>In contrast to {@link #setSystemGestureInsets regular system gestures},
977          * <b>mandatory</b> system gestures cannot be overriden by
978          * {@link View#setSystemGestureExclusionRects}.
979          *
980          * @see #getMandatorySystemGestureInsets()
981          * @return itself
982          */
983         @NonNull
setMandatorySystemGestureInsets(@onNull Insets insets)984         public Builder setMandatorySystemGestureInsets(@NonNull Insets insets) {
985             WindowInsets.setInsets(mTypeInsetsMap, MANDATORY_SYSTEM_GESTURES, insets);
986             return this;
987         }
988 
989         /**
990          * Sets tappable element insets in pixels.
991          *
992          * <p>The tappable element insets represent how much tappable elements <b>must at least</b>
993          * be inset to remain both tappable and visually unobstructed by persistent system windows.
994          *
995          * @see #getTappableElementInsets()
996          * @return itself
997          */
998         @NonNull
setTappableElementInsets(@onNull Insets insets)999         public Builder setTappableElementInsets(@NonNull Insets insets) {
1000             WindowInsets.setInsets(mTypeInsetsMap, TAPPABLE_ELEMENT, insets);
1001             return this;
1002         }
1003 
1004         /**
1005          * Sets the insets of a specific window type in pixels.
1006          *
1007          * <p>The insets represents the area of a a window that is partially or fully obscured by
1008          * the system windows identified by {@code typeMask}.
1009          * </p>
1010          *
1011          * @see #getInsets(int)
1012          *
1013          * @param typeMask The bitmask of {@link InsetType} to set the insets for.
1014          * @param insets The insets to set.
1015          *
1016          * @return itself
1017          * @hide pending unhide
1018          */
1019         @NonNull
setInsets(@nsetType int typeMask, @NonNull Insets insets)1020         public Builder setInsets(@InsetType int typeMask, @NonNull Insets insets) {
1021             Preconditions.checkNotNull(insets);
1022             WindowInsets.setInsets(mTypeInsetsMap, typeMask, insets);
1023             mSystemInsetsConsumed = false;
1024             return this;
1025         }
1026 
1027         /**
1028          * Sets the maximum amount of insets a specific window type in pixels.
1029          *
1030          * <p>The maximum insets represents the area of a a window that that <b>may</b> be partially
1031          * or fully obscured by the system windows identified by {@code typeMask}. This value does
1032          * not change based on the visibility state of those elements. for example, if the status
1033          * bar is normally shown, but temporarily hidden, the maximum inset will still provide the
1034          * inset associated with the status bar being shown.</p>
1035          *
1036          * @see #getMaxInsets(int)
1037          *
1038          * @param typeMask The bitmask of {@link InsetType} to set the insets for.
1039          * @param insets The insets to set.
1040          *
1041          * @return itself
1042          *
1043          * @throws IllegalArgumentException If {@code typeMask} contains {@link Type#ime()}. Maximum
1044          *                                  insets are not available for this type as the height of
1045          *                                  the IME is dynamic depending on the {@link EditorInfo}
1046          *                                  of the currently focused view, as well as the UI
1047          *                                  state of the IME.
1048          * @hide pending unhide
1049          */
1050         @NonNull
setMaxInsets(@nsetType int typeMask, @NonNull Insets insets)1051         public Builder setMaxInsets(@InsetType int typeMask, @NonNull Insets insets)
1052                 throws IllegalArgumentException{
1053             if (typeMask == IME) {
1054                 throw new IllegalArgumentException("Maximum inset not available for IME");
1055             }
1056             Preconditions.checkNotNull(insets);
1057             WindowInsets.setInsets(mTypeMaxInsetsMap, typeMask, insets);
1058             mStableInsetsConsumed = false;
1059             return this;
1060         }
1061 
1062         /**
1063          * Sets whether windows that can cause insets are currently visible on screen.
1064          *
1065          *
1066          * @see #isVisible(int)
1067          *
1068          * @param typeMask The bitmask of {@link InsetType} to set the visibility for.
1069          * @param visible Whether to mark the windows as visible or not.
1070          *
1071          * @return itself
1072          * @hide pending unhide
1073          */
1074         @NonNull
setVisible(@nsetType int typeMask, boolean visible)1075         public Builder setVisible(@InsetType int typeMask, boolean visible) {
1076             for (int i = FIRST; i <= LAST; i = i << 1) {
1077                 if ((typeMask & i) == 0) {
1078                     continue;
1079                 }
1080                 mTypeVisibilityMap[indexOf(i)] = visible;
1081             }
1082             return this;
1083         }
1084 
1085         /**
1086          * Sets the stable insets in pixels.
1087          *
1088          * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
1089          * partially or fully obscured by the system UI elements.  This value does not change
1090          * based on the visibility state of those elements; for example, if the status bar is
1091          * normally shown, but temporarily hidden, the stable inset will still provide the inset
1092          * associated with the status bar being shown.</p>
1093          *
1094          * @see #getStableInsets()
1095          * @return itself
1096          */
1097         @NonNull
setStableInsets(@onNull Insets stableInsets)1098         public Builder setStableInsets(@NonNull Insets stableInsets) {
1099             Preconditions.checkNotNull(stableInsets);
1100             assignCompatInsets(mTypeMaxInsetsMap, stableInsets.toRect());
1101             mStableInsetsConsumed = false;
1102             return this;
1103         }
1104 
1105         /**
1106          * Sets the display cutout.
1107          *
1108          * @see #getDisplayCutout()
1109          * @param displayCutout the display cutout or null if there is none
1110          * @return itself
1111          */
1112         @NonNull
setDisplayCutout(@ullable DisplayCutout displayCutout)1113         public Builder setDisplayCutout(@Nullable DisplayCutout displayCutout) {
1114             mDisplayCutout = displayCutout != null ? displayCutout : DisplayCutout.NO_CUTOUT;
1115             return this;
1116         }
1117 
1118         /** @hide */
1119         @NonNull
setRound(boolean round)1120         public Builder setRound(boolean round) {
1121             mIsRound = round;
1122             return this;
1123         }
1124 
1125         /** @hide */
1126         @NonNull
setAlwaysConsumeSystemBars(boolean alwaysConsumeSystemBars)1127         public Builder setAlwaysConsumeSystemBars(boolean alwaysConsumeSystemBars) {
1128             mAlwaysConsumeSystemBars = alwaysConsumeSystemBars;
1129             return this;
1130         }
1131 
1132         /**
1133          * Builds a {@link WindowInsets} instance.
1134          *
1135          * @return the {@link WindowInsets} instance.
1136          */
1137         @NonNull
build()1138         public WindowInsets build() {
1139             return new WindowInsets(mSystemInsetsConsumed ? null : mTypeInsetsMap,
1140                     mStableInsetsConsumed ? null : mTypeMaxInsetsMap, mTypeVisibilityMap,
1141                     mIsRound, mAlwaysConsumeSystemBars, mDisplayCutout);
1142         }
1143     }
1144 
1145     /**
1146      * Class that defines different types of sources causing window insets.
1147      * @hide pending unhide
1148      */
1149     public static final class Type {
1150 
1151         static final int FIRST = 1 << 0;
1152         static final int TOP_BAR = FIRST;
1153 
1154         static final int IME = 1 << 1;
1155         static final int SIDE_BARS = 1 << 2;
1156 
1157         static final int SYSTEM_GESTURES = 1 << 3;
1158         static final int MANDATORY_SYSTEM_GESTURES = 1 << 4;
1159         static final int TAPPABLE_ELEMENT = 1 << 5;
1160 
1161         static final int LAST = 1 << 6;
1162         static final int SIZE = 7;
1163         static final int WINDOW_DECOR = LAST;
1164 
indexOf(@nsetType int type)1165         static int indexOf(@InsetType int type) {
1166             switch (type) {
1167                 case TOP_BAR:
1168                     return 0;
1169                 case IME:
1170                     return 1;
1171                 case SIDE_BARS:
1172                     return 2;
1173                 case SYSTEM_GESTURES:
1174                     return 3;
1175                 case MANDATORY_SYSTEM_GESTURES:
1176                     return 4;
1177                 case TAPPABLE_ELEMENT:
1178                     return 5;
1179                 case WINDOW_DECOR:
1180                     return 6;
1181                 default:
1182                     throw new IllegalArgumentException("type needs to be >= FIRST and <= LAST,"
1183                             + " type=" + type);
1184             }
1185         }
1186 
Type()1187         private Type() {
1188         }
1189 
1190         /** @hide */
1191         @Retention(RetentionPolicy.SOURCE)
1192         @IntDef(flag = true, value = { TOP_BAR, IME, SIDE_BARS, WINDOW_DECOR, SYSTEM_GESTURES,
1193                 MANDATORY_SYSTEM_GESTURES, TAPPABLE_ELEMENT})
1194         public @interface InsetType {
1195         }
1196 
1197         /**
1198          * @return An inset type representing the top bar of a window, which can be the status
1199          *         bar on handheld-like devices as well as a caption bar.
1200          */
topBar()1201         public static @InsetType int topBar() {
1202             return TOP_BAR;
1203         }
1204 
1205         /**
1206          * @return An inset type representing the window of an {@link InputMethod}.
1207          */
ime()1208         public static @InsetType int ime() {
1209             return IME;
1210         }
1211 
1212         /**
1213          * @return An inset type representing any system bars that are not {@link #topBar()}.
1214          */
sideBars()1215         public static @InsetType int sideBars() {
1216             return SIDE_BARS;
1217         }
1218 
1219         /**
1220          * @return An inset type representing decor that is being app-controlled.
1221          */
windowDecor()1222         public static @InsetType int windowDecor() {
1223             return WINDOW_DECOR;
1224         }
1225 
1226         /**
1227          * Returns an inset type representing the system gesture insets.
1228          *
1229          * <p>The system gesture insets represent the area of a window where system gestures have
1230          * priority and may consume some or all touch input, e.g. due to the a system bar
1231          * occupying it, or it being reserved for touch-only gestures.
1232          *
1233          * <p>Simple taps are guaranteed to reach the window even within the system gesture insets,
1234          * as long as they are outside the {@link #getSystemWindowInsets() system window insets}.
1235          *
1236          * <p>When {@link View#SYSTEM_UI_FLAG_LAYOUT_STABLE} is requested, an inset will be returned
1237          * even when the system gestures are inactive due to
1238          * {@link View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} or
1239          * {@link View#SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}.
1240          *
1241          * @see #getSystemGestureInsets()
1242          */
systemGestures()1243         public static @InsetType int systemGestures() {
1244             return SYSTEM_GESTURES;
1245         }
1246 
1247         /**
1248          * @see #getMandatorySystemGestureInsets
1249          */
mandatorySystemGestures()1250         public static @InsetType int mandatorySystemGestures() {
1251             return MANDATORY_SYSTEM_GESTURES;
1252         }
1253 
1254         /**
1255          * @see #getTappableElementInsets
1256          */
tappableElement()1257         public static @InsetType int tappableElement() {
1258             return TAPPABLE_ELEMENT;
1259         }
1260 
1261         /**
1262          * @return All system bars. Includes {@link #topBar()} as well as {@link #sideBars()}, but
1263          *         not {@link #ime()}.
1264          */
systemBars()1265         public static @InsetType int systemBars() {
1266             return TOP_BAR | SIDE_BARS;
1267         }
1268 
1269         /**
1270          * @return Inset types representing the list of bars that traditionally were denoted as
1271          *         system insets.
1272          * @hide
1273          */
compatSystemInsets()1274         static @InsetType int compatSystemInsets() {
1275             return TOP_BAR | SIDE_BARS | IME;
1276         }
1277 
1278         /**
1279          * @return All inset types combined.
1280          *
1281          * TODO: Figure out if this makes sense at all, mixing e.g {@link #systemGestures()} and
1282          *       {@link #ime()} does not seem very useful.
1283          */
all()1284         public static @InsetType int all() {
1285             return 0xFFFFFFFF;
1286         }
1287     }
1288 }
1289