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