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