blob: f3bbca3500c7a73aea84c5f3f8bfe87721f8b08c [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;
23import static android.view.WindowInsets.Type.SIDE_BARS;
24import static android.view.WindowInsets.Type.SIZE;
Adrian Roosdd49eb72019-02-26 19:38:10 +010025import static android.view.WindowInsets.Type.SYSTEM_GESTURES;
Jorim Jaggi297985a2018-11-30 17:24:58 +010026import static android.view.WindowInsets.Type.TOP_BAR;
27import static android.view.WindowInsets.Type.all;
28import static android.view.WindowInsets.Type.compatSystemInsets;
29import static android.view.WindowInsets.Type.indexOf;
30
Jorim Jaggib6030952018-10-23 18:31:52 +020031import android.annotation.IntDef;
Adrian Roos9e860352019-02-26 18:28:41 +010032import android.annotation.IntRange;
Jorim Jaggi297985a2018-11-30 17:24:58 +010033import android.annotation.NonNull;
Adrian Roosd07bafd2017-12-11 17:30:56 +010034import android.annotation.Nullable;
Mathew Inwooda570dee2018-08-17 14:56:00 +010035import android.annotation.UnsupportedAppUsage;
Adrian Roos60f59292018-08-24 16:29:06 +020036import android.graphics.Insets;
Adam Powell50d7bfd2014-02-03 10:16:49 -080037import android.graphics.Rect;
Jorim Jaggi297985a2018-11-30 17:24:58 +010038import android.util.SparseArray;
39import android.view.WindowInsets.Type.InsetType;
Jorim Jaggibcf99ff2018-12-03 18:04:26 +010040import android.view.inputmethod.EditorInfo;
Jorim Jaggib6030952018-10-23 18:31:52 +020041import android.view.inputmethod.InputMethod;
Adam Powell50d7bfd2014-02-03 10:16:49 -080042
Adrian Roosf7b74262017-11-22 14:21:01 +010043import com.android.internal.util.Preconditions;
44
Jorim Jaggib6030952018-10-23 18:31:52 +020045import java.lang.annotation.Retention;
46import java.lang.annotation.RetentionPolicy;
Jorim Jaggi297985a2018-11-30 17:24:58 +010047import java.util.Arrays;
Adrian Roosf7b74262017-11-22 14:21:01 +010048import java.util.Objects;
49
Adam Powell50d7bfd2014-02-03 10:16:49 -080050/**
51 * Describes a set of insets for window content.
52 *
53 * <p>WindowInsets are immutable and may be expanded to include more inset types in the future.
54 * To adjust insets, use one of the supplied clone methods to obtain a new WindowInsets instance
55 * with the adjusted properties.</p>
56 *
Adrian Roosf7b74262017-11-22 14:21:01 +010057 * <p>Note: Before {@link android.os.Build.VERSION_CODES#P P}, WindowInsets instances were only
58 * immutable during a single layout pass (i.e. would return the same values between
59 * {@link View#onApplyWindowInsets} and {@link View#onLayout}, but could return other values
60 * otherwise). Starting with {@link android.os.Build.VERSION_CODES#P P}, WindowInsets are
61 * always immutable and implement equality.
62 *
Adam Powell50d7bfd2014-02-03 10:16:49 -080063 * @see View.OnApplyWindowInsetsListener
64 * @see View#onApplyWindowInsets(WindowInsets)
65 */
Adam Powellf4a39412014-05-05 17:29:17 -070066public final class WindowInsets {
Adrian Roosfa104232014-06-20 16:10:14 -070067
Jorim Jaggi297985a2018-11-30 17:24:58 +010068 private final Insets[] mTypeInsetsMap;
69 private final Insets[] mTypeMaxInsetsMap;
Jorim Jaggi90990792019-01-21 23:00:20 +010070 private final boolean[] mTypeVisibilityMap;
Jorim Jaggi297985a2018-11-30 17:24:58 +010071
Adrian Roos60f59292018-08-24 16:29:06 +020072 @Nullable private Rect mTempRect;
73 private final boolean mIsRound;
74 @Nullable private final DisplayCutout mDisplayCutout;
Adam Powell50d7bfd2014-02-03 10:16:49 -080075
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -080076 /**
77 * In multi-window we force show the navigation bar. Because we don't want that the surface size
78 * changes in this mode, we instead have a flag whether the navigation bar size should always
79 * be consumed, so the app is treated like there is no virtual navigation bar at all.
80 */
Adrian Roos60f59292018-08-24 16:29:06 +020081 private final boolean mAlwaysConsumeNavBar;
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -080082
Adrian Roos60f59292018-08-24 16:29:06 +020083 private final boolean mSystemWindowInsetsConsumed;
Adrian Roos60f59292018-08-24 16:29:06 +020084 private final boolean mStableInsetsConsumed;
85 private final boolean mDisplayCutoutConsumed;
Adam Powell50d7bfd2014-02-03 10:16:49 -080086
87 /**
88 * Since new insets may be added in the future that existing apps couldn't
89 * know about, this fully empty constant shouldn't be made available to apps
90 * since it would allow them to inadvertently consume unknown insets by returning it.
91 * @hide
92 */
Mathew Inwooda570dee2018-08-17 14:56:00 +010093 @UnsupportedAppUsage
Adam Powell720924b2014-06-12 14:51:10 -070094 public static final WindowInsets CONSUMED;
95
96 static {
Jorim Jaggi297985a2018-11-30 17:24:58 +010097 CONSUMED = new WindowInsets((Rect) null, null, false, false, null);
Adam Powell720924b2014-06-12 14:51:10 -070098 }
Adam Powell50d7bfd2014-02-03 10:16:49 -080099
Adrian Roosb8493862018-11-14 06:50:55 -0800100 /**
101 * Construct a new WindowInsets from individual insets.
102 *
103 * A {@code null} inset indicates that the respective inset is consumed.
104 *
105 * @hide
Jorim Jaggi297985a2018-11-30 17:24:58 +0100106 * @deprecated Use {@link WindowInsets(SparseArray, SparseArray, boolean, boolean, DisplayCutout)}
Adrian Roosb8493862018-11-14 06:50:55 -0800107 */
Jorim Jaggi297985a2018-11-30 17:24:58 +0100108 public WindowInsets(Rect systemWindowInsetsRect, Rect stableInsetsRect,
Adrian Roosd4970af2017-11-10 15:48:01 +0100109 boolean isRound, boolean alwaysConsumeNavBar, DisplayCutout displayCutout) {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100110 this(createCompatTypeMap(systemWindowInsetsRect), createCompatTypeMap(stableInsetsRect),
Jorim Jaggi90990792019-01-21 23:00:20 +0100111 createCompatVisibilityMap(createCompatTypeMap(systemWindowInsetsRect)),
Jorim Jaggi297985a2018-11-30 17:24:58 +0100112 isRound, alwaysConsumeNavBar, displayCutout);
Adrian Roos60f59292018-08-24 16:29:06 +0200113 }
114
Jorim Jaggi297985a2018-11-30 17:24:58 +0100115 /**
116 * Construct a new WindowInsets from individual insets.
117 *
118 * {@code typeInsetsMap} and {@code typeMaxInsetsMap} are a map of indexOf(type) -> insets that
119 * contain the information what kind of system bars causes how much insets. The insets in this
120 * map are non-additive; i.e. they have the same origin. In other words: If two system bars
121 * overlap on one side, the insets of the larger bar will also include the insets of the smaller
122 * bar.
123 *
124 * {@code null} type inset map indicates that the respective inset is fully consumed.
125 * @hide
126 */
127 public WindowInsets(@Nullable Insets[] typeInsetsMap,
Jorim Jaggi90990792019-01-21 23:00:20 +0100128 @Nullable Insets[] typeMaxInsetsMap,
129 boolean[] typeVisibilityMap,
130 boolean isRound,
Jorim Jaggi297985a2018-11-30 17:24:58 +0100131 boolean alwaysConsumeNavBar, DisplayCutout displayCutout) {
132 mSystemWindowInsetsConsumed = typeInsetsMap == null;
133 mTypeInsetsMap = mSystemWindowInsetsConsumed
134 ? new Insets[SIZE]
135 : typeInsetsMap.clone();
Adam Powell0d9fdba2014-06-11 15:33:08 -0700136
Jorim Jaggi297985a2018-11-30 17:24:58 +0100137 mStableInsetsConsumed = typeMaxInsetsMap == null;
138 mTypeMaxInsetsMap = mStableInsetsConsumed
139 ? new Insets[SIZE]
140 : typeMaxInsetsMap.clone();
Adrian Roosfa104232014-06-20 16:10:14 -0700141
Jorim Jaggi90990792019-01-21 23:00:20 +0100142 mTypeVisibilityMap = typeVisibilityMap;
Adam Powell973ddaa2014-04-15 17:38:54 -0700143 mIsRound = isRound;
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -0800144 mAlwaysConsumeNavBar = alwaysConsumeNavBar;
Adrian Roosd4970af2017-11-10 15:48:01 +0100145
Adrian Roosd07bafd2017-12-11 17:30:56 +0100146 mDisplayCutoutConsumed = displayCutout == null;
147 mDisplayCutout = (mDisplayCutoutConsumed || displayCutout.isEmpty())
148 ? null : displayCutout;
Adam Powell50d7bfd2014-02-03 10:16:49 -0800149 }
150
151 /**
152 * Construct a new WindowInsets, copying all values from a source WindowInsets.
153 *
154 * @param src Source to copy insets from
155 */
156 public WindowInsets(WindowInsets src) {
Jorim Jaggi90990792019-01-21 23:00:20 +0100157 this(src.mTypeInsetsMap, src.mTypeMaxInsetsMap, src.mTypeVisibilityMap, src.mIsRound,
158 src.mAlwaysConsumeNavBar, displayCutoutCopyConstructorArgument(src));
Adrian Roos60f59292018-08-24 16:29:06 +0200159 }
160
161 private static DisplayCutout displayCutoutCopyConstructorArgument(WindowInsets w) {
162 if (w.mDisplayCutoutConsumed) {
163 return null;
164 } else if (w.mDisplayCutout == null) {
165 return DisplayCutout.NO_CUTOUT;
166 } else {
167 return w.mDisplayCutout;
168 }
Adam Powell50d7bfd2014-02-03 10:16:49 -0800169 }
170
Jorim Jaggi297985a2018-11-30 17:24:58 +0100171 /**
172 * @return The insets that include system bars indicated by {@code typeMask}, taken from
173 * {@code typeInsetMap}.
174 */
175 private static Insets getInsets(Insets[] typeInsetsMap, @InsetType int typeMask) {
176 Insets result = null;
177 for (int i = FIRST; i <= LAST; i = i << 1) {
178 if ((typeMask & i) == 0) {
179 continue;
180 }
181 Insets insets = typeInsetsMap[indexOf(i)];
182 if (insets == null) {
183 continue;
184 }
185 if (result == null) {
186 result = insets;
187 } else {
188 result = Insets.max(result, insets);
189 }
190 }
191 return result == null ? Insets.NONE : result;
192 }
193
Jorim Jaggibcf99ff2018-12-03 18:04:26 +0100194 /**
195 * Sets all entries in {@code typeInsetsMap} that belong to {@code typeMask} to {@code insets},
196 */
197 private static void setInsets(Insets[] typeInsetsMap, @InsetType int typeMask, Insets insets) {
198 for (int i = FIRST; i <= LAST; i = i << 1) {
199 if ((typeMask & i) == 0) {
200 continue;
201 }
202 typeInsetsMap[indexOf(i)] = insets;
203 }
204 }
205
Adam Powell50d7bfd2014-02-03 10:16:49 -0800206 /** @hide */
Mathew Inwooda570dee2018-08-17 14:56:00 +0100207 @UnsupportedAppUsage
Adam Powell50d7bfd2014-02-03 10:16:49 -0800208 public WindowInsets(Rect systemWindowInsets) {
Jorim Jaggi90990792019-01-21 23:00:20 +0100209 this(createCompatTypeMap(systemWindowInsets), null, new boolean[SIZE], false, false, null);
Jorim Jaggi297985a2018-11-30 17:24:58 +0100210 }
211
212 /**
213 * Creates a indexOf(type) -> inset map for which the {@code insets} is just mapped to
214 * {@link InsetType#topBar()} and {@link InsetType#sideBars()}, depending on the location of the
215 * inset.
216 */
217 private static Insets[] createCompatTypeMap(@Nullable Rect insets) {
218 if (insets == null) {
219 return null;
220 }
221 Insets[] typeInsetMap = new Insets[SIZE];
222 assignCompatInsets(typeInsetMap, insets);
223 return typeInsetMap;
224 }
225
Jorim Jaggi73f3e8a2019-01-14 13:06:23 +0100226 /**
227 * @hide
228 */
229 static void assignCompatInsets(Insets[] typeInsetMap, Rect insets) {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100230 typeInsetMap[indexOf(TOP_BAR)] = Insets.of(0, insets.top, 0, 0);
231 typeInsetMap[indexOf(SIDE_BARS)] = Insets.of(insets.left, 0, insets.right, insets.bottom);
Adrian Roosdd49eb72019-02-26 19:38:10 +0100232 typeInsetMap[indexOf(SYSTEM_GESTURES)] = Insets.of(insets);
Adam Powell50d7bfd2014-02-03 10:16:49 -0800233 }
234
Jorim Jaggi90990792019-01-21 23:00:20 +0100235 private static boolean[] createCompatVisibilityMap(@Nullable Insets[] typeInsetMap) {
236 boolean[] typeVisibilityMap = new boolean[SIZE];
237 if (typeInsetMap == null) {
238 return typeVisibilityMap;
239 }
240 for (int i = FIRST; i <= LAST; i = i << 1) {
241 int index = indexOf(i);
242 if (!Insets.NONE.equals(typeInsetMap[index])) {
243 typeVisibilityMap[index] = true;
244 }
245 }
246 return typeVisibilityMap;
247 }
248
Adam Powell50d7bfd2014-02-03 10:16:49 -0800249 /**
250 * Used to provide a safe copy of the system window insets to pass through
251 * to the existing fitSystemWindows method and other similar internals.
252 * @hide
Adrian Roos60f59292018-08-24 16:29:06 +0200253 *
254 * @deprecated use {@link #getSystemWindowInsets()} instead.
Adam Powell50d7bfd2014-02-03 10:16:49 -0800255 */
Adrian Roos60f59292018-08-24 16:29:06 +0200256 @Deprecated
Adrian Roos9272cfe2018-09-28 13:35:07 +0200257 @NonNull
Adrian Roos60f59292018-08-24 16:29:06 +0200258 public Rect getSystemWindowInsetsAsRect() {
Adam Powell50d7bfd2014-02-03 10:16:49 -0800259 if (mTempRect == null) {
260 mTempRect = new Rect();
261 }
Jorim Jaggi297985a2018-11-30 17:24:58 +0100262 Insets insets = getSystemWindowInsets();
263 mTempRect.set(insets.left, insets.top, insets.right, insets.bottom);
Adam Powell50d7bfd2014-02-03 10:16:49 -0800264 return mTempRect;
265 }
266
267 /**
Adrian Roos60f59292018-08-24 16:29:06 +0200268 * Returns the system window insets in pixels.
269 *
270 * <p>The system window inset represents the area of a full-screen window that is
271 * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
272 * </p>
273 *
274 * @return The system window insets
275 */
276 @NonNull
277 public Insets getSystemWindowInsets() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100278 return getInsets(mTypeInsetsMap, compatSystemInsets());
Adrian Roos60f59292018-08-24 16:29:06 +0200279 }
280
281 /**
Jorim Jaggibcf99ff2018-12-03 18:04:26 +0100282 * Returns the insets of a specific set of windows causing insets, denoted by the
283 * {@code typeMask} bit mask of {@link InsetType}s.
284 *
285 * @param typeMask Bit mask of {@link InsetType}s to query the insets for.
286 * @return The insets.
287 *
288 * @hide pending unhide
289 */
290 public Insets getInsets(@InsetType int typeMask) {
291 return getInsets(mTypeInsetsMap, typeMask);
292 }
293
294 /**
295 * Returns the maximum amount of insets a specific set of windows can cause, denoted by the
296 * {@code typeMask} bit mask of {@link InsetType}s.
297 *
298 * <p>The maximum insets represents the area of a a window that that <b>may</b> be partially
299 * or fully obscured by the system window identified by {@code type}. This value does not
300 * change based on the visibility state of those elements. for example, if the status bar is
301 * normally shown, but temporarily hidden, the maximum inset will still provide the inset
302 * associated with the status bar being shown.</p>
303 *
304 * @param typeMask Bit mask of {@link InsetType}s to query the insets for.
305 * @return The insets.
306 *
307 * @throws IllegalArgumentException If the caller tries to query {@link Type#ime()}. Maximum
308 * insets are not available for this type as the height of the
309 * IME is dynamic depending on the {@link EditorInfo} of the
310 * currently focused view, as well as the UI state of the IME.
311 * @hide pending unhide
312 */
313 public Insets getMaxInsets(@InsetType int typeMask) throws IllegalArgumentException {
314 if ((typeMask & IME) != 0) {
315 throw new IllegalArgumentException("Unable to query the maximum insets for IME");
316 }
317 return getInsets(mTypeMaxInsetsMap, typeMask);
318 }
319
320 /**
Jorim Jaggi90990792019-01-21 23:00:20 +0100321 * Returns whether a set of windows that may cause insets is currently visible on screen,
322 * regardless of whether it actually overlaps with this window.
323 *
324 * @param typeMask Bit mask of {@link InsetType}s to query visibility status.
325 * @return {@code true} if and only if all windows included in {@code typeMask} are currently
326 * visible on screen.
327 * @hide pending unhide
328 */
329 public boolean isVisible(@InsetType int typeMask) {
330 for (int i = FIRST; i <= LAST; i = i << 1) {
331 if ((typeMask & i) == 0) {
332 continue;
333 }
334 if (!mTypeVisibilityMap[indexOf(i)]) {
335 return false;
336 }
337 }
338 return true;
339 }
340
341 /**
Adam Powell50d7bfd2014-02-03 10:16:49 -0800342 * Returns the left system window inset in pixels.
343 *
344 * <p>The system window inset represents the area of a full-screen window that is
345 * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
346 * </p>
347 *
348 * @return The left system window inset
349 */
350 public int getSystemWindowInsetLeft() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100351 return getSystemWindowInsets().left;
Adam Powell50d7bfd2014-02-03 10:16:49 -0800352 }
353
354 /**
355 * Returns the top system window inset in pixels.
356 *
357 * <p>The system window inset represents the area of a full-screen window that is
358 * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
359 * </p>
360 *
361 * @return The top system window inset
362 */
363 public int getSystemWindowInsetTop() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100364 return getSystemWindowInsets().top;
Adam Powell50d7bfd2014-02-03 10:16:49 -0800365 }
366
367 /**
368 * Returns the right system window inset in pixels.
369 *
370 * <p>The system window inset represents the area of a full-screen window that is
371 * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
372 * </p>
373 *
374 * @return The right system window inset
375 */
376 public int getSystemWindowInsetRight() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100377 return getSystemWindowInsets().right;
Adam Powell50d7bfd2014-02-03 10:16:49 -0800378 }
379
380 /**
381 * Returns the bottom system window inset in pixels.
382 *
383 * <p>The system window inset represents the area of a full-screen window that is
384 * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
385 * </p>
386 *
387 * @return The bottom system window inset
388 */
389 public int getSystemWindowInsetBottom() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100390 return getSystemWindowInsets().bottom;
Adam Powell50d7bfd2014-02-03 10:16:49 -0800391 }
392
393 /**
394 * Returns true if this WindowInsets has nonzero system window insets.
395 *
396 * <p>The system window inset represents the area of a full-screen window that is
397 * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
398 * </p>
399 *
400 * @return true if any of the system window inset values are nonzero
401 */
402 public boolean hasSystemWindowInsets() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100403 return !getSystemWindowInsets().equals(Insets.NONE);
Adam Powell50d7bfd2014-02-03 10:16:49 -0800404 }
405
406 /**
407 * Returns true if this WindowInsets has any nonzero insets.
408 *
409 * @return true if any inset values are nonzero
410 */
411 public boolean hasInsets() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100412 return !getInsets(mTypeInsetsMap, all()).equals(Insets.NONE)
413 || !getInsets(mTypeMaxInsetsMap, all()).equals(Insets.NONE)
Adrian Roosd07bafd2017-12-11 17:30:56 +0100414 || mDisplayCutout != null;
Adam Powell50d7bfd2014-02-03 10:16:49 -0800415 }
416
Adam Powell973ddaa2014-04-15 17:38:54 -0700417 /**
Adrian Roosd07bafd2017-12-11 17:30:56 +0100418 * Returns the display cutout if there is one.
419 *
420 * @return the display cutout or null if there is none
Adrian Roosd4970af2017-11-10 15:48:01 +0100421 * @see DisplayCutout
Adrian Roosd4970af2017-11-10 15:48:01 +0100422 */
Adrian Roosd07bafd2017-12-11 17:30:56 +0100423 @Nullable
Adrian Roosd4970af2017-11-10 15:48:01 +0100424 public DisplayCutout getDisplayCutout() {
425 return mDisplayCutout;
426 }
427
428 /**
429 * Returns a copy of this WindowInsets with the cutout fully consumed.
430 *
431 * @return A modified copy of this WindowInsets
Adrian Roosd4970af2017-11-10 15:48:01 +0100432 */
Adrian Roos9272cfe2018-09-28 13:35:07 +0200433 @NonNull
Adrian Roosd07bafd2017-12-11 17:30:56 +0100434 public WindowInsets consumeDisplayCutout() {
Jorim Jaggi9b30a742019-01-21 15:21:44 +0100435 return new WindowInsets(mSystemWindowInsetsConsumed ? null : mTypeInsetsMap,
436 mStableInsetsConsumed ? null : mTypeMaxInsetsMap,
Jorim Jaggi90990792019-01-21 23:00:20 +0100437 mTypeVisibilityMap,
Adrian Roos60f59292018-08-24 16:29:06 +0200438 mIsRound, mAlwaysConsumeNavBar,
439 null /* displayCutout */);
Adrian Roosd4970af2017-11-10 15:48:01 +0100440 }
441
442
443 /**
Adam Powell0d9fdba2014-06-11 15:33:08 -0700444 * Check if these insets have been fully consumed.
445 *
446 * <p>Insets are considered "consumed" if the applicable <code>consume*</code> methods
447 * have been called such that all insets have been set to zero. This affects propagation of
448 * insets through the view hierarchy; insets that have not been fully consumed will continue
449 * to propagate down to child views.</p>
450 *
451 * <p>The result of this method is equivalent to the return value of
452 * {@link View#fitSystemWindows(android.graphics.Rect)}.</p>
453 *
454 * @return true if the insets have been fully consumed.
Adam Powell0d9fdba2014-06-11 15:33:08 -0700455 */
456 public boolean isConsumed() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100457 return mSystemWindowInsetsConsumed && mStableInsetsConsumed
Adrian Roosd07bafd2017-12-11 17:30:56 +0100458 && mDisplayCutoutConsumed;
Adam Powell0d9fdba2014-06-11 15:33:08 -0700459 }
460
461 /**
Adam Powell973ddaa2014-04-15 17:38:54 -0700462 * Returns true if the associated window has a round shape.
463 *
464 * <p>A round window's left, top, right and bottom edges reach all the way to the
465 * associated edges of the window but the corners may not be visible. Views responding
466 * to round insets should take care to not lay out critical elements within the corners
467 * where they may not be accessible.</p>
468 *
469 * @return True if the window is round
470 */
471 public boolean isRound() {
472 return mIsRound;
473 }
474
Adam Powellf4a39412014-05-05 17:29:17 -0700475 /**
476 * Returns a copy of this WindowInsets with the system window insets fully consumed.
477 *
478 * @return A modified copy of this WindowInsets
479 */
Adrian Roos9272cfe2018-09-28 13:35:07 +0200480 @NonNull
Adam Powellf4a39412014-05-05 17:29:17 -0700481 public WindowInsets consumeSystemWindowInsets() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100482 return new WindowInsets(null, mStableInsetsConsumed ? null : mTypeMaxInsetsMap,
Jorim Jaggi90990792019-01-21 23:00:20 +0100483 mTypeVisibilityMap,
Adrian Roos60f59292018-08-24 16:29:06 +0200484 mIsRound, mAlwaysConsumeNavBar,
485 displayCutoutCopyConstructorArgument(this));
Adam Powell50d7bfd2014-02-03 10:16:49 -0800486 }
487
Adrian Roos18b11d52018-11-07 19:04:19 +0100488 // TODO(b/119190588): replace @code with @link below
Adam Powellf4a39412014-05-05 17:29:17 -0700489 /**
490 * Returns a copy of this WindowInsets with selected system window insets replaced
491 * with new values.
492 *
Adrian Roos60f59292018-08-24 16:29:06 +0200493 * <p>Note: If the system window insets are already consumed, this method will return them
494 * unchanged on {@link android.os.Build.VERSION_CODES#Q Q} and later. Prior to
495 * {@link android.os.Build.VERSION_CODES#Q Q}, the new values were applied regardless of
496 * whether they were consumed, and this method returns invalid non-zero consumed insets.
497 *
Adam Powellf4a39412014-05-05 17:29:17 -0700498 * @param left New left inset in pixels
499 * @param top New top inset in pixels
500 * @param right New right inset in pixels
501 * @param bottom New bottom inset in pixels
502 * @return A modified copy of this WindowInsets
Adrian Roos18b11d52018-11-07 19:04:19 +0100503 * @deprecated use {@code Builder#Builder(WindowInsets)} with
Adrian Roosf35eb022018-07-25 18:29:10 +0200504 * {@link Builder#setSystemWindowInsets(Insets)} instead.
Adam Powellf4a39412014-05-05 17:29:17 -0700505 */
Adrian Roosf35eb022018-07-25 18:29:10 +0200506 @Deprecated
Adrian Roos9272cfe2018-09-28 13:35:07 +0200507 @NonNull
Adrian Roos60f59292018-08-24 16:29:06 +0200508 public WindowInsets replaceSystemWindowInsets(int left, int top, int right, int bottom) {
Adrian Roos60f59292018-08-24 16:29:06 +0200509 // Compat edge case: what should this do if the insets have already been consumed?
510 // On platforms prior to Q, the behavior was to override the insets with non-zero values,
511 // but leave them consumed, which is invalid (consumed insets must be zero).
512 // The behavior is now keeping them consumed and discarding the new insets.
513 if (mSystemWindowInsetsConsumed) {
514 return this;
515 }
Adrian Roosf35eb022018-07-25 18:29:10 +0200516 return new Builder(this).setSystemWindowInsets(Insets.of(left, top, right, bottom)).build();
Adam Powell50d7bfd2014-02-03 10:16:49 -0800517 }
518
Adrian Roos18b11d52018-11-07 19:04:19 +0100519 // TODO(b/119190588): replace @code with @link below
Adam Powellf4a39412014-05-05 17:29:17 -0700520 /**
Adam Powelld72068b2014-09-12 14:42:25 -0700521 * Returns a copy of this WindowInsets with selected system window insets replaced
522 * with new values.
523 *
Adrian Roos60f59292018-08-24 16:29:06 +0200524 * <p>Note: If the system window insets are already consumed, this method will return them
525 * unchanged on {@link android.os.Build.VERSION_CODES#Q Q} and later. Prior to
526 * {@link android.os.Build.VERSION_CODES#Q Q}, the new values were applied regardless of
527 * whether they were consumed, and this method returns invalid non-zero consumed insets.
528 *
Adam Powelld72068b2014-09-12 14:42:25 -0700529 * @param systemWindowInsets New system window insets. Each field is the inset in pixels
530 * for that edge
531 * @return A modified copy of this WindowInsets
Adrian Roos18b11d52018-11-07 19:04:19 +0100532 * @deprecated use {@code Builder#Builder(WindowInsets)} with
Adrian Roosf35eb022018-07-25 18:29:10 +0200533 * {@link Builder#setSystemWindowInsets(Insets)} instead.
Adam Powelld72068b2014-09-12 14:42:25 -0700534 */
Adrian Roosf35eb022018-07-25 18:29:10 +0200535 @Deprecated
Adrian Roos9272cfe2018-09-28 13:35:07 +0200536 @NonNull
Adam Powelld72068b2014-09-12 14:42:25 -0700537 public WindowInsets replaceSystemWindowInsets(Rect systemWindowInsets) {
Adrian Roos60f59292018-08-24 16:29:06 +0200538 return replaceSystemWindowInsets(systemWindowInsets.left, systemWindowInsets.top,
539 systemWindowInsets.right, systemWindowInsets.bottom);
Adam Powelld72068b2014-09-12 14:42:25 -0700540 }
541
542 /**
Adrian Roos60f59292018-08-24 16:29:06 +0200543 * Returns the stable insets in pixels.
544 *
545 * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
546 * partially or fully obscured by the system UI elements. This value does not change
547 * based on the visibility state of those elements; for example, if the status bar is
548 * normally shown, but temporarily hidden, the stable inset will still provide the inset
549 * associated with the status bar being shown.</p>
550 *
551 * @return The stable insets
Adam Powellf4a39412014-05-05 17:29:17 -0700552 */
Adrian Roos60f59292018-08-24 16:29:06 +0200553 @NonNull
554 public Insets getStableInsets() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100555 return getInsets(mTypeMaxInsetsMap, compatSystemInsets());
Adam Powell50d7bfd2014-02-03 10:16:49 -0800556 }
557
Adrian Roosfa104232014-06-20 16:10:14 -0700558 /**
Dianne Hackborn067e5f62014-09-07 23:14:30 -0700559 * Returns the top stable inset in pixels.
560 *
561 * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
562 * partially or fully obscured by the system UI elements. This value does not change
563 * based on the visibility state of those elements; for example, if the status bar is
564 * normally shown, but temporarily hidden, the stable inset will still provide the inset
565 * associated with the status bar being shown.</p>
566 *
567 * @return The top stable inset
Adrian Roosfa104232014-06-20 16:10:14 -0700568 */
569 public int getStableInsetTop() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100570 return getStableInsets().top;
Adrian Roosfa104232014-06-20 16:10:14 -0700571 }
572
573 /**
Dianne Hackborn067e5f62014-09-07 23:14:30 -0700574 * Returns the left stable inset in pixels.
575 *
576 * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
577 * partially or fully obscured by the system UI elements. This value does not change
578 * based on the visibility state of those elements; for example, if the status bar is
579 * normally shown, but temporarily hidden, the stable inset will still provide the inset
580 * associated with the status bar being shown.</p>
581 *
582 * @return The left stable inset
Adrian Roosfa104232014-06-20 16:10:14 -0700583 */
584 public int getStableInsetLeft() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100585 return getStableInsets().left;
Adrian Roosfa104232014-06-20 16:10:14 -0700586 }
587
588 /**
Dianne Hackborn067e5f62014-09-07 23:14:30 -0700589 * Returns the right stable inset in pixels.
590 *
591 * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
592 * partially or fully obscured by the system UI elements. This value does not change
593 * based on the visibility state of those elements; for example, if the status bar is
594 * normally shown, but temporarily hidden, the stable inset will still provide the inset
595 * associated with the status bar being shown.</p>
596 *
597 * @return The right stable inset
Adrian Roosfa104232014-06-20 16:10:14 -0700598 */
599 public int getStableInsetRight() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100600 return getStableInsets().right;
Adrian Roosfa104232014-06-20 16:10:14 -0700601 }
602
603 /**
Dianne Hackborn067e5f62014-09-07 23:14:30 -0700604 * Returns the bottom stable inset in pixels.
605 *
606 * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
607 * partially or fully obscured by the system UI elements. This value does not change
608 * based on the visibility state of those elements; for example, if the status bar is
609 * normally shown, but temporarily hidden, the stable inset will still provide the inset
610 * associated with the status bar being shown.</p>
611 *
612 * @return The bottom stable inset
Adrian Roosfa104232014-06-20 16:10:14 -0700613 */
614 public int getStableInsetBottom() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100615 return getStableInsets().bottom;
Adrian Roosfa104232014-06-20 16:10:14 -0700616 }
617
618 /**
Dianne Hackborn067e5f62014-09-07 23:14:30 -0700619 * Returns true if this WindowInsets has nonzero stable insets.
620 *
621 * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
622 * partially or fully obscured by the system UI elements. This value does not change
623 * based on the visibility state of those elements; for example, if the status bar is
624 * normally shown, but temporarily hidden, the stable inset will still provide the inset
625 * associated with the status bar being shown.</p>
626 *
627 * @return true if any of the stable inset values are nonzero
Adrian Roosfa104232014-06-20 16:10:14 -0700628 */
629 public boolean hasStableInsets() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100630 return !getStableInsets().equals(Insets.NONE);
Adrian Roosfa104232014-06-20 16:10:14 -0700631 }
632
633 /**
Adrian Roosdd49eb72019-02-26 19:38:10 +0100634 * Returns the system gesture insets.
635 *
636 * <p>The system gesture insets represent the area of a window where system gestures have
637 * priority and may consume some or all touch input, e.g. due to the a system bar
638 * occupying it, or it being reserved for touch-only gestures.
639 *
640 * <p>Simple taps are guaranteed to reach the window even within the system gesture insets,
641 * as long as they are outside the {@link #getSystemWindowInsets() system window insets}.
642 *
643 * <p>When {@link View#SYSTEM_UI_FLAG_LAYOUT_STABLE} is requested, an inset will be returned
644 * even when the system gestures are inactive due to
645 * {@link View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} or
646 * {@link View#SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}.
647 *
648 * <p>This inset does not affect the result of {@link #isConsumed()} and cannot be consumed.
649 */
650 @NonNull
651 public Insets getSystemGestureInsets() {
652 return getInsets(mTypeInsetsMap, SYSTEM_GESTURES);
653 }
654
655 /**
Dianne Hackborn067e5f62014-09-07 23:14:30 -0700656 * Returns a copy of this WindowInsets with the stable insets fully consumed.
657 *
658 * @return A modified copy of this WindowInsets
Adrian Roosfa104232014-06-20 16:10:14 -0700659 */
Adrian Roos9272cfe2018-09-28 13:35:07 +0200660 @NonNull
Adrian Roosfa104232014-06-20 16:10:14 -0700661 public WindowInsets consumeStableInsets() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100662 return new WindowInsets(mSystemWindowInsetsConsumed ? null : mTypeInsetsMap, null,
Jorim Jaggi90990792019-01-21 23:00:20 +0100663 mTypeVisibilityMap, mIsRound, mAlwaysConsumeNavBar,
Adrian Roos60f59292018-08-24 16:29:06 +0200664 displayCutoutCopyConstructorArgument(this));
Adrian Roosfa104232014-06-20 16:10:14 -0700665 }
666
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -0800667 /**
668 * @hide
669 */
670 public boolean shouldAlwaysConsumeNavBar() {
671 return mAlwaysConsumeNavBar;
672 }
673
Adam Powell50d7bfd2014-02-03 10:16:49 -0800674 @Override
675 public String toString() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100676 return "WindowInsets{systemWindowInsets=" + getSystemWindowInsets()
677 + " stableInsets=" + getStableInsets()
Adrian Roosd07bafd2017-12-11 17:30:56 +0100678 + (mDisplayCutout != null ? " cutout=" + mDisplayCutout : "")
Adrian Roosd4970af2017-11-10 15:48:01 +0100679 + (isRound() ? " round" : "")
680 + "}";
Adam Powell50d7bfd2014-02-03 10:16:49 -0800681 }
Adrian Roosf7b74262017-11-22 14:21:01 +0100682
683 /**
684 * Returns a copy of this instance inset in the given directions.
685 *
686 * @see #inset(int, int, int, int)
Adrian Roos60f59292018-08-24 16:29:06 +0200687 * @deprecated use {@link #inset(Insets)}
Adrian Roosf7b74262017-11-22 14:21:01 +0100688 * @hide
689 */
Adrian Roos60f59292018-08-24 16:29:06 +0200690 @Deprecated
Adrian Roos9272cfe2018-09-28 13:35:07 +0200691 @NonNull
Adrian Roosf7b74262017-11-22 14:21:01 +0100692 public WindowInsets inset(Rect r) {
693 return inset(r.left, r.top, r.right, r.bottom);
694 }
695
696 /**
697 * Returns a copy of this instance inset in the given directions.
698 *
Adrian Roos60f59292018-08-24 16:29:06 +0200699 * @see #inset(int, int, int, int)
700 * @hide
701 */
Adrian Roos9272cfe2018-09-28 13:35:07 +0200702 @NonNull
Adrian Roos60f59292018-08-24 16:29:06 +0200703 public WindowInsets inset(Insets insets) {
704 return inset(insets.left, insets.top, insets.right, insets.bottom);
705 }
706
707 /**
708 * Returns a copy of this instance inset in the given directions.
709 *
Adrian Roosf7b74262017-11-22 14:21:01 +0100710 * This is intended for dispatching insets to areas of the window that are smaller than the
711 * current area.
712 *
713 * <p>Example:
714 * <pre>
715 * childView.dispatchApplyWindowInsets(insets.inset(
716 * childMarginLeft, childMarginTop, childMarginBottom, childMarginRight));
717 * </pre>
718 *
719 * @param left the amount of insets to remove from the left. Must be non-negative.
720 * @param top the amount of insets to remove from the top. Must be non-negative.
721 * @param right the amount of insets to remove from the right. Must be non-negative.
722 * @param bottom the amount of insets to remove from the bottom. Must be non-negative.
723 *
724 * @return the inset insets
Adrian Roosf7b74262017-11-22 14:21:01 +0100725 */
Adrian Roosb57bfe02018-07-25 18:28:32 +0200726 @NonNull
Adrian Roos9e860352019-02-26 18:28:41 +0100727 public WindowInsets inset(@IntRange(from = 0) int left, @IntRange(from = 0) int top,
728 @IntRange(from = 0) int right, @IntRange(from = 0) int bottom) {
Adrian Roosf7b74262017-11-22 14:21:01 +0100729 Preconditions.checkArgumentNonnegative(left);
730 Preconditions.checkArgumentNonnegative(top);
731 Preconditions.checkArgumentNonnegative(right);
732 Preconditions.checkArgumentNonnegative(bottom);
733
Adrian Roos60f59292018-08-24 16:29:06 +0200734 return new WindowInsets(
Jorim Jaggi297985a2018-11-30 17:24:58 +0100735 mSystemWindowInsetsConsumed
736 ? null
737 : insetInsets(mTypeInsetsMap, left, top, right, bottom),
738 mStableInsetsConsumed
739 ? null
740 : insetInsets(mTypeMaxInsetsMap, left, top, right, bottom),
Jorim Jaggi90990792019-01-21 23:00:20 +0100741 mTypeVisibilityMap,
Adrian Roos60f59292018-08-24 16:29:06 +0200742 mIsRound, mAlwaysConsumeNavBar,
743 mDisplayCutoutConsumed
Jorim Jaggi297985a2018-11-30 17:24:58 +0100744 ? null
745 : mDisplayCutout == null
Adrian Roos60f59292018-08-24 16:29:06 +0200746 ? DisplayCutout.NO_CUTOUT
747 : mDisplayCutout.inset(left, top, right, bottom));
Adrian Roosf7b74262017-11-22 14:21:01 +0100748 }
749
750 @Override
751 public boolean equals(Object o) {
752 if (this == o) return true;
753 if (o == null || !(o instanceof WindowInsets)) return false;
754 WindowInsets that = (WindowInsets) o;
Jorim Jaggi297985a2018-11-30 17:24:58 +0100755
Adrian Roosf7b74262017-11-22 14:21:01 +0100756 return mIsRound == that.mIsRound
757 && mAlwaysConsumeNavBar == that.mAlwaysConsumeNavBar
758 && mSystemWindowInsetsConsumed == that.mSystemWindowInsetsConsumed
Adrian Roosf7b74262017-11-22 14:21:01 +0100759 && mStableInsetsConsumed == that.mStableInsetsConsumed
760 && mDisplayCutoutConsumed == that.mDisplayCutoutConsumed
Jorim Jaggi297985a2018-11-30 17:24:58 +0100761 && Arrays.equals(mTypeInsetsMap, that.mTypeInsetsMap)
762 && Arrays.equals(mTypeMaxInsetsMap, that.mTypeMaxInsetsMap)
Jorim Jaggi90990792019-01-21 23:00:20 +0100763 && Arrays.equals(mTypeVisibilityMap, that.mTypeVisibilityMap)
Adrian Roosf7b74262017-11-22 14:21:01 +0100764 && Objects.equals(mDisplayCutout, that.mDisplayCutout);
765 }
766
767 @Override
768 public int hashCode() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100769 return Objects.hash(Arrays.hashCode(mTypeInsetsMap), Arrays.hashCode(mTypeMaxInsetsMap),
Jorim Jaggi90990792019-01-21 23:00:20 +0100770 Arrays.hashCode(mTypeVisibilityMap), mIsRound, mDisplayCutout, mAlwaysConsumeNavBar,
771 mSystemWindowInsetsConsumed, mStableInsetsConsumed, mDisplayCutoutConsumed);
Jorim Jaggi297985a2018-11-30 17:24:58 +0100772 }
773
774
775 /**
776 * Insets every inset in {@code typeInsetsMap} by the specified left, top, right, bottom.
777 *
778 * @return {@code typeInsetsMap} if no inset was modified; a copy of the map with the modified
779 * insets otherwise.
780 */
781 private static Insets[] insetInsets(
782 Insets[] typeInsetsMap, int left, int top, int right, int bottom) {
783 boolean cloned = false;
784 for (int i = 0; i < SIZE; i++) {
785 Insets insets = typeInsetsMap[i];
786 if (insets == null) {
787 continue;
788 }
789 Insets insetInsets = insetInsets(insets, left, top, right, bottom);
790 if (insetInsets != insets) {
791 if (!cloned) {
792 typeInsetsMap = typeInsetsMap.clone();
793 cloned = true;
794 }
795 typeInsetsMap[i] = insetInsets;
796 }
797 }
798 return typeInsetsMap;
Adrian Roosf7b74262017-11-22 14:21:01 +0100799 }
800
Adrian Roos60f59292018-08-24 16:29:06 +0200801 private static Insets insetInsets(Insets insets, int left, int top, int right, int bottom) {
Adrian Roosf7b74262017-11-22 14:21:01 +0100802 int newLeft = Math.max(0, insets.left - left);
803 int newTop = Math.max(0, insets.top - top);
804 int newRight = Math.max(0, insets.right - right);
805 int newBottom = Math.max(0, insets.bottom - bottom);
806 if (newLeft == left && newTop == top && newRight == right && newBottom == bottom) {
807 return insets;
808 }
Adrian Roos60f59292018-08-24 16:29:06 +0200809 return Insets.of(newLeft, newTop, newRight, newBottom);
Adrian Roosf7b74262017-11-22 14:21:01 +0100810 }
811
812 /**
813 * @return whether system window insets have been consumed.
814 */
815 boolean isSystemWindowInsetsConsumed() {
816 return mSystemWindowInsetsConsumed;
817 }
Adrian Roosf35eb022018-07-25 18:29:10 +0200818
819 /**
820 * Builder for WindowInsets.
821 */
Adrian Roos9e860352019-02-26 18:28:41 +0100822 public static final class Builder {
Adrian Roosf35eb022018-07-25 18:29:10 +0200823
Jorim Jaggi297985a2018-11-30 17:24:58 +0100824 private final Insets[] mTypeInsetsMap;
825 private final Insets[] mTypeMaxInsetsMap;
Jorim Jaggi90990792019-01-21 23:00:20 +0100826 private final boolean[] mTypeVisibilityMap;
Jorim Jaggi297985a2018-11-30 17:24:58 +0100827 private boolean mSystemInsetsConsumed = true;
828 private boolean mStableInsetsConsumed = true;
829
Adrian Roosf35eb022018-07-25 18:29:10 +0200830 private DisplayCutout mDisplayCutout;
831
Adrian Roosf35eb022018-07-25 18:29:10 +0200832 private boolean mIsRound;
833 private boolean mAlwaysConsumeNavBar;
834
835 /**
836 * Creates a builder where all insets are initially consumed.
837 */
838 public Builder() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100839 mTypeInsetsMap = new Insets[SIZE];
840 mTypeMaxInsetsMap = new Insets[SIZE];
Jorim Jaggi90990792019-01-21 23:00:20 +0100841 mTypeVisibilityMap = new boolean[SIZE];
Adrian Roosf35eb022018-07-25 18:29:10 +0200842 }
843
844 /**
845 * Creates a builder where all insets are initialized from {@link WindowInsets}.
846 *
847 * @param insets the instance to initialize from.
848 */
Adrian Roos9e860352019-02-26 18:28:41 +0100849 public Builder(@NonNull WindowInsets insets) {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100850 mTypeInsetsMap = insets.mTypeInsetsMap.clone();
851 mTypeMaxInsetsMap = insets.mTypeMaxInsetsMap.clone();
Jorim Jaggi90990792019-01-21 23:00:20 +0100852 mTypeVisibilityMap = insets.mTypeVisibilityMap.clone();
Jorim Jaggi297985a2018-11-30 17:24:58 +0100853 mSystemInsetsConsumed = insets.mSystemWindowInsetsConsumed;
854 mStableInsetsConsumed = insets.mStableInsetsConsumed;
Adrian Roosf35eb022018-07-25 18:29:10 +0200855 mDisplayCutout = displayCutoutCopyConstructorArgument(insets);
Adrian Roosf35eb022018-07-25 18:29:10 +0200856 mIsRound = insets.mIsRound;
857 mAlwaysConsumeNavBar = insets.mAlwaysConsumeNavBar;
858 }
859
860 /**
861 * Sets system window insets in pixels.
862 *
863 * <p>The system window inset represents the area of a full-screen window that is
864 * partially or fully obscured by the status bar, navigation bar, IME or other system
865 * windows.</p>
866 *
867 * @see #getSystemWindowInsets()
868 * @return itself
869 */
870 @NonNull
871 public Builder setSystemWindowInsets(@NonNull Insets systemWindowInsets) {
872 Preconditions.checkNotNull(systemWindowInsets);
Jorim Jaggi297985a2018-11-30 17:24:58 +0100873 assignCompatInsets(mTypeInsetsMap, systemWindowInsets.toRect());
874 mSystemInsetsConsumed = false;
Adrian Roosf35eb022018-07-25 18:29:10 +0200875 return this;
876 }
877
878 /**
Adrian Roosdd49eb72019-02-26 19:38:10 +0100879 * Sets system gesture insets in pixels.
880 *
881 * <p>The system gesture insets represent the area of a window where system gestures have
882 * priority and may consume some or all touch input, e.g. due to the a system bar
883 * occupying it, or it being reserved for touch-only gestures.
884 *
885 * @see #getSystemGestureInsets()
886 * @return itself
887 */
888 @NonNull
889 public Builder setSystemGestureInsets(@NonNull Insets insets) {
890 WindowInsets.setInsets(mTypeInsetsMap, SYSTEM_GESTURES, insets);
891 return this;
892 }
893
894 /**
Jorim Jaggibcf99ff2018-12-03 18:04:26 +0100895 * Sets the insets of a specific window type in pixels.
896 *
897 * <p>The insets represents the area of a a window that is partially or fully obscured by
898 * the system windows identified by {@code typeMask}.
899 * </p>
900 *
901 * @see #getInsets(int)
902 *
903 * @param typeMask The bitmask of {@link InsetType} to set the insets for.
904 * @param insets The insets to set.
905 *
906 * @return itself
907 * @hide pending unhide
908 */
909 @NonNull
910 public Builder setInsets(@InsetType int typeMask, @NonNull Insets insets) {
911 Preconditions.checkNotNull(insets);
912 WindowInsets.setInsets(mTypeInsetsMap, typeMask, insets);
913 mSystemInsetsConsumed = false;
914 return this;
915 }
916
917 /**
918 * Sets the maximum amount of insets a specific window type in pixels.
919 *
920 * <p>The maximum insets represents the area of a a window that that <b>may</b> be partially
921 * or fully obscured by the system windows identified by {@code typeMask}. This value does
922 * not change based on the visibility state of those elements. for example, if the status
923 * bar is normally shown, but temporarily hidden, the maximum inset will still provide the
924 * inset associated with the status bar being shown.</p>
925 *
926 * @see #getMaxInsets(int)
927 *
928 * @param typeMask The bitmask of {@link InsetType} to set the insets for.
929 * @param insets The insets to set.
930 *
931 * @return itself
932 *
933 * @throws IllegalArgumentException If {@code typeMask} contains {@link Type#ime()}. Maximum
934 * insets are not available for this type as the height of
935 * the IME is dynamic depending on the {@link EditorInfo}
936 * of the currently focused view, as well as the UI
937 * state of the IME.
938 * @hide pending unhide
939 */
940 @NonNull
941 public Builder setMaxInsets(@InsetType int typeMask, @NonNull Insets insets)
942 throws IllegalArgumentException{
943 if (typeMask == IME) {
944 throw new IllegalArgumentException("Maximum inset not available for IME");
945 }
946 Preconditions.checkNotNull(insets);
947 WindowInsets.setInsets(mTypeMaxInsetsMap, typeMask, insets);
948 mStableInsetsConsumed = false;
949 return this;
950 }
951
952 /**
Jorim Jaggi90990792019-01-21 23:00:20 +0100953 * Sets whether windows that can cause insets are currently visible on screen.
954 *
955 *
956 * @see #isVisible(int)
957 *
958 * @param typeMask The bitmask of {@link InsetType} to set the visibility for.
959 * @param visible Whether to mark the windows as visible or not.
960 *
961 * @return itself
962 * @hide pending unhide
963 */
964 @NonNull
965 public Builder setVisible(@InsetType int typeMask, boolean visible) {
966 for (int i = FIRST; i <= LAST; i = i << 1) {
967 if ((typeMask & i) == 0) {
968 continue;
969 }
970 mTypeVisibilityMap[indexOf(i)] = visible;
971 }
972 return this;
973 }
974
975 /**
Adrian Roosf35eb022018-07-25 18:29:10 +0200976 * Sets the stable insets in pixels.
977 *
978 * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
979 * partially or fully obscured by the system UI elements. This value does not change
980 * based on the visibility state of those elements; for example, if the status bar is
981 * normally shown, but temporarily hidden, the stable inset will still provide the inset
982 * associated with the status bar being shown.</p>
983 *
984 * @see #getStableInsets()
985 * @return itself
986 */
987 @NonNull
988 public Builder setStableInsets(@NonNull Insets stableInsets) {
989 Preconditions.checkNotNull(stableInsets);
Jorim Jaggi9b30a742019-01-21 15:21:44 +0100990 assignCompatInsets(mTypeMaxInsetsMap, stableInsets.toRect());
Jorim Jaggi297985a2018-11-30 17:24:58 +0100991 mStableInsetsConsumed = false;
Adrian Roosf35eb022018-07-25 18:29:10 +0200992 return this;
993 }
994
995 /**
996 * Sets the display cutout.
997 *
998 * @see #getDisplayCutout()
999 * @param displayCutout the display cutout or null if there is none
1000 * @return itself
1001 */
1002 @NonNull
1003 public Builder setDisplayCutout(@Nullable DisplayCutout displayCutout) {
1004 mDisplayCutout = displayCutout != null ? displayCutout : DisplayCutout.NO_CUTOUT;
1005 return this;
1006 }
1007
1008 /** @hide */
1009 @NonNull
Adrian Roosf35eb022018-07-25 18:29:10 +02001010 public Builder setRound(boolean round) {
1011 mIsRound = round;
1012 return this;
1013 }
1014
1015 /** @hide */
1016 @NonNull
1017 public Builder setAlwaysConsumeNavBar(boolean alwaysConsumeNavBar) {
1018 mAlwaysConsumeNavBar = alwaysConsumeNavBar;
1019 return this;
1020 }
1021
1022 /**
1023 * Builds a {@link WindowInsets} instance.
1024 *
1025 * @return the {@link WindowInsets} instance.
1026 */
1027 @NonNull
1028 public WindowInsets build() {
Jorim Jaggi297985a2018-11-30 17:24:58 +01001029 return new WindowInsets(mSystemInsetsConsumed ? null : mTypeInsetsMap,
Jorim Jaggi90990792019-01-21 23:00:20 +01001030 mStableInsetsConsumed ? null : mTypeMaxInsetsMap, mTypeVisibilityMap,
1031 mIsRound, mAlwaysConsumeNavBar, mDisplayCutout);
Adrian Roosf35eb022018-07-25 18:29:10 +02001032 }
1033 }
Jorim Jaggib6030952018-10-23 18:31:52 +02001034
1035 /**
1036 * Class that defines different types of sources causing window insets.
1037 * @hide pending unhide
1038 */
1039 public static final class Type {
1040
Jorim Jaggi297985a2018-11-30 17:24:58 +01001041 static final int FIRST = 0x1;
1042 static final int TOP_BAR = FIRST;
1043
Jorim Jaggib6030952018-10-23 18:31:52 +02001044 static final int IME = 0x2;
1045 static final int SIDE_BARS = 0x4;
Jorim Jaggi297985a2018-11-30 17:24:58 +01001046
Adrian Roosdd49eb72019-02-26 19:38:10 +01001047 static final int SYSTEM_GESTURES = 0x8;
1048
1049 static final int LAST = 0x10;
1050 static final int SIZE = 5;
Jorim Jaggi297985a2018-11-30 17:24:58 +01001051 static final int WINDOW_DECOR = LAST;
1052
1053 static int indexOf(@InsetType int type) {
1054 switch (type) {
1055 case TOP_BAR:
1056 return 0;
1057 case IME:
1058 return 1;
1059 case SIDE_BARS:
1060 return 2;
Adrian Roosdd49eb72019-02-26 19:38:10 +01001061 case SYSTEM_GESTURES:
Jorim Jaggi297985a2018-11-30 17:24:58 +01001062 return 3;
Adrian Roosdd49eb72019-02-26 19:38:10 +01001063 case WINDOW_DECOR:
1064 return 4;
Jorim Jaggi297985a2018-11-30 17:24:58 +01001065 default:
1066 throw new IllegalArgumentException("type needs to be >= FIRST and <= LAST,"
1067 + " type=" + type);
1068 }
1069 }
Jorim Jaggib6030952018-10-23 18:31:52 +02001070
1071 private Type() {
1072 }
1073
1074 /** @hide */
1075 @Retention(RetentionPolicy.SOURCE)
Adrian Roosdd49eb72019-02-26 19:38:10 +01001076 @IntDef(flag = true, value = { TOP_BAR, IME, SIDE_BARS, WINDOW_DECOR, SYSTEM_GESTURES })
Jorim Jaggib6030952018-10-23 18:31:52 +02001077 public @interface InsetType {
1078 }
1079
1080 /**
1081 * @return An inset type representing the top bar of a window, which can be the status
1082 * bar on handheld-like devices as well as a caption bar.
1083 */
1084 public static @InsetType int topBar() {
1085 return TOP_BAR;
1086 }
1087
1088 /**
1089 * @return An inset type representing the window of an {@link InputMethod}.
1090 */
1091 public static @InsetType int ime() {
1092 return IME;
1093 }
1094
1095 /**
1096 * @return An inset type representing any system bars that are not {@link #topBar()}.
1097 */
1098 public static @InsetType int sideBars() {
1099 return SIDE_BARS;
1100 }
1101
1102 /**
1103 * @return An inset type representing decor that is being app-controlled.
1104 */
1105 public static @InsetType int windowDecor() {
1106 return WINDOW_DECOR;
1107 }
1108
1109 /**
Adrian Roosdd49eb72019-02-26 19:38:10 +01001110 * Returns an inset type representing the system gesture insets.
1111 *
1112 * <p>The system gesture insets represent the area of a window where system gestures have
1113 * priority and may consume some or all touch input, e.g. due to the a system bar
1114 * occupying it, or it being reserved for touch-only gestures.
1115 *
1116 * <p>Simple taps are guaranteed to reach the window even within the system gesture insets,
1117 * as long as they are outside the {@link #getSystemWindowInsets() system window insets}.
1118 *
1119 * <p>When {@link View#SYSTEM_UI_FLAG_LAYOUT_STABLE} is requested, an inset will be returned
1120 * even when the system gestures are inactive due to
1121 * {@link View#SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} or
1122 * {@link View#SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}.
1123 *
1124 * @see #getSystemGestureInsets()
1125 */
1126 public static @InsetType int systemGestures() {
1127 return SYSTEM_GESTURES;
1128 }
1129
1130 /**
Jorim Jaggib6030952018-10-23 18:31:52 +02001131 * @return All system bars. Includes {@link #topBar()} as well as {@link #sideBars()}, but
1132 * not {@link #ime()}.
1133 */
1134 public static @InsetType int systemBars() {
1135 return TOP_BAR | SIDE_BARS;
1136 }
1137
1138 /**
Jorim Jaggi297985a2018-11-30 17:24:58 +01001139 * @return Inset types representing the list of bars that traditionally were denoted as
1140 * system insets.
1141 * @hide
1142 */
1143 static @InsetType int compatSystemInsets() {
1144 return TOP_BAR | SIDE_BARS | IME;
1145 }
1146
1147 /**
Jorim Jaggib6030952018-10-23 18:31:52 +02001148 * @return All inset types combined.
Adrian Roosdd49eb72019-02-26 19:38:10 +01001149 *
1150 * TODO: Figure out if this makes sense at all, mixing e.g {@link #systemGestures()} and
1151 * {@link #ime()} does not seem very useful.
Jorim Jaggib6030952018-10-23 18:31:52 +02001152 */
1153 public static @InsetType int all() {
1154 return 0xFFFFFFFF;
1155 }
1156 }
Adam Powell50d7bfd2014-02-03 10:16:49 -08001157}