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