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