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