blob: bcc6a552f569850fdf1f1fa5cea4a521ac1baf5f [file] [log] [blame]
Adam Powell50d7bfd2014-02-03 10:16:49 -08001/*
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
18package android.view;
19
Jorim Jaggi297985a2018-11-30 17:24:58 +010020import static android.view.WindowInsets.Type.FIRST;
Jorim Jaggibcf99ff2018-12-03 18:04:26 +010021import static android.view.WindowInsets.Type.IME;
Jorim Jaggi297985a2018-11-30 17:24:58 +010022import static android.view.WindowInsets.Type.LAST;
Adrian Roos15ab5192019-03-13 18:23:05 -070023import static android.view.WindowInsets.Type.MANDATORY_SYSTEM_GESTURES;
Jorim Jaggi297985a2018-11-30 17:24:58 +010024import static android.view.WindowInsets.Type.SIDE_BARS;
25import static android.view.WindowInsets.Type.SIZE;
Adrian Roosdd49eb72019-02-26 19:38:10 +010026import static android.view.WindowInsets.Type.SYSTEM_GESTURES;
Adrian Roos15ab5192019-03-13 18:23:05 -070027import static android.view.WindowInsets.Type.TAPPABLE_ELEMENT;
Jorim Jaggi297985a2018-11-30 17:24:58 +010028import static android.view.WindowInsets.Type.TOP_BAR;
29import static android.view.WindowInsets.Type.all;
30import static android.view.WindowInsets.Type.compatSystemInsets;
31import static android.view.WindowInsets.Type.indexOf;
32
Jorim Jaggib6030952018-10-23 18:31:52 +020033import android.annotation.IntDef;
Adrian Roos9e860352019-02-26 18:28:41 +010034import android.annotation.IntRange;
Jorim Jaggi297985a2018-11-30 17:24:58 +010035import android.annotation.NonNull;
Adrian Roosd07bafd2017-12-11 17:30:56 +010036import android.annotation.Nullable;
Mathew Inwooda570dee2018-08-17 14:56:00 +010037import android.annotation.UnsupportedAppUsage;
Adrian Roose6feb7d2019-07-25 20:29:07 +020038import android.content.Intent;
Adrian Roos60f59292018-08-24 16:29:06 +020039import android.graphics.Insets;
Adam Powell50d7bfd2014-02-03 10:16:49 -080040import android.graphics.Rect;
Jorim Jaggi297985a2018-11-30 17:24:58 +010041import android.util.SparseArray;
42import android.view.WindowInsets.Type.InsetType;
Jorim Jaggibcf99ff2018-12-03 18:04:26 +010043import android.view.inputmethod.EditorInfo;
Jorim Jaggib6030952018-10-23 18:31:52 +020044import android.view.inputmethod.InputMethod;
Adam Powell50d7bfd2014-02-03 10:16:49 -080045
Adrian Roosf7b74262017-11-22 14:21:01 +010046import com.android.internal.util.Preconditions;
47
Jorim Jaggib6030952018-10-23 18:31:52 +020048import java.lang.annotation.Retention;
49import java.lang.annotation.RetentionPolicy;
Jorim Jaggi297985a2018-11-30 17:24:58 +010050import java.util.Arrays;
Adrian Roosf7b74262017-11-22 14:21:01 +010051import java.util.Objects;
52
Adam Powell50d7bfd2014-02-03 10:16:49 -080053/**
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 *
Adrian Roosf7b74262017-11-22 14:21:01 +010060 * <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 *
Adam Powell50d7bfd2014-02-03 10:16:49 -080066 * @see View.OnApplyWindowInsetsListener
67 * @see View#onApplyWindowInsets(WindowInsets)
68 */
Adam Powellf4a39412014-05-05 17:29:17 -070069public final class WindowInsets {
Adrian Roosfa104232014-06-20 16:10:14 -070070
Jorim Jaggi297985a2018-11-30 17:24:58 +010071 private final Insets[] mTypeInsetsMap;
72 private final Insets[] mTypeMaxInsetsMap;
Jorim Jaggi90990792019-01-21 23:00:20 +010073 private final boolean[] mTypeVisibilityMap;
Jorim Jaggi297985a2018-11-30 17:24:58 +010074
Adrian Roos60f59292018-08-24 16:29:06 +020075 @Nullable private Rect mTempRect;
76 private final boolean mIsRound;
77 @Nullable private final DisplayCutout mDisplayCutout;
Adam Powell50d7bfd2014-02-03 10:16:49 -080078
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -080079 /**
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 */
Brad Stenninge0573692019-03-11 13:52:46 -070084 private final boolean mAlwaysConsumeSystemBars;
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -080085
Adrian Roos60f59292018-08-24 16:29:06 +020086 private final boolean mSystemWindowInsetsConsumed;
Adrian Roos60f59292018-08-24 16:29:06 +020087 private final boolean mStableInsetsConsumed;
88 private final boolean mDisplayCutoutConsumed;
Adam Powell50d7bfd2014-02-03 10:16:49 -080089
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 */
Mathew Inwooda570dee2018-08-17 14:56:00 +010096 @UnsupportedAppUsage
Adam Powell720924b2014-06-12 14:51:10 -070097 public static final WindowInsets CONSUMED;
98
99 static {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100100 CONSUMED = new WindowInsets((Rect) null, null, false, false, null);
Adam Powell720924b2014-06-12 14:51:10 -0700101 }
Adam Powell50d7bfd2014-02-03 10:16:49 -0800102
Adrian Roosb8493862018-11-14 06:50:55 -0800103 /**
104 * Construct a new WindowInsets from individual insets.
105 *
106 * A {@code null} inset indicates that the respective inset is consumed.
107 *
108 * @hide
Jorim Jaggi297985a2018-11-30 17:24:58 +0100109 * @deprecated Use {@link WindowInsets(SparseArray, SparseArray, boolean, boolean, DisplayCutout)}
Adrian Roosb8493862018-11-14 06:50:55 -0800110 */
Jorim Jaggi297985a2018-11-30 17:24:58 +0100111 public WindowInsets(Rect systemWindowInsetsRect, Rect stableInsetsRect,
Brad Stenninge0573692019-03-11 13:52:46 -0700112 boolean isRound, boolean alwaysConsumeSystemBars, DisplayCutout displayCutout) {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100113 this(createCompatTypeMap(systemWindowInsetsRect), createCompatTypeMap(stableInsetsRect),
Jorim Jaggi90990792019-01-21 23:00:20 +0100114 createCompatVisibilityMap(createCompatTypeMap(systemWindowInsetsRect)),
Brad Stenninge0573692019-03-11 13:52:46 -0700115 isRound, alwaysConsumeSystemBars, displayCutout);
Adrian Roos60f59292018-08-24 16:29:06 +0200116 }
117
Jorim Jaggi297985a2018-11-30 17:24:58 +0100118 /**
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 */
130 public WindowInsets(@Nullable Insets[] typeInsetsMap,
Jorim Jaggi90990792019-01-21 23:00:20 +0100131 @Nullable Insets[] typeMaxInsetsMap,
132 boolean[] typeVisibilityMap,
133 boolean isRound,
Brad Stenninge0573692019-03-11 13:52:46 -0700134 boolean alwaysConsumeSystemBars, DisplayCutout displayCutout) {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100135 mSystemWindowInsetsConsumed = typeInsetsMap == null;
136 mTypeInsetsMap = mSystemWindowInsetsConsumed
137 ? new Insets[SIZE]
138 : typeInsetsMap.clone();
Adam Powell0d9fdba2014-06-11 15:33:08 -0700139
Jorim Jaggi297985a2018-11-30 17:24:58 +0100140 mStableInsetsConsumed = typeMaxInsetsMap == null;
141 mTypeMaxInsetsMap = mStableInsetsConsumed
142 ? new Insets[SIZE]
143 : typeMaxInsetsMap.clone();
Adrian Roosfa104232014-06-20 16:10:14 -0700144
Jorim Jaggi90990792019-01-21 23:00:20 +0100145 mTypeVisibilityMap = typeVisibilityMap;
Adam Powell973ddaa2014-04-15 17:38:54 -0700146 mIsRound = isRound;
Brad Stenninge0573692019-03-11 13:52:46 -0700147 mAlwaysConsumeSystemBars = alwaysConsumeSystemBars;
Adrian Roosd4970af2017-11-10 15:48:01 +0100148
Adrian Roosd07bafd2017-12-11 17:30:56 +0100149 mDisplayCutoutConsumed = displayCutout == null;
150 mDisplayCutout = (mDisplayCutoutConsumed || displayCutout.isEmpty())
151 ? null : displayCutout;
Adam Powell50d7bfd2014-02-03 10:16:49 -0800152 }
153
154 /**
155 * Construct a new WindowInsets, copying all values from a source WindowInsets.
156 *
157 * @param src Source to copy insets from
158 */
159 public WindowInsets(WindowInsets src) {
Jorim Jaggi7882548b2019-05-14 18:54:40 +0200160 this(src.mSystemWindowInsetsConsumed ? null : src.mTypeInsetsMap,
161 src.mStableInsetsConsumed ? null : src.mTypeMaxInsetsMap,
162 src.mTypeVisibilityMap, src.mIsRound,
Brad Stenninge0573692019-03-11 13:52:46 -0700163 src.mAlwaysConsumeSystemBars, displayCutoutCopyConstructorArgument(src));
Adrian Roos60f59292018-08-24 16:29:06 +0200164 }
165
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 }
Adam Powell50d7bfd2014-02-03 10:16:49 -0800174 }
175
Jorim Jaggi297985a2018-11-30 17:24:58 +0100176 /**
177 * @return The insets that include system bars indicated by {@code typeMask}, taken from
178 * {@code typeInsetMap}.
179 */
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
Jorim Jaggibcf99ff2018-12-03 18:04:26 +0100199 /**
200 * Sets all entries in {@code typeInsetsMap} that belong to {@code typeMask} to {@code insets},
201 */
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
Adam Powell50d7bfd2014-02-03 10:16:49 -0800211 /** @hide */
Mathew Inwooda570dee2018-08-17 14:56:00 +0100212 @UnsupportedAppUsage
Adam Powell50d7bfd2014-02-03 10:16:49 -0800213 public WindowInsets(Rect systemWindowInsets) {
Jorim Jaggi90990792019-01-21 23:00:20 +0100214 this(createCompatTypeMap(systemWindowInsets), null, new boolean[SIZE], false, false, null);
Jorim Jaggi297985a2018-11-30 17:24:58 +0100215 }
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 */
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
Jorim Jaggi73f3e8a2019-01-14 13:06:23 +0100231 /**
232 * @hide
233 */
234 static void assignCompatInsets(Insets[] typeInsetMap, Rect insets) {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100235 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);
Adam Powell50d7bfd2014-02-03 10:16:49 -0800237 }
238
Jorim Jaggi90990792019-01-21 23:00:20 +0100239 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
Adam Powell50d7bfd2014-02-03 10:16:49 -0800253 /**
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
Adrian Roos60f59292018-08-24 16:29:06 +0200257 *
258 * @deprecated use {@link #getSystemWindowInsets()} instead.
Adam Powell50d7bfd2014-02-03 10:16:49 -0800259 */
Adrian Roos60f59292018-08-24 16:29:06 +0200260 @Deprecated
Adrian Roos9272cfe2018-09-28 13:35:07 +0200261 @NonNull
Adrian Roos60f59292018-08-24 16:29:06 +0200262 public Rect getSystemWindowInsetsAsRect() {
Adam Powell50d7bfd2014-02-03 10:16:49 -0800263 if (mTempRect == null) {
264 mTempRect = new Rect();
265 }
Jorim Jaggi297985a2018-11-30 17:24:58 +0100266 Insets insets = getSystemWindowInsets();
267 mTempRect.set(insets.left, insets.top, insets.right, insets.bottom);
Adam Powell50d7bfd2014-02-03 10:16:49 -0800268 return mTempRect;
269 }
270
271 /**
Adrian Roos60f59292018-08-24 16:29:06 +0200272 * 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
281 public Insets getSystemWindowInsets() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100282 return getInsets(mTypeInsetsMap, compatSystemInsets());
Adrian Roos60f59292018-08-24 16:29:06 +0200283 }
284
285 /**
Jorim Jaggibcf99ff2018-12-03 18:04:26 +0100286 * 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 */
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 */
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 /**
Jorim Jaggi90990792019-01-21 23:00:20 +0100325 * 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 */
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 /**
Adam Powell50d7bfd2014-02-03 10:16:49 -0800346 * 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 */
354 public int getSystemWindowInsetLeft() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100355 return getSystemWindowInsets().left;
Adam Powell50d7bfd2014-02-03 10:16:49 -0800356 }
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 */
367 public int getSystemWindowInsetTop() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100368 return getSystemWindowInsets().top;
Adam Powell50d7bfd2014-02-03 10:16:49 -0800369 }
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 */
380 public int getSystemWindowInsetRight() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100381 return getSystemWindowInsets().right;
Adam Powell50d7bfd2014-02-03 10:16:49 -0800382 }
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 */
393 public int getSystemWindowInsetBottom() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100394 return getSystemWindowInsets().bottom;
Adam Powell50d7bfd2014-02-03 10:16:49 -0800395 }
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 */
406 public boolean hasSystemWindowInsets() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100407 return !getSystemWindowInsets().equals(Insets.NONE);
Adam Powell50d7bfd2014-02-03 10:16:49 -0800408 }
409
410 /**
411 * Returns true if this WindowInsets has any nonzero insets.
412 *
413 * @return true if any inset values are nonzero
414 */
415 public boolean hasInsets() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100416 return !getInsets(mTypeInsetsMap, all()).equals(Insets.NONE)
417 || !getInsets(mTypeMaxInsetsMap, all()).equals(Insets.NONE)
Adrian Roosd07bafd2017-12-11 17:30:56 +0100418 || mDisplayCutout != null;
Adam Powell50d7bfd2014-02-03 10:16:49 -0800419 }
420
Adam Powell973ddaa2014-04-15 17:38:54 -0700421 /**
Adrian Roosd07bafd2017-12-11 17:30:56 +0100422 * Returns the display cutout if there is one.
423 *
424 * @return the display cutout or null if there is none
Adrian Roosd4970af2017-11-10 15:48:01 +0100425 * @see DisplayCutout
Adrian Roosd4970af2017-11-10 15:48:01 +0100426 */
Adrian Roosd07bafd2017-12-11 17:30:56 +0100427 @Nullable
Adrian Roosd4970af2017-11-10 15:48:01 +0100428 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
Adrian Roosd4970af2017-11-10 15:48:01 +0100436 */
Adrian Roos9272cfe2018-09-28 13:35:07 +0200437 @NonNull
Adrian Roosd07bafd2017-12-11 17:30:56 +0100438 public WindowInsets consumeDisplayCutout() {
Jorim Jaggi9b30a742019-01-21 15:21:44 +0100439 return new WindowInsets(mSystemWindowInsetsConsumed ? null : mTypeInsetsMap,
440 mStableInsetsConsumed ? null : mTypeMaxInsetsMap,
Jorim Jaggi90990792019-01-21 23:00:20 +0100441 mTypeVisibilityMap,
Brad Stenninge0573692019-03-11 13:52:46 -0700442 mIsRound, mAlwaysConsumeSystemBars,
Adrian Roos60f59292018-08-24 16:29:06 +0200443 null /* displayCutout */);
Adrian Roosd4970af2017-11-10 15:48:01 +0100444 }
445
446
447 /**
Adam Powell0d9fdba2014-06-11 15:33:08 -0700448 * 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.
Adam Powell0d9fdba2014-06-11 15:33:08 -0700459 */
460 public boolean isConsumed() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100461 return mSystemWindowInsetsConsumed && mStableInsetsConsumed
Adrian Roosd07bafd2017-12-11 17:30:56 +0100462 && mDisplayCutoutConsumed;
Adam Powell0d9fdba2014-06-11 15:33:08 -0700463 }
464
465 /**
Adam Powell973ddaa2014-04-15 17:38:54 -0700466 * 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 */
475 public boolean isRound() {
476 return mIsRound;
477 }
478
Adam Powellf4a39412014-05-05 17:29:17 -0700479 /**
480 * Returns a copy of this WindowInsets with the system window insets fully consumed.
481 *
482 * @return A modified copy of this WindowInsets
483 */
Adrian Roos9272cfe2018-09-28 13:35:07 +0200484 @NonNull
Adam Powellf4a39412014-05-05 17:29:17 -0700485 public WindowInsets consumeSystemWindowInsets() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100486 return new WindowInsets(null, mStableInsetsConsumed ? null : mTypeMaxInsetsMap,
Jorim Jaggi90990792019-01-21 23:00:20 +0100487 mTypeVisibilityMap,
Brad Stenninge0573692019-03-11 13:52:46 -0700488 mIsRound, mAlwaysConsumeSystemBars,
Adrian Roos60f59292018-08-24 16:29:06 +0200489 displayCutoutCopyConstructorArgument(this));
Adam Powell50d7bfd2014-02-03 10:16:49 -0800490 }
491
Adrian Roos18b11d52018-11-07 19:04:19 +0100492 // TODO(b/119190588): replace @code with @link below
Adam Powellf4a39412014-05-05 17:29:17 -0700493 /**
494 * Returns a copy of this WindowInsets with selected system window insets replaced
495 * with new values.
496 *
Adrian Roos60f59292018-08-24 16:29:06 +0200497 * <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 *
Adam Powellf4a39412014-05-05 17:29:17 -0700502 * @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
Adrian Roos18b11d52018-11-07 19:04:19 +0100507 * @deprecated use {@code Builder#Builder(WindowInsets)} with
Adrian Roosf35eb022018-07-25 18:29:10 +0200508 * {@link Builder#setSystemWindowInsets(Insets)} instead.
Adam Powellf4a39412014-05-05 17:29:17 -0700509 */
Adrian Roosf35eb022018-07-25 18:29:10 +0200510 @Deprecated
Adrian Roos9272cfe2018-09-28 13:35:07 +0200511 @NonNull
Adrian Roos60f59292018-08-24 16:29:06 +0200512 public WindowInsets replaceSystemWindowInsets(int left, int top, int right, int bottom) {
Adrian Roos60f59292018-08-24 16:29:06 +0200513 // 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 }
Adrian Roosf35eb022018-07-25 18:29:10 +0200520 return new Builder(this).setSystemWindowInsets(Insets.of(left, top, right, bottom)).build();
Adam Powell50d7bfd2014-02-03 10:16:49 -0800521 }
522
Adrian Roos18b11d52018-11-07 19:04:19 +0100523 // TODO(b/119190588): replace @code with @link below
Adam Powellf4a39412014-05-05 17:29:17 -0700524 /**
Adam Powelld72068b2014-09-12 14:42:25 -0700525 * Returns a copy of this WindowInsets with selected system window insets replaced
526 * with new values.
527 *
Adrian Roos60f59292018-08-24 16:29:06 +0200528 * <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 *
Adam Powelld72068b2014-09-12 14:42:25 -0700533 * @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
Adrian Roos18b11d52018-11-07 19:04:19 +0100536 * @deprecated use {@code Builder#Builder(WindowInsets)} with
Adrian Roosf35eb022018-07-25 18:29:10 +0200537 * {@link Builder#setSystemWindowInsets(Insets)} instead.
Adam Powelld72068b2014-09-12 14:42:25 -0700538 */
Adrian Roosf35eb022018-07-25 18:29:10 +0200539 @Deprecated
Adrian Roos9272cfe2018-09-28 13:35:07 +0200540 @NonNull
Adam Powelld72068b2014-09-12 14:42:25 -0700541 public WindowInsets replaceSystemWindowInsets(Rect systemWindowInsets) {
Adrian Roos60f59292018-08-24 16:29:06 +0200542 return replaceSystemWindowInsets(systemWindowInsets.left, systemWindowInsets.top,
543 systemWindowInsets.right, systemWindowInsets.bottom);
Adam Powelld72068b2014-09-12 14:42:25 -0700544 }
545
546 /**
Adrian Roos60f59292018-08-24 16:29:06 +0200547 * 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
Adam Powellf4a39412014-05-05 17:29:17 -0700556 */
Adrian Roos60f59292018-08-24 16:29:06 +0200557 @NonNull
558 public Insets getStableInsets() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100559 return getInsets(mTypeMaxInsetsMap, compatSystemInsets());
Adam Powell50d7bfd2014-02-03 10:16:49 -0800560 }
561
Adrian Roosfa104232014-06-20 16:10:14 -0700562 /**
Dianne Hackborn067e5f62014-09-07 23:14:30 -0700563 * 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
Adrian Roosfa104232014-06-20 16:10:14 -0700572 */
573 public int getStableInsetTop() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100574 return getStableInsets().top;
Adrian Roosfa104232014-06-20 16:10:14 -0700575 }
576
577 /**
Dianne Hackborn067e5f62014-09-07 23:14:30 -0700578 * 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
Adrian Roosfa104232014-06-20 16:10:14 -0700587 */
588 public int getStableInsetLeft() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100589 return getStableInsets().left;
Adrian Roosfa104232014-06-20 16:10:14 -0700590 }
591
592 /**
Dianne Hackborn067e5f62014-09-07 23:14:30 -0700593 * 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
Adrian Roosfa104232014-06-20 16:10:14 -0700602 */
603 public int getStableInsetRight() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100604 return getStableInsets().right;
Adrian Roosfa104232014-06-20 16:10:14 -0700605 }
606
607 /**
Dianne Hackborn067e5f62014-09-07 23:14:30 -0700608 * 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
Adrian Roosfa104232014-06-20 16:10:14 -0700617 */
618 public int getStableInsetBottom() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100619 return getStableInsets().bottom;
Adrian Roosfa104232014-06-20 16:10:14 -0700620 }
621
622 /**
Dianne Hackborn067e5f62014-09-07 23:14:30 -0700623 * 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
Adrian Roosfa104232014-06-20 16:10:14 -0700632 */
633 public boolean hasStableInsets() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100634 return !getStableInsets().equals(Insets.NONE);
Adrian Roosfa104232014-06-20 16:10:14 -0700635 }
636
637 /**
Adrian Roosdd49eb72019-02-26 19:38:10 +0100638 * 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 *
Adrian Roos15ab5192019-03-13 18:23:05 -0700644 * <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 *
Adrian Roose6feb7d2019-07-25 20:29:07 +0200648 * <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 *
Adrian Roosdd49eb72019-02-26 19:38:10 +0100656 * <p>Simple taps are guaranteed to reach the window even within the system gesture insets,
Adrian Roos15ab5192019-03-13 18:23:05 -0700657 * as long as they are outside the {@link #getTappableElementInsets() system window insets}.
Adrian Roosdd49eb72019-02-26 19:38:10 +0100658 *
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 *
Adrian Roos15ab5192019-03-13 18:23:05 -0700664 * <p>This inset is consumed together with the {@link #getSystemWindowInsets()
665 * system window insets} by {@link #consumeSystemWindowInsets()}.
666 *
667 * @see #getMandatorySystemGestureInsets
Adrian Roosdd49eb72019-02-26 19:38:10 +0100668 */
669 @NonNull
670 public Insets getSystemGestureInsets() {
671 return getInsets(mTypeInsetsMap, SYSTEM_GESTURES);
672 }
673
674 /**
Adrian Roos15ab5192019-03-13 18:23:05 -0700675 * 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
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
724 public Insets getTappableElementInsets() {
725 return getInsets(mTypeInsetsMap, TAPPABLE_ELEMENT);
726 }
727
728 /**
Dianne Hackborn067e5f62014-09-07 23:14:30 -0700729 * Returns a copy of this WindowInsets with the stable insets fully consumed.
730 *
731 * @return A modified copy of this WindowInsets
Adrian Roosfa104232014-06-20 16:10:14 -0700732 */
Adrian Roos9272cfe2018-09-28 13:35:07 +0200733 @NonNull
Adrian Roosfa104232014-06-20 16:10:14 -0700734 public WindowInsets consumeStableInsets() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100735 return new WindowInsets(mSystemWindowInsetsConsumed ? null : mTypeInsetsMap, null,
Brad Stenninge0573692019-03-11 13:52:46 -0700736 mTypeVisibilityMap, mIsRound, mAlwaysConsumeSystemBars,
Adrian Roos60f59292018-08-24 16:29:06 +0200737 displayCutoutCopyConstructorArgument(this));
Adrian Roosfa104232014-06-20 16:10:14 -0700738 }
739
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -0800740 /**
741 * @hide
742 */
Brad Stenninge0573692019-03-11 13:52:46 -0700743 public boolean shouldAlwaysConsumeSystemBars() {
744 return mAlwaysConsumeSystemBars;
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -0800745 }
746
Adam Powell50d7bfd2014-02-03 10:16:49 -0800747 @Override
748 public String toString() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100749 return "WindowInsets{systemWindowInsets=" + getSystemWindowInsets()
750 + " stableInsets=" + getStableInsets()
Adrian Roosa5355862019-03-06 17:19:21 +0100751 + " sysGestureInsets=" + getSystemGestureInsets()
Adrian Roosd07bafd2017-12-11 17:30:56 +0100752 + (mDisplayCutout != null ? " cutout=" + mDisplayCutout : "")
Adrian Roosd4970af2017-11-10 15:48:01 +0100753 + (isRound() ? " round" : "")
754 + "}";
Adam Powell50d7bfd2014-02-03 10:16:49 -0800755 }
Adrian Roosf7b74262017-11-22 14:21:01 +0100756
757 /**
758 * Returns a copy of this instance inset in the given directions.
759 *
760 * @see #inset(int, int, int, int)
Adrian Roos60f59292018-08-24 16:29:06 +0200761 * @deprecated use {@link #inset(Insets)}
Adrian Roosf7b74262017-11-22 14:21:01 +0100762 * @hide
763 */
Adrian Roos60f59292018-08-24 16:29:06 +0200764 @Deprecated
Adrian Roos9272cfe2018-09-28 13:35:07 +0200765 @NonNull
Adrian Roosf7b74262017-11-22 14:21:01 +0100766 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 *
Adrian Roos60f59292018-08-24 16:29:06 +0200773 * @see #inset(int, int, int, int)
774 * @hide
775 */
Adrian Roos9272cfe2018-09-28 13:35:07 +0200776 @NonNull
Adrian Roos60f59292018-08-24 16:29:06 +0200777 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 *
Adrian Roosf7b74262017-11-22 14:21:01 +0100784 * 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
Adrian Roosf7b74262017-11-22 14:21:01 +0100799 */
Adrian Roosb57bfe02018-07-25 18:28:32 +0200800 @NonNull
Adrian Roos9e860352019-02-26 18:28:41 +0100801 public WindowInsets inset(@IntRange(from = 0) int left, @IntRange(from = 0) int top,
802 @IntRange(from = 0) int right, @IntRange(from = 0) int bottom) {
Adrian Roosf7b74262017-11-22 14:21:01 +0100803 Preconditions.checkArgumentNonnegative(left);
804 Preconditions.checkArgumentNonnegative(top);
805 Preconditions.checkArgumentNonnegative(right);
806 Preconditions.checkArgumentNonnegative(bottom);
807
Adrian Roos60f59292018-08-24 16:29:06 +0200808 return new WindowInsets(
Jorim Jaggi297985a2018-11-30 17:24:58 +0100809 mSystemWindowInsetsConsumed
810 ? null
811 : insetInsets(mTypeInsetsMap, left, top, right, bottom),
812 mStableInsetsConsumed
813 ? null
814 : insetInsets(mTypeMaxInsetsMap, left, top, right, bottom),
Jorim Jaggi90990792019-01-21 23:00:20 +0100815 mTypeVisibilityMap,
Brad Stenninge0573692019-03-11 13:52:46 -0700816 mIsRound, mAlwaysConsumeSystemBars,
Adrian Roos60f59292018-08-24 16:29:06 +0200817 mDisplayCutoutConsumed
Jorim Jaggi297985a2018-11-30 17:24:58 +0100818 ? null
819 : mDisplayCutout == null
Adrian Roos60f59292018-08-24 16:29:06 +0200820 ? DisplayCutout.NO_CUTOUT
821 : mDisplayCutout.inset(left, top, right, bottom));
Adrian Roosf7b74262017-11-22 14:21:01 +0100822 }
823
824 @Override
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;
Jorim Jaggi297985a2018-11-30 17:24:58 +0100829
Adrian Roosf7b74262017-11-22 14:21:01 +0100830 return mIsRound == that.mIsRound
Brad Stenninge0573692019-03-11 13:52:46 -0700831 && mAlwaysConsumeSystemBars == that.mAlwaysConsumeSystemBars
Adrian Roosf7b74262017-11-22 14:21:01 +0100832 && mSystemWindowInsetsConsumed == that.mSystemWindowInsetsConsumed
Adrian Roosf7b74262017-11-22 14:21:01 +0100833 && mStableInsetsConsumed == that.mStableInsetsConsumed
834 && mDisplayCutoutConsumed == that.mDisplayCutoutConsumed
Jorim Jaggi297985a2018-11-30 17:24:58 +0100835 && Arrays.equals(mTypeInsetsMap, that.mTypeInsetsMap)
836 && Arrays.equals(mTypeMaxInsetsMap, that.mTypeMaxInsetsMap)
Jorim Jaggi90990792019-01-21 23:00:20 +0100837 && Arrays.equals(mTypeVisibilityMap, that.mTypeVisibilityMap)
Adrian Roosf7b74262017-11-22 14:21:01 +0100838 && Objects.equals(mDisplayCutout, that.mDisplayCutout);
839 }
840
841 @Override
842 public int hashCode() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100843 return Objects.hash(Arrays.hashCode(mTypeInsetsMap), Arrays.hashCode(mTypeMaxInsetsMap),
Brad Stenninge0573692019-03-11 13:52:46 -0700844 Arrays.hashCode(mTypeVisibilityMap), mIsRound, mDisplayCutout,
845 mAlwaysConsumeSystemBars, mSystemWindowInsetsConsumed, mStableInsetsConsumed,
846 mDisplayCutoutConsumed);
Jorim Jaggi297985a2018-11-30 17:24:58 +0100847 }
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 */
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;
Adrian Roosf7b74262017-11-22 14:21:01 +0100874 }
875
Adrian Roos60f59292018-08-24 16:29:06 +0200876 private static Insets insetInsets(Insets insets, int left, int top, int right, int bottom) {
Adrian Roosf7b74262017-11-22 14:21:01 +0100877 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 }
Adrian Roos60f59292018-08-24 16:29:06 +0200884 return Insets.of(newLeft, newTop, newRight, newBottom);
Adrian Roosf7b74262017-11-22 14:21:01 +0100885 }
886
887 /**
888 * @return whether system window insets have been consumed.
889 */
890 boolean isSystemWindowInsetsConsumed() {
891 return mSystemWindowInsetsConsumed;
892 }
Adrian Roosf35eb022018-07-25 18:29:10 +0200893
894 /**
895 * Builder for WindowInsets.
896 */
Adrian Roos9e860352019-02-26 18:28:41 +0100897 public static final class Builder {
Adrian Roosf35eb022018-07-25 18:29:10 +0200898
Jorim Jaggi297985a2018-11-30 17:24:58 +0100899 private final Insets[] mTypeInsetsMap;
900 private final Insets[] mTypeMaxInsetsMap;
Jorim Jaggi90990792019-01-21 23:00:20 +0100901 private final boolean[] mTypeVisibilityMap;
Jorim Jaggi297985a2018-11-30 17:24:58 +0100902 private boolean mSystemInsetsConsumed = true;
903 private boolean mStableInsetsConsumed = true;
904
Adrian Roosf35eb022018-07-25 18:29:10 +0200905 private DisplayCutout mDisplayCutout;
906
Adrian Roosf35eb022018-07-25 18:29:10 +0200907 private boolean mIsRound;
Brad Stenninge0573692019-03-11 13:52:46 -0700908 private boolean mAlwaysConsumeSystemBars;
Adrian Roosf35eb022018-07-25 18:29:10 +0200909
910 /**
911 * Creates a builder where all insets are initially consumed.
912 */
913 public Builder() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100914 mTypeInsetsMap = new Insets[SIZE];
915 mTypeMaxInsetsMap = new Insets[SIZE];
Jorim Jaggi90990792019-01-21 23:00:20 +0100916 mTypeVisibilityMap = new boolean[SIZE];
Adrian Roosf35eb022018-07-25 18:29:10 +0200917 }
918
919 /**
920 * Creates a builder where all insets are initialized from {@link WindowInsets}.
921 *
922 * @param insets the instance to initialize from.
923 */
Adrian Roos9e860352019-02-26 18:28:41 +0100924 public Builder(@NonNull WindowInsets insets) {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100925 mTypeInsetsMap = insets.mTypeInsetsMap.clone();
926 mTypeMaxInsetsMap = insets.mTypeMaxInsetsMap.clone();
Jorim Jaggi90990792019-01-21 23:00:20 +0100927 mTypeVisibilityMap = insets.mTypeVisibilityMap.clone();
Jorim Jaggi297985a2018-11-30 17:24:58 +0100928 mSystemInsetsConsumed = insets.mSystemWindowInsetsConsumed;
929 mStableInsetsConsumed = insets.mStableInsetsConsumed;
Adrian Roosf35eb022018-07-25 18:29:10 +0200930 mDisplayCutout = displayCutoutCopyConstructorArgument(insets);
Adrian Roosf35eb022018-07-25 18:29:10 +0200931 mIsRound = insets.mIsRound;
Brad Stenninge0573692019-03-11 13:52:46 -0700932 mAlwaysConsumeSystemBars = insets.mAlwaysConsumeSystemBars;
Adrian Roosf35eb022018-07-25 18:29:10 +0200933 }
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
946 public Builder setSystemWindowInsets(@NonNull Insets systemWindowInsets) {
947 Preconditions.checkNotNull(systemWindowInsets);
Jorim Jaggi297985a2018-11-30 17:24:58 +0100948 assignCompatInsets(mTypeInsetsMap, systemWindowInsets.toRect());
949 mSystemInsetsConsumed = false;
Adrian Roosf35eb022018-07-25 18:29:10 +0200950 return this;
951 }
952
953 /**
Adrian Roosdd49eb72019-02-26 19:38:10 +0100954 * 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
964 public Builder setSystemGestureInsets(@NonNull Insets insets) {
965 WindowInsets.setInsets(mTypeInsetsMap, SYSTEM_GESTURES, insets);
966 return this;
967 }
968
969 /**
Adrian Roos15ab5192019-03-13 18:23:05 -0700970 * 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
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
999 public Builder setTappableElementInsets(@NonNull Insets insets) {
1000 WindowInsets.setInsets(mTypeInsetsMap, TAPPABLE_ELEMENT, insets);
1001 return this;
1002 }
1003
1004 /**
Jorim Jaggibcf99ff2018-12-03 18:04:26 +01001005 * 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
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
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 /**
Jorim Jaggi90990792019-01-21 23:00:20 +01001063 * 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
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 /**
Adrian Roosf35eb022018-07-25 18:29:10 +02001086 * 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
1098 public Builder setStableInsets(@NonNull Insets stableInsets) {
1099 Preconditions.checkNotNull(stableInsets);
Jorim Jaggi9b30a742019-01-21 15:21:44 +01001100 assignCompatInsets(mTypeMaxInsetsMap, stableInsets.toRect());
Jorim Jaggi297985a2018-11-30 17:24:58 +01001101 mStableInsetsConsumed = false;
Adrian Roosf35eb022018-07-25 18:29:10 +02001102 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
1113 public Builder setDisplayCutout(@Nullable DisplayCutout displayCutout) {
1114 mDisplayCutout = displayCutout != null ? displayCutout : DisplayCutout.NO_CUTOUT;
1115 return this;
1116 }
1117
1118 /** @hide */
1119 @NonNull
Adrian Roosf35eb022018-07-25 18:29:10 +02001120 public Builder setRound(boolean round) {
1121 mIsRound = round;
1122 return this;
1123 }
1124
1125 /** @hide */
1126 @NonNull
Brad Stenninge0573692019-03-11 13:52:46 -07001127 public Builder setAlwaysConsumeSystemBars(boolean alwaysConsumeSystemBars) {
1128 mAlwaysConsumeSystemBars = alwaysConsumeSystemBars;
Adrian Roosf35eb022018-07-25 18:29:10 +02001129 return this;
1130 }
1131
1132 /**
1133 * Builds a {@link WindowInsets} instance.
1134 *
1135 * @return the {@link WindowInsets} instance.
1136 */
1137 @NonNull
1138 public WindowInsets build() {
Jorim Jaggi297985a2018-11-30 17:24:58 +01001139 return new WindowInsets(mSystemInsetsConsumed ? null : mTypeInsetsMap,
Jorim Jaggi90990792019-01-21 23:00:20 +01001140 mStableInsetsConsumed ? null : mTypeMaxInsetsMap, mTypeVisibilityMap,
Brad Stenninge0573692019-03-11 13:52:46 -07001141 mIsRound, mAlwaysConsumeSystemBars, mDisplayCutout);
Adrian Roosf35eb022018-07-25 18:29:10 +02001142 }
1143 }
Jorim Jaggib6030952018-10-23 18:31:52 +02001144
1145 /**
1146 * Class that defines different types of sources causing window insets.
1147 * @hide pending unhide
1148 */
1149 public static final class Type {
1150
Adrian Roos15ab5192019-03-13 18:23:05 -07001151 static final int FIRST = 1 << 0;
Jorim Jaggi297985a2018-11-30 17:24:58 +01001152 static final int TOP_BAR = FIRST;
1153
Adrian Roos15ab5192019-03-13 18:23:05 -07001154 static final int IME = 1 << 1;
1155 static final int SIDE_BARS = 1 << 2;
Jorim Jaggi297985a2018-11-30 17:24:58 +01001156
Adrian Roos15ab5192019-03-13 18:23:05 -07001157 static final int SYSTEM_GESTURES = 1 << 3;
1158 static final int MANDATORY_SYSTEM_GESTURES = 1 << 4;
1159 static final int TAPPABLE_ELEMENT = 1 << 5;
Adrian Roosdd49eb72019-02-26 19:38:10 +01001160
Adrian Roos15ab5192019-03-13 18:23:05 -07001161 static final int LAST = 1 << 6;
1162 static final int SIZE = 7;
Jorim Jaggi297985a2018-11-30 17:24:58 +01001163 static final int WINDOW_DECOR = LAST;
1164
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;
Adrian Roosdd49eb72019-02-26 19:38:10 +01001173 case SYSTEM_GESTURES:
Jorim Jaggi297985a2018-11-30 17:24:58 +01001174 return 3;
Adrian Roos15ab5192019-03-13 18:23:05 -07001175 case MANDATORY_SYSTEM_GESTURES:
Adrian Roosdd49eb72019-02-26 19:38:10 +01001176 return 4;
Adrian Roos15ab5192019-03-13 18:23:05 -07001177 case TAPPABLE_ELEMENT:
1178 return 5;
1179 case WINDOW_DECOR:
1180 return 6;
Jorim Jaggi297985a2018-11-30 17:24:58 +01001181 default:
1182 throw new IllegalArgumentException("type needs to be >= FIRST and <= LAST,"
1183 + " type=" + type);
1184 }
1185 }
Jorim Jaggib6030952018-10-23 18:31:52 +02001186
1187 private Type() {
1188 }
1189
1190 /** @hide */
1191 @Retention(RetentionPolicy.SOURCE)
Adrian Roos15ab5192019-03-13 18:23:05 -07001192 @IntDef(flag = true, value = { TOP_BAR, IME, SIDE_BARS, WINDOW_DECOR, SYSTEM_GESTURES,
1193 MANDATORY_SYSTEM_GESTURES, TAPPABLE_ELEMENT})
Jorim Jaggib6030952018-10-23 18:31:52 +02001194 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 */
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 */
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 */
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 */
1222 public static @InsetType int windowDecor() {
1223 return WINDOW_DECOR;
1224 }
1225
1226 /**
Adrian Roosdd49eb72019-02-26 19:38:10 +01001227 * 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 */
1243 public static @InsetType int systemGestures() {
1244 return SYSTEM_GESTURES;
1245 }
1246
1247 /**
Adrian Roos15ab5192019-03-13 18:23:05 -07001248 * @see #getMandatorySystemGestureInsets
1249 */
1250 public static @InsetType int mandatorySystemGestures() {
1251 return MANDATORY_SYSTEM_GESTURES;
1252 }
1253
1254 /**
1255 * @see #getTappableElementInsets
1256 */
1257 public static @InsetType int tappableElement() {
1258 return TAPPABLE_ELEMENT;
1259 }
1260
1261 /**
Jorim Jaggib6030952018-10-23 18:31:52 +02001262 * @return All system bars. Includes {@link #topBar()} as well as {@link #sideBars()}, but
1263 * not {@link #ime()}.
1264 */
1265 public static @InsetType int systemBars() {
1266 return TOP_BAR | SIDE_BARS;
1267 }
1268
1269 /**
Jorim Jaggi297985a2018-11-30 17:24:58 +01001270 * @return Inset types representing the list of bars that traditionally were denoted as
1271 * system insets.
1272 * @hide
1273 */
1274 static @InsetType int compatSystemInsets() {
1275 return TOP_BAR | SIDE_BARS | IME;
1276 }
1277
1278 /**
Jorim Jaggib6030952018-10-23 18:31:52 +02001279 * @return All inset types combined.
Adrian Roosdd49eb72019-02-26 19:38:10 +01001280 *
1281 * TODO: Figure out if this makes sense at all, mixing e.g {@link #systemGestures()} and
1282 * {@link #ime()} does not seem very useful.
Jorim Jaggib6030952018-10-23 18:31:52 +02001283 */
1284 public static @InsetType int all() {
1285 return 0xFFFFFFFF;
1286 }
1287 }
Adam Powell50d7bfd2014-02-03 10:16:49 -08001288}