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