blob: 135a8912fc60c62002377a7c82da7c266a6d3d35 [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;
25import static android.view.WindowInsets.Type.TOP_BAR;
26import static android.view.WindowInsets.Type.all;
27import static android.view.WindowInsets.Type.compatSystemInsets;
28import static android.view.WindowInsets.Type.indexOf;
29
Jorim Jaggib6030952018-10-23 18:31:52 +020030import android.annotation.IntDef;
Adrian Roos9e860352019-02-26 18:28:41 +010031import android.annotation.IntRange;
Jorim Jaggi297985a2018-11-30 17:24:58 +010032import android.annotation.NonNull;
Adrian Roosd07bafd2017-12-11 17:30:56 +010033import android.annotation.Nullable;
Mathew Inwooda570dee2018-08-17 14:56:00 +010034import android.annotation.UnsupportedAppUsage;
Adrian Roos60f59292018-08-24 16:29:06 +020035import android.graphics.Insets;
Adam Powell50d7bfd2014-02-03 10:16:49 -080036import android.graphics.Rect;
Jorim Jaggi297985a2018-11-30 17:24:58 +010037import android.util.SparseArray;
Jorim Jaggibcf99ff2018-12-03 18:04:26 +010038import android.view.InsetsState.InternalInsetType;
Jorim Jaggi297985a2018-11-30 17:24:58 +010039import 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);
Adam Powell50d7bfd2014-02-03 10:16:49 -0800232 }
233
Jorim Jaggi90990792019-01-21 23:00:20 +0100234 private static boolean[] createCompatVisibilityMap(@Nullable Insets[] typeInsetMap) {
235 boolean[] typeVisibilityMap = new boolean[SIZE];
236 if (typeInsetMap == null) {
237 return typeVisibilityMap;
238 }
239 for (int i = FIRST; i <= LAST; i = i << 1) {
240 int index = indexOf(i);
241 if (!Insets.NONE.equals(typeInsetMap[index])) {
242 typeVisibilityMap[index] = true;
243 }
244 }
245 return typeVisibilityMap;
246 }
247
Adam Powell50d7bfd2014-02-03 10:16:49 -0800248 /**
249 * Used to provide a safe copy of the system window insets to pass through
250 * to the existing fitSystemWindows method and other similar internals.
251 * @hide
Adrian Roos60f59292018-08-24 16:29:06 +0200252 *
253 * @deprecated use {@link #getSystemWindowInsets()} instead.
Adam Powell50d7bfd2014-02-03 10:16:49 -0800254 */
Adrian Roos60f59292018-08-24 16:29:06 +0200255 @Deprecated
Adrian Roos9272cfe2018-09-28 13:35:07 +0200256 @NonNull
Adrian Roos60f59292018-08-24 16:29:06 +0200257 public Rect getSystemWindowInsetsAsRect() {
Adam Powell50d7bfd2014-02-03 10:16:49 -0800258 if (mTempRect == null) {
259 mTempRect = new Rect();
260 }
Jorim Jaggi297985a2018-11-30 17:24:58 +0100261 Insets insets = getSystemWindowInsets();
262 mTempRect.set(insets.left, insets.top, insets.right, insets.bottom);
Adam Powell50d7bfd2014-02-03 10:16:49 -0800263 return mTempRect;
264 }
265
266 /**
Adrian Roos60f59292018-08-24 16:29:06 +0200267 * Returns the system window insets in pixels.
268 *
269 * <p>The system window inset represents the area of a full-screen window that is
270 * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
271 * </p>
272 *
273 * @return The system window insets
274 */
275 @NonNull
276 public Insets getSystemWindowInsets() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100277 return getInsets(mTypeInsetsMap, compatSystemInsets());
Adrian Roos60f59292018-08-24 16:29:06 +0200278 }
279
280 /**
Jorim Jaggibcf99ff2018-12-03 18:04:26 +0100281 * Returns the insets of a specific set of windows causing insets, denoted by the
282 * {@code typeMask} bit mask of {@link InsetType}s.
283 *
284 * @param typeMask Bit mask of {@link InsetType}s to query the insets for.
285 * @return The insets.
286 *
287 * @hide pending unhide
288 */
289 public Insets getInsets(@InsetType int typeMask) {
290 return getInsets(mTypeInsetsMap, typeMask);
291 }
292
293 /**
294 * Returns the maximum amount of insets a specific set of windows can cause, denoted by the
295 * {@code typeMask} bit mask of {@link InsetType}s.
296 *
297 * <p>The maximum insets represents the area of a a window that that <b>may</b> be partially
298 * or fully obscured by the system window identified by {@code type}. This value does not
299 * change based on the visibility state of those elements. for example, if the status bar is
300 * normally shown, but temporarily hidden, the maximum inset will still provide the inset
301 * associated with the status bar being shown.</p>
302 *
303 * @param typeMask Bit mask of {@link InsetType}s to query the insets for.
304 * @return The insets.
305 *
306 * @throws IllegalArgumentException If the caller tries to query {@link Type#ime()}. Maximum
307 * insets are not available for this type as the height of the
308 * IME is dynamic depending on the {@link EditorInfo} of the
309 * currently focused view, as well as the UI state of the IME.
310 * @hide pending unhide
311 */
312 public Insets getMaxInsets(@InsetType int typeMask) throws IllegalArgumentException {
313 if ((typeMask & IME) != 0) {
314 throw new IllegalArgumentException("Unable to query the maximum insets for IME");
315 }
316 return getInsets(mTypeMaxInsetsMap, typeMask);
317 }
318
319 /**
Jorim Jaggi90990792019-01-21 23:00:20 +0100320 * Returns whether a set of windows that may cause insets is currently visible on screen,
321 * regardless of whether it actually overlaps with this window.
322 *
323 * @param typeMask Bit mask of {@link InsetType}s to query visibility status.
324 * @return {@code true} if and only if all windows included in {@code typeMask} are currently
325 * visible on screen.
326 * @hide pending unhide
327 */
328 public boolean isVisible(@InsetType int typeMask) {
329 for (int i = FIRST; i <= LAST; i = i << 1) {
330 if ((typeMask & i) == 0) {
331 continue;
332 }
333 if (!mTypeVisibilityMap[indexOf(i)]) {
334 return false;
335 }
336 }
337 return true;
338 }
339
340 /**
Adam Powell50d7bfd2014-02-03 10:16:49 -0800341 * Returns the left system window inset in pixels.
342 *
343 * <p>The system window inset represents the area of a full-screen window that is
344 * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
345 * </p>
346 *
347 * @return The left system window inset
348 */
349 public int getSystemWindowInsetLeft() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100350 return getSystemWindowInsets().left;
Adam Powell50d7bfd2014-02-03 10:16:49 -0800351 }
352
353 /**
354 * Returns the top system window inset in pixels.
355 *
356 * <p>The system window inset represents the area of a full-screen window that is
357 * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
358 * </p>
359 *
360 * @return The top system window inset
361 */
362 public int getSystemWindowInsetTop() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100363 return getSystemWindowInsets().top;
Adam Powell50d7bfd2014-02-03 10:16:49 -0800364 }
365
366 /**
367 * Returns the right system window inset in pixels.
368 *
369 * <p>The system window inset represents the area of a full-screen window that is
370 * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
371 * </p>
372 *
373 * @return The right system window inset
374 */
375 public int getSystemWindowInsetRight() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100376 return getSystemWindowInsets().right;
Adam Powell50d7bfd2014-02-03 10:16:49 -0800377 }
378
379 /**
380 * Returns the bottom system window inset in pixels.
381 *
382 * <p>The system window inset represents the area of a full-screen window that is
383 * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
384 * </p>
385 *
386 * @return The bottom system window inset
387 */
388 public int getSystemWindowInsetBottom() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100389 return getSystemWindowInsets().bottom;
Adam Powell50d7bfd2014-02-03 10:16:49 -0800390 }
391
392 /**
393 * Returns true if this WindowInsets has nonzero system window insets.
394 *
395 * <p>The system window inset represents the area of a full-screen window that is
396 * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
397 * </p>
398 *
399 * @return true if any of the system window inset values are nonzero
400 */
401 public boolean hasSystemWindowInsets() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100402 return !getSystemWindowInsets().equals(Insets.NONE);
Adam Powell50d7bfd2014-02-03 10:16:49 -0800403 }
404
405 /**
406 * Returns true if this WindowInsets has any nonzero insets.
407 *
408 * @return true if any inset values are nonzero
409 */
410 public boolean hasInsets() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100411 return !getInsets(mTypeInsetsMap, all()).equals(Insets.NONE)
412 || !getInsets(mTypeMaxInsetsMap, all()).equals(Insets.NONE)
Adrian Roosd07bafd2017-12-11 17:30:56 +0100413 || mDisplayCutout != null;
Adam Powell50d7bfd2014-02-03 10:16:49 -0800414 }
415
Adam Powell973ddaa2014-04-15 17:38:54 -0700416 /**
Adrian Roosd07bafd2017-12-11 17:30:56 +0100417 * Returns the display cutout if there is one.
418 *
419 * @return the display cutout or null if there is none
Adrian Roosd4970af2017-11-10 15:48:01 +0100420 * @see DisplayCutout
Adrian Roosd4970af2017-11-10 15:48:01 +0100421 */
Adrian Roosd07bafd2017-12-11 17:30:56 +0100422 @Nullable
Adrian Roosd4970af2017-11-10 15:48:01 +0100423 public DisplayCutout getDisplayCutout() {
424 return mDisplayCutout;
425 }
426
427 /**
428 * Returns a copy of this WindowInsets with the cutout fully consumed.
429 *
430 * @return A modified copy of this WindowInsets
Adrian Roosd4970af2017-11-10 15:48:01 +0100431 */
Adrian Roos9272cfe2018-09-28 13:35:07 +0200432 @NonNull
Adrian Roosd07bafd2017-12-11 17:30:56 +0100433 public WindowInsets consumeDisplayCutout() {
Jorim Jaggi9b30a742019-01-21 15:21:44 +0100434 return new WindowInsets(mSystemWindowInsetsConsumed ? null : mTypeInsetsMap,
435 mStableInsetsConsumed ? null : mTypeMaxInsetsMap,
Jorim Jaggi90990792019-01-21 23:00:20 +0100436 mTypeVisibilityMap,
Adrian Roos60f59292018-08-24 16:29:06 +0200437 mIsRound, mAlwaysConsumeNavBar,
438 null /* displayCutout */);
Adrian Roosd4970af2017-11-10 15:48:01 +0100439 }
440
441
442 /**
Adam Powell0d9fdba2014-06-11 15:33:08 -0700443 * Check if these insets have been fully consumed.
444 *
445 * <p>Insets are considered "consumed" if the applicable <code>consume*</code> methods
446 * have been called such that all insets have been set to zero. This affects propagation of
447 * insets through the view hierarchy; insets that have not been fully consumed will continue
448 * to propagate down to child views.</p>
449 *
450 * <p>The result of this method is equivalent to the return value of
451 * {@link View#fitSystemWindows(android.graphics.Rect)}.</p>
452 *
453 * @return true if the insets have been fully consumed.
Adam Powell0d9fdba2014-06-11 15:33:08 -0700454 */
455 public boolean isConsumed() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100456 return mSystemWindowInsetsConsumed && mStableInsetsConsumed
Adrian Roosd07bafd2017-12-11 17:30:56 +0100457 && mDisplayCutoutConsumed;
Adam Powell0d9fdba2014-06-11 15:33:08 -0700458 }
459
460 /**
Adam Powell973ddaa2014-04-15 17:38:54 -0700461 * Returns true if the associated window has a round shape.
462 *
463 * <p>A round window's left, top, right and bottom edges reach all the way to the
464 * associated edges of the window but the corners may not be visible. Views responding
465 * to round insets should take care to not lay out critical elements within the corners
466 * where they may not be accessible.</p>
467 *
468 * @return True if the window is round
469 */
470 public boolean isRound() {
471 return mIsRound;
472 }
473
Adam Powellf4a39412014-05-05 17:29:17 -0700474 /**
475 * Returns a copy of this WindowInsets with the system window insets fully consumed.
476 *
477 * @return A modified copy of this WindowInsets
478 */
Adrian Roos9272cfe2018-09-28 13:35:07 +0200479 @NonNull
Adam Powellf4a39412014-05-05 17:29:17 -0700480 public WindowInsets consumeSystemWindowInsets() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100481 return new WindowInsets(null, mStableInsetsConsumed ? null : mTypeMaxInsetsMap,
Jorim Jaggi90990792019-01-21 23:00:20 +0100482 mTypeVisibilityMap,
Adrian Roos60f59292018-08-24 16:29:06 +0200483 mIsRound, mAlwaysConsumeNavBar,
484 displayCutoutCopyConstructorArgument(this));
Adam Powell50d7bfd2014-02-03 10:16:49 -0800485 }
486
Adrian Roos18b11d52018-11-07 19:04:19 +0100487 // TODO(b/119190588): replace @code with @link below
Adam Powellf4a39412014-05-05 17:29:17 -0700488 /**
489 * Returns a copy of this WindowInsets with selected system window insets replaced
490 * with new values.
491 *
Adrian Roos60f59292018-08-24 16:29:06 +0200492 * <p>Note: If the system window insets are already consumed, this method will return them
493 * unchanged on {@link android.os.Build.VERSION_CODES#Q Q} and later. Prior to
494 * {@link android.os.Build.VERSION_CODES#Q Q}, the new values were applied regardless of
495 * whether they were consumed, and this method returns invalid non-zero consumed insets.
496 *
Adam Powellf4a39412014-05-05 17:29:17 -0700497 * @param left New left inset in pixels
498 * @param top New top inset in pixels
499 * @param right New right inset in pixels
500 * @param bottom New bottom inset in pixels
501 * @return A modified copy of this WindowInsets
Adrian Roos18b11d52018-11-07 19:04:19 +0100502 * @deprecated use {@code Builder#Builder(WindowInsets)} with
Adrian Roosf35eb022018-07-25 18:29:10 +0200503 * {@link Builder#setSystemWindowInsets(Insets)} instead.
Adam Powellf4a39412014-05-05 17:29:17 -0700504 */
Adrian Roosf35eb022018-07-25 18:29:10 +0200505 @Deprecated
Adrian Roos9272cfe2018-09-28 13:35:07 +0200506 @NonNull
Adrian Roos60f59292018-08-24 16:29:06 +0200507 public WindowInsets replaceSystemWindowInsets(int left, int top, int right, int bottom) {
Adrian Roos60f59292018-08-24 16:29:06 +0200508 // Compat edge case: what should this do if the insets have already been consumed?
509 // On platforms prior to Q, the behavior was to override the insets with non-zero values,
510 // but leave them consumed, which is invalid (consumed insets must be zero).
511 // The behavior is now keeping them consumed and discarding the new insets.
512 if (mSystemWindowInsetsConsumed) {
513 return this;
514 }
Adrian Roosf35eb022018-07-25 18:29:10 +0200515 return new Builder(this).setSystemWindowInsets(Insets.of(left, top, right, bottom)).build();
Adam Powell50d7bfd2014-02-03 10:16:49 -0800516 }
517
Adrian Roos18b11d52018-11-07 19:04:19 +0100518 // TODO(b/119190588): replace @code with @link below
Adam Powellf4a39412014-05-05 17:29:17 -0700519 /**
Adam Powelld72068b2014-09-12 14:42:25 -0700520 * Returns a copy of this WindowInsets with selected system window insets replaced
521 * with new values.
522 *
Adrian Roos60f59292018-08-24 16:29:06 +0200523 * <p>Note: If the system window insets are already consumed, this method will return them
524 * unchanged on {@link android.os.Build.VERSION_CODES#Q Q} and later. Prior to
525 * {@link android.os.Build.VERSION_CODES#Q Q}, the new values were applied regardless of
526 * whether they were consumed, and this method returns invalid non-zero consumed insets.
527 *
Adam Powelld72068b2014-09-12 14:42:25 -0700528 * @param systemWindowInsets New system window insets. Each field is the inset in pixels
529 * for that edge
530 * @return A modified copy of this WindowInsets
Adrian Roos18b11d52018-11-07 19:04:19 +0100531 * @deprecated use {@code Builder#Builder(WindowInsets)} with
Adrian Roosf35eb022018-07-25 18:29:10 +0200532 * {@link Builder#setSystemWindowInsets(Insets)} instead.
Adam Powelld72068b2014-09-12 14:42:25 -0700533 */
Adrian Roosf35eb022018-07-25 18:29:10 +0200534 @Deprecated
Adrian Roos9272cfe2018-09-28 13:35:07 +0200535 @NonNull
Adam Powelld72068b2014-09-12 14:42:25 -0700536 public WindowInsets replaceSystemWindowInsets(Rect systemWindowInsets) {
Adrian Roos60f59292018-08-24 16:29:06 +0200537 return replaceSystemWindowInsets(systemWindowInsets.left, systemWindowInsets.top,
538 systemWindowInsets.right, systemWindowInsets.bottom);
Adam Powelld72068b2014-09-12 14:42:25 -0700539 }
540
541 /**
Adrian Roos60f59292018-08-24 16:29:06 +0200542 * Returns the stable insets in pixels.
543 *
544 * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
545 * partially or fully obscured by the system UI elements. This value does not change
546 * based on the visibility state of those elements; for example, if the status bar is
547 * normally shown, but temporarily hidden, the stable inset will still provide the inset
548 * associated with the status bar being shown.</p>
549 *
550 * @return The stable insets
Adam Powellf4a39412014-05-05 17:29:17 -0700551 */
Adrian Roos60f59292018-08-24 16:29:06 +0200552 @NonNull
553 public Insets getStableInsets() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100554 return getInsets(mTypeMaxInsetsMap, compatSystemInsets());
Adam Powell50d7bfd2014-02-03 10:16:49 -0800555 }
556
Adrian Roosfa104232014-06-20 16:10:14 -0700557 /**
Dianne Hackborn067e5f62014-09-07 23:14:30 -0700558 * Returns the top stable inset in pixels.
559 *
560 * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
561 * partially or fully obscured by the system UI elements. This value does not change
562 * based on the visibility state of those elements; for example, if the status bar is
563 * normally shown, but temporarily hidden, the stable inset will still provide the inset
564 * associated with the status bar being shown.</p>
565 *
566 * @return The top stable inset
Adrian Roosfa104232014-06-20 16:10:14 -0700567 */
568 public int getStableInsetTop() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100569 return getStableInsets().top;
Adrian Roosfa104232014-06-20 16:10:14 -0700570 }
571
572 /**
Dianne Hackborn067e5f62014-09-07 23:14:30 -0700573 * Returns the left stable inset in pixels.
574 *
575 * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
576 * partially or fully obscured by the system UI elements. This value does not change
577 * based on the visibility state of those elements; for example, if the status bar is
578 * normally shown, but temporarily hidden, the stable inset will still provide the inset
579 * associated with the status bar being shown.</p>
580 *
581 * @return The left stable inset
Adrian Roosfa104232014-06-20 16:10:14 -0700582 */
583 public int getStableInsetLeft() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100584 return getStableInsets().left;
Adrian Roosfa104232014-06-20 16:10:14 -0700585 }
586
587 /**
Dianne Hackborn067e5f62014-09-07 23:14:30 -0700588 * Returns the right stable inset in pixels.
589 *
590 * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
591 * partially or fully obscured by the system UI elements. This value does not change
592 * based on the visibility state of those elements; for example, if the status bar is
593 * normally shown, but temporarily hidden, the stable inset will still provide the inset
594 * associated with the status bar being shown.</p>
595 *
596 * @return The right stable inset
Adrian Roosfa104232014-06-20 16:10:14 -0700597 */
598 public int getStableInsetRight() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100599 return getStableInsets().right;
Adrian Roosfa104232014-06-20 16:10:14 -0700600 }
601
602 /**
Dianne Hackborn067e5f62014-09-07 23:14:30 -0700603 * Returns the bottom stable inset in pixels.
604 *
605 * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
606 * partially or fully obscured by the system UI elements. This value does not change
607 * based on the visibility state of those elements; for example, if the status bar is
608 * normally shown, but temporarily hidden, the stable inset will still provide the inset
609 * associated with the status bar being shown.</p>
610 *
611 * @return The bottom stable inset
Adrian Roosfa104232014-06-20 16:10:14 -0700612 */
613 public int getStableInsetBottom() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100614 return getStableInsets().bottom;
Adrian Roosfa104232014-06-20 16:10:14 -0700615 }
616
617 /**
Dianne Hackborn067e5f62014-09-07 23:14:30 -0700618 * Returns true if this WindowInsets has nonzero stable insets.
619 *
620 * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
621 * partially or fully obscured by the system UI elements. This value does not change
622 * based on the visibility state of those elements; for example, if the status bar is
623 * normally shown, but temporarily hidden, the stable inset will still provide the inset
624 * associated with the status bar being shown.</p>
625 *
626 * @return true if any of the stable inset values are nonzero
Adrian Roosfa104232014-06-20 16:10:14 -0700627 */
628 public boolean hasStableInsets() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100629 return !getStableInsets().equals(Insets.NONE);
Adrian Roosfa104232014-06-20 16:10:14 -0700630 }
631
632 /**
Dianne Hackborn067e5f62014-09-07 23:14:30 -0700633 * Returns a copy of this WindowInsets with the stable insets fully consumed.
634 *
635 * @return A modified copy of this WindowInsets
Adrian Roosfa104232014-06-20 16:10:14 -0700636 */
Adrian Roos9272cfe2018-09-28 13:35:07 +0200637 @NonNull
Adrian Roosfa104232014-06-20 16:10:14 -0700638 public WindowInsets consumeStableInsets() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100639 return new WindowInsets(mSystemWindowInsetsConsumed ? null : mTypeInsetsMap, null,
Jorim Jaggi90990792019-01-21 23:00:20 +0100640 mTypeVisibilityMap, mIsRound, mAlwaysConsumeNavBar,
Adrian Roos60f59292018-08-24 16:29:06 +0200641 displayCutoutCopyConstructorArgument(this));
Adrian Roosfa104232014-06-20 16:10:14 -0700642 }
643
Jorim Jaggi0ffd49c2016-02-12 15:04:21 -0800644 /**
645 * @hide
646 */
647 public boolean shouldAlwaysConsumeNavBar() {
648 return mAlwaysConsumeNavBar;
649 }
650
Adam Powell50d7bfd2014-02-03 10:16:49 -0800651 @Override
652 public String toString() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100653 return "WindowInsets{systemWindowInsets=" + getSystemWindowInsets()
654 + " stableInsets=" + getStableInsets()
Adrian Roosd07bafd2017-12-11 17:30:56 +0100655 + (mDisplayCutout != null ? " cutout=" + mDisplayCutout : "")
Adrian Roosd4970af2017-11-10 15:48:01 +0100656 + (isRound() ? " round" : "")
657 + "}";
Adam Powell50d7bfd2014-02-03 10:16:49 -0800658 }
Adrian Roosf7b74262017-11-22 14:21:01 +0100659
660 /**
661 * Returns a copy of this instance inset in the given directions.
662 *
663 * @see #inset(int, int, int, int)
Adrian Roos60f59292018-08-24 16:29:06 +0200664 * @deprecated use {@link #inset(Insets)}
Adrian Roosf7b74262017-11-22 14:21:01 +0100665 * @hide
666 */
Adrian Roos60f59292018-08-24 16:29:06 +0200667 @Deprecated
Adrian Roos9272cfe2018-09-28 13:35:07 +0200668 @NonNull
Adrian Roosf7b74262017-11-22 14:21:01 +0100669 public WindowInsets inset(Rect r) {
670 return inset(r.left, r.top, r.right, r.bottom);
671 }
672
673 /**
674 * Returns a copy of this instance inset in the given directions.
675 *
Adrian Roos60f59292018-08-24 16:29:06 +0200676 * @see #inset(int, int, int, int)
677 * @hide
678 */
Adrian Roos9272cfe2018-09-28 13:35:07 +0200679 @NonNull
Adrian Roos60f59292018-08-24 16:29:06 +0200680 public WindowInsets inset(Insets insets) {
681 return inset(insets.left, insets.top, insets.right, insets.bottom);
682 }
683
684 /**
685 * Returns a copy of this instance inset in the given directions.
686 *
Adrian Roosf7b74262017-11-22 14:21:01 +0100687 * This is intended for dispatching insets to areas of the window that are smaller than the
688 * current area.
689 *
690 * <p>Example:
691 * <pre>
692 * childView.dispatchApplyWindowInsets(insets.inset(
693 * childMarginLeft, childMarginTop, childMarginBottom, childMarginRight));
694 * </pre>
695 *
696 * @param left the amount of insets to remove from the left. Must be non-negative.
697 * @param top the amount of insets to remove from the top. Must be non-negative.
698 * @param right the amount of insets to remove from the right. Must be non-negative.
699 * @param bottom the amount of insets to remove from the bottom. Must be non-negative.
700 *
701 * @return the inset insets
Adrian Roosf7b74262017-11-22 14:21:01 +0100702 */
Adrian Roosb57bfe02018-07-25 18:28:32 +0200703 @NonNull
Adrian Roos9e860352019-02-26 18:28:41 +0100704 public WindowInsets inset(@IntRange(from = 0) int left, @IntRange(from = 0) int top,
705 @IntRange(from = 0) int right, @IntRange(from = 0) int bottom) {
Adrian Roosf7b74262017-11-22 14:21:01 +0100706 Preconditions.checkArgumentNonnegative(left);
707 Preconditions.checkArgumentNonnegative(top);
708 Preconditions.checkArgumentNonnegative(right);
709 Preconditions.checkArgumentNonnegative(bottom);
710
Adrian Roos60f59292018-08-24 16:29:06 +0200711 return new WindowInsets(
Jorim Jaggi297985a2018-11-30 17:24:58 +0100712 mSystemWindowInsetsConsumed
713 ? null
714 : insetInsets(mTypeInsetsMap, left, top, right, bottom),
715 mStableInsetsConsumed
716 ? null
717 : insetInsets(mTypeMaxInsetsMap, left, top, right, bottom),
Jorim Jaggi90990792019-01-21 23:00:20 +0100718 mTypeVisibilityMap,
Adrian Roos60f59292018-08-24 16:29:06 +0200719 mIsRound, mAlwaysConsumeNavBar,
720 mDisplayCutoutConsumed
Jorim Jaggi297985a2018-11-30 17:24:58 +0100721 ? null
722 : mDisplayCutout == null
Adrian Roos60f59292018-08-24 16:29:06 +0200723 ? DisplayCutout.NO_CUTOUT
724 : mDisplayCutout.inset(left, top, right, bottom));
Adrian Roosf7b74262017-11-22 14:21:01 +0100725 }
726
727 @Override
728 public boolean equals(Object o) {
729 if (this == o) return true;
730 if (o == null || !(o instanceof WindowInsets)) return false;
731 WindowInsets that = (WindowInsets) o;
Jorim Jaggi297985a2018-11-30 17:24:58 +0100732
Adrian Roosf7b74262017-11-22 14:21:01 +0100733 return mIsRound == that.mIsRound
734 && mAlwaysConsumeNavBar == that.mAlwaysConsumeNavBar
735 && mSystemWindowInsetsConsumed == that.mSystemWindowInsetsConsumed
Adrian Roosf7b74262017-11-22 14:21:01 +0100736 && mStableInsetsConsumed == that.mStableInsetsConsumed
737 && mDisplayCutoutConsumed == that.mDisplayCutoutConsumed
Jorim Jaggi297985a2018-11-30 17:24:58 +0100738 && Arrays.equals(mTypeInsetsMap, that.mTypeInsetsMap)
739 && Arrays.equals(mTypeMaxInsetsMap, that.mTypeMaxInsetsMap)
Jorim Jaggi90990792019-01-21 23:00:20 +0100740 && Arrays.equals(mTypeVisibilityMap, that.mTypeVisibilityMap)
Adrian Roosf7b74262017-11-22 14:21:01 +0100741 && Objects.equals(mDisplayCutout, that.mDisplayCutout);
742 }
743
744 @Override
745 public int hashCode() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100746 return Objects.hash(Arrays.hashCode(mTypeInsetsMap), Arrays.hashCode(mTypeMaxInsetsMap),
Jorim Jaggi90990792019-01-21 23:00:20 +0100747 Arrays.hashCode(mTypeVisibilityMap), mIsRound, mDisplayCutout, mAlwaysConsumeNavBar,
748 mSystemWindowInsetsConsumed, mStableInsetsConsumed, mDisplayCutoutConsumed);
Jorim Jaggi297985a2018-11-30 17:24:58 +0100749 }
750
751
752 /**
753 * Insets every inset in {@code typeInsetsMap} by the specified left, top, right, bottom.
754 *
755 * @return {@code typeInsetsMap} if no inset was modified; a copy of the map with the modified
756 * insets otherwise.
757 */
758 private static Insets[] insetInsets(
759 Insets[] typeInsetsMap, int left, int top, int right, int bottom) {
760 boolean cloned = false;
761 for (int i = 0; i < SIZE; i++) {
762 Insets insets = typeInsetsMap[i];
763 if (insets == null) {
764 continue;
765 }
766 Insets insetInsets = insetInsets(insets, left, top, right, bottom);
767 if (insetInsets != insets) {
768 if (!cloned) {
769 typeInsetsMap = typeInsetsMap.clone();
770 cloned = true;
771 }
772 typeInsetsMap[i] = insetInsets;
773 }
774 }
775 return typeInsetsMap;
Adrian Roosf7b74262017-11-22 14:21:01 +0100776 }
777
Adrian Roos60f59292018-08-24 16:29:06 +0200778 private static Insets insetInsets(Insets insets, int left, int top, int right, int bottom) {
Adrian Roosf7b74262017-11-22 14:21:01 +0100779 int newLeft = Math.max(0, insets.left - left);
780 int newTop = Math.max(0, insets.top - top);
781 int newRight = Math.max(0, insets.right - right);
782 int newBottom = Math.max(0, insets.bottom - bottom);
783 if (newLeft == left && newTop == top && newRight == right && newBottom == bottom) {
784 return insets;
785 }
Adrian Roos60f59292018-08-24 16:29:06 +0200786 return Insets.of(newLeft, newTop, newRight, newBottom);
Adrian Roosf7b74262017-11-22 14:21:01 +0100787 }
788
789 /**
790 * @return whether system window insets have been consumed.
791 */
792 boolean isSystemWindowInsetsConsumed() {
793 return mSystemWindowInsetsConsumed;
794 }
Adrian Roosf35eb022018-07-25 18:29:10 +0200795
796 /**
797 * Builder for WindowInsets.
798 */
Adrian Roos9e860352019-02-26 18:28:41 +0100799 public static final class Builder {
Adrian Roosf35eb022018-07-25 18:29:10 +0200800
Jorim Jaggi297985a2018-11-30 17:24:58 +0100801 private final Insets[] mTypeInsetsMap;
802 private final Insets[] mTypeMaxInsetsMap;
Jorim Jaggi90990792019-01-21 23:00:20 +0100803 private final boolean[] mTypeVisibilityMap;
Jorim Jaggi297985a2018-11-30 17:24:58 +0100804 private boolean mSystemInsetsConsumed = true;
805 private boolean mStableInsetsConsumed = true;
806
Adrian Roosf35eb022018-07-25 18:29:10 +0200807 private DisplayCutout mDisplayCutout;
808
Adrian Roosf35eb022018-07-25 18:29:10 +0200809 private boolean mIsRound;
810 private boolean mAlwaysConsumeNavBar;
811
812 /**
813 * Creates a builder where all insets are initially consumed.
814 */
815 public Builder() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100816 mTypeInsetsMap = new Insets[SIZE];
817 mTypeMaxInsetsMap = new Insets[SIZE];
Jorim Jaggi90990792019-01-21 23:00:20 +0100818 mTypeVisibilityMap = new boolean[SIZE];
Adrian Roosf35eb022018-07-25 18:29:10 +0200819 }
820
821 /**
822 * Creates a builder where all insets are initialized from {@link WindowInsets}.
823 *
824 * @param insets the instance to initialize from.
825 */
Adrian Roos9e860352019-02-26 18:28:41 +0100826 public Builder(@NonNull WindowInsets insets) {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100827 mTypeInsetsMap = insets.mTypeInsetsMap.clone();
828 mTypeMaxInsetsMap = insets.mTypeMaxInsetsMap.clone();
Jorim Jaggi90990792019-01-21 23:00:20 +0100829 mTypeVisibilityMap = insets.mTypeVisibilityMap.clone();
Jorim Jaggi297985a2018-11-30 17:24:58 +0100830 mSystemInsetsConsumed = insets.mSystemWindowInsetsConsumed;
831 mStableInsetsConsumed = insets.mStableInsetsConsumed;
Adrian Roosf35eb022018-07-25 18:29:10 +0200832 mDisplayCutout = displayCutoutCopyConstructorArgument(insets);
Adrian Roosf35eb022018-07-25 18:29:10 +0200833 mIsRound = insets.mIsRound;
834 mAlwaysConsumeNavBar = insets.mAlwaysConsumeNavBar;
835 }
836
837 /**
838 * Sets system window insets in pixels.
839 *
840 * <p>The system window inset represents the area of a full-screen window that is
841 * partially or fully obscured by the status bar, navigation bar, IME or other system
842 * windows.</p>
843 *
844 * @see #getSystemWindowInsets()
845 * @return itself
846 */
847 @NonNull
848 public Builder setSystemWindowInsets(@NonNull Insets systemWindowInsets) {
849 Preconditions.checkNotNull(systemWindowInsets);
Jorim Jaggi297985a2018-11-30 17:24:58 +0100850 assignCompatInsets(mTypeInsetsMap, systemWindowInsets.toRect());
851 mSystemInsetsConsumed = false;
Adrian Roosf35eb022018-07-25 18:29:10 +0200852 return this;
853 }
854
855 /**
Jorim Jaggibcf99ff2018-12-03 18:04:26 +0100856 * Sets the insets of a specific window type in pixels.
857 *
858 * <p>The insets represents the area of a a window that is partially or fully obscured by
859 * the system windows identified by {@code typeMask}.
860 * </p>
861 *
862 * @see #getInsets(int)
863 *
864 * @param typeMask The bitmask of {@link InsetType} to set the insets for.
865 * @param insets The insets to set.
866 *
867 * @return itself
868 * @hide pending unhide
869 */
870 @NonNull
871 public Builder setInsets(@InsetType int typeMask, @NonNull Insets insets) {
872 Preconditions.checkNotNull(insets);
873 WindowInsets.setInsets(mTypeInsetsMap, typeMask, insets);
874 mSystemInsetsConsumed = false;
875 return this;
876 }
877
878 /**
879 * Sets the maximum amount of insets a specific window type in pixels.
880 *
881 * <p>The maximum insets represents the area of a a window that that <b>may</b> be partially
882 * or fully obscured by the system windows identified by {@code typeMask}. This value does
883 * not change based on the visibility state of those elements. for example, if the status
884 * bar is normally shown, but temporarily hidden, the maximum inset will still provide the
885 * inset associated with the status bar being shown.</p>
886 *
887 * @see #getMaxInsets(int)
888 *
889 * @param typeMask The bitmask of {@link InsetType} to set the insets for.
890 * @param insets The insets to set.
891 *
892 * @return itself
893 *
894 * @throws IllegalArgumentException If {@code typeMask} contains {@link Type#ime()}. Maximum
895 * insets are not available for this type as the height of
896 * the IME is dynamic depending on the {@link EditorInfo}
897 * of the currently focused view, as well as the UI
898 * state of the IME.
899 * @hide pending unhide
900 */
901 @NonNull
902 public Builder setMaxInsets(@InsetType int typeMask, @NonNull Insets insets)
903 throws IllegalArgumentException{
904 if (typeMask == IME) {
905 throw new IllegalArgumentException("Maximum inset not available for IME");
906 }
907 Preconditions.checkNotNull(insets);
908 WindowInsets.setInsets(mTypeMaxInsetsMap, typeMask, insets);
909 mStableInsetsConsumed = false;
910 return this;
911 }
912
913 /**
Jorim Jaggi90990792019-01-21 23:00:20 +0100914 * Sets whether windows that can cause insets are currently visible on screen.
915 *
916 *
917 * @see #isVisible(int)
918 *
919 * @param typeMask The bitmask of {@link InsetType} to set the visibility for.
920 * @param visible Whether to mark the windows as visible or not.
921 *
922 * @return itself
923 * @hide pending unhide
924 */
925 @NonNull
926 public Builder setVisible(@InsetType int typeMask, boolean visible) {
927 for (int i = FIRST; i <= LAST; i = i << 1) {
928 if ((typeMask & i) == 0) {
929 continue;
930 }
931 mTypeVisibilityMap[indexOf(i)] = visible;
932 }
933 return this;
934 }
935
936 /**
Adrian Roosf35eb022018-07-25 18:29:10 +0200937 * Sets the stable insets in pixels.
938 *
939 * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
940 * partially or fully obscured by the system UI elements. This value does not change
941 * based on the visibility state of those elements; for example, if the status bar is
942 * normally shown, but temporarily hidden, the stable inset will still provide the inset
943 * associated with the status bar being shown.</p>
944 *
945 * @see #getStableInsets()
946 * @return itself
947 */
948 @NonNull
949 public Builder setStableInsets(@NonNull Insets stableInsets) {
950 Preconditions.checkNotNull(stableInsets);
Jorim Jaggi9b30a742019-01-21 15:21:44 +0100951 assignCompatInsets(mTypeMaxInsetsMap, stableInsets.toRect());
Jorim Jaggi297985a2018-11-30 17:24:58 +0100952 mStableInsetsConsumed = false;
Adrian Roosf35eb022018-07-25 18:29:10 +0200953 return this;
954 }
955
956 /**
957 * Sets the display cutout.
958 *
959 * @see #getDisplayCutout()
960 * @param displayCutout the display cutout or null if there is none
961 * @return itself
962 */
963 @NonNull
964 public Builder setDisplayCutout(@Nullable DisplayCutout displayCutout) {
965 mDisplayCutout = displayCutout != null ? displayCutout : DisplayCutout.NO_CUTOUT;
966 return this;
967 }
968
969 /** @hide */
970 @NonNull
Adrian Roosf35eb022018-07-25 18:29:10 +0200971 public Builder setRound(boolean round) {
972 mIsRound = round;
973 return this;
974 }
975
976 /** @hide */
977 @NonNull
978 public Builder setAlwaysConsumeNavBar(boolean alwaysConsumeNavBar) {
979 mAlwaysConsumeNavBar = alwaysConsumeNavBar;
980 return this;
981 }
982
983 /**
984 * Builds a {@link WindowInsets} instance.
985 *
986 * @return the {@link WindowInsets} instance.
987 */
988 @NonNull
989 public WindowInsets build() {
Jorim Jaggi297985a2018-11-30 17:24:58 +0100990 return new WindowInsets(mSystemInsetsConsumed ? null : mTypeInsetsMap,
Jorim Jaggi90990792019-01-21 23:00:20 +0100991 mStableInsetsConsumed ? null : mTypeMaxInsetsMap, mTypeVisibilityMap,
992 mIsRound, mAlwaysConsumeNavBar, mDisplayCutout);
Adrian Roosf35eb022018-07-25 18:29:10 +0200993 }
994 }
Jorim Jaggib6030952018-10-23 18:31:52 +0200995
996 /**
997 * Class that defines different types of sources causing window insets.
998 * @hide pending unhide
999 */
1000 public static final class Type {
1001
Jorim Jaggi297985a2018-11-30 17:24:58 +01001002 static final int FIRST = 0x1;
1003 static final int TOP_BAR = FIRST;
1004
Jorim Jaggib6030952018-10-23 18:31:52 +02001005 static final int IME = 0x2;
1006 static final int SIDE_BARS = 0x4;
Jorim Jaggi297985a2018-11-30 17:24:58 +01001007
1008 static final int LAST = 0x8;
1009 static final int SIZE = 4;
1010 static final int WINDOW_DECOR = LAST;
1011
1012 static int indexOf(@InsetType int type) {
1013 switch (type) {
1014 case TOP_BAR:
1015 return 0;
1016 case IME:
1017 return 1;
1018 case SIDE_BARS:
1019 return 2;
1020 case WINDOW_DECOR:
1021 return 3;
1022 default:
1023 throw new IllegalArgumentException("type needs to be >= FIRST and <= LAST,"
1024 + " type=" + type);
1025 }
1026 }
Jorim Jaggib6030952018-10-23 18:31:52 +02001027
1028 private Type() {
1029 }
1030
1031 /** @hide */
1032 @Retention(RetentionPolicy.SOURCE)
1033 @IntDef(flag = true, value = { TOP_BAR, IME, SIDE_BARS, WINDOW_DECOR })
1034 public @interface InsetType {
1035 }
1036
1037 /**
1038 * @return An inset type representing the top bar of a window, which can be the status
1039 * bar on handheld-like devices as well as a caption bar.
1040 */
1041 public static @InsetType int topBar() {
1042 return TOP_BAR;
1043 }
1044
1045 /**
1046 * @return An inset type representing the window of an {@link InputMethod}.
1047 */
1048 public static @InsetType int ime() {
1049 return IME;
1050 }
1051
1052 /**
1053 * @return An inset type representing any system bars that are not {@link #topBar()}.
1054 */
1055 public static @InsetType int sideBars() {
1056 return SIDE_BARS;
1057 }
1058
1059 /**
1060 * @return An inset type representing decor that is being app-controlled.
1061 */
1062 public static @InsetType int windowDecor() {
1063 return WINDOW_DECOR;
1064 }
1065
1066 /**
1067 * @return All system bars. Includes {@link #topBar()} as well as {@link #sideBars()}, but
1068 * not {@link #ime()}.
1069 */
1070 public static @InsetType int systemBars() {
1071 return TOP_BAR | SIDE_BARS;
1072 }
1073
1074 /**
Jorim Jaggi297985a2018-11-30 17:24:58 +01001075 * @return Inset types representing the list of bars that traditionally were denoted as
1076 * system insets.
1077 * @hide
1078 */
1079 static @InsetType int compatSystemInsets() {
1080 return TOP_BAR | SIDE_BARS | IME;
1081 }
1082
1083 /**
Jorim Jaggib6030952018-10-23 18:31:52 +02001084 * @return All inset types combined.
1085 */
1086 public static @InsetType int all() {
1087 return 0xFFFFFFFF;
1088 }
1089 }
Adam Powell50d7bfd2014-02-03 10:16:49 -08001090}