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 android.graphics.Rect; 21 22 /** 23 * Describes a set of insets for window content. 24 * 25 * <p>WindowInsets are immutable and may be expanded to include more inset types in the future. 26 * To adjust insets, use one of the supplied clone methods to obtain a new WindowInsets instance 27 * with the adjusted properties.</p> 28 * 29 * @see View.OnApplyWindowInsetsListener 30 * @see View#onApplyWindowInsets(WindowInsets) 31 */ 32 public final class WindowInsets { 33 34 private Rect mSystemWindowInsets; 35 private Rect mWindowDecorInsets; 36 private Rect mStableInsets; 37 private Rect mTempRect; 38 private boolean mIsRound; 39 40 /** 41 * In multi-window we force show the navigation bar. Because we don't want that the surface size 42 * changes in this mode, we instead have a flag whether the navigation bar size should always 43 * be consumed, so the app is treated like there is no virtual navigation bar at all. 44 */ 45 private boolean mAlwaysConsumeNavBar; 46 47 private boolean mSystemWindowInsetsConsumed = false; 48 private boolean mWindowDecorInsetsConsumed = false; 49 private boolean mStableInsetsConsumed = false; 50 51 private static final Rect EMPTY_RECT = new Rect(0, 0, 0, 0); 52 53 /** 54 * Since new insets may be added in the future that existing apps couldn't 55 * know about, this fully empty constant shouldn't be made available to apps 56 * since it would allow them to inadvertently consume unknown insets by returning it. 57 * @hide 58 */ 59 public static final WindowInsets CONSUMED; 60 61 static { 62 CONSUMED = new WindowInsets(null, null, null, false, false); 63 } 64 65 /** @hide */ WindowInsets(Rect systemWindowInsets, Rect windowDecorInsets, Rect stableInsets, boolean isRound, boolean alwaysConsumeNavBar)66 public WindowInsets(Rect systemWindowInsets, Rect windowDecorInsets, Rect stableInsets, 67 boolean isRound, boolean alwaysConsumeNavBar) { 68 mSystemWindowInsetsConsumed = systemWindowInsets == null; 69 mSystemWindowInsets = mSystemWindowInsetsConsumed ? EMPTY_RECT : systemWindowInsets; 70 71 mWindowDecorInsetsConsumed = windowDecorInsets == null; 72 mWindowDecorInsets = mWindowDecorInsetsConsumed ? EMPTY_RECT : windowDecorInsets; 73 74 mStableInsetsConsumed = stableInsets == null; 75 mStableInsets = mStableInsetsConsumed ? EMPTY_RECT : stableInsets; 76 77 mIsRound = isRound; 78 mAlwaysConsumeNavBar = alwaysConsumeNavBar; 79 } 80 81 /** 82 * Construct a new WindowInsets, copying all values from a source WindowInsets. 83 * 84 * @param src Source to copy insets from 85 */ WindowInsets(WindowInsets src)86 public WindowInsets(WindowInsets src) { 87 mSystemWindowInsets = src.mSystemWindowInsets; 88 mWindowDecorInsets = src.mWindowDecorInsets; 89 mStableInsets = src.mStableInsets; 90 mSystemWindowInsetsConsumed = src.mSystemWindowInsetsConsumed; 91 mWindowDecorInsetsConsumed = src.mWindowDecorInsetsConsumed; 92 mStableInsetsConsumed = src.mStableInsetsConsumed; 93 mIsRound = src.mIsRound; 94 mAlwaysConsumeNavBar = src.mAlwaysConsumeNavBar; 95 } 96 97 /** @hide */ WindowInsets(Rect systemWindowInsets)98 public WindowInsets(Rect systemWindowInsets) { 99 this(systemWindowInsets, null, null, false, false); 100 } 101 102 /** 103 * Used to provide a safe copy of the system window insets to pass through 104 * to the existing fitSystemWindows method and other similar internals. 105 * @hide 106 */ getSystemWindowInsets()107 public Rect getSystemWindowInsets() { 108 if (mTempRect == null) { 109 mTempRect = new Rect(); 110 } 111 if (mSystemWindowInsets != null) { 112 mTempRect.set(mSystemWindowInsets); 113 } else { 114 // If there were no system window insets, this is just empty. 115 mTempRect.setEmpty(); 116 } 117 return mTempRect; 118 } 119 120 /** 121 * Returns the left system window inset in pixels. 122 * 123 * <p>The system window inset represents the area of a full-screen window that is 124 * partially or fully obscured by the status bar, navigation bar, IME or other system windows. 125 * </p> 126 * 127 * @return The left system window inset 128 */ getSystemWindowInsetLeft()129 public int getSystemWindowInsetLeft() { 130 return mSystemWindowInsets.left; 131 } 132 133 /** 134 * Returns the top system window inset in pixels. 135 * 136 * <p>The system window inset represents the area of a full-screen window that is 137 * partially or fully obscured by the status bar, navigation bar, IME or other system windows. 138 * </p> 139 * 140 * @return The top system window inset 141 */ getSystemWindowInsetTop()142 public int getSystemWindowInsetTop() { 143 return mSystemWindowInsets.top; 144 } 145 146 /** 147 * Returns the right system window inset in pixels. 148 * 149 * <p>The system window inset represents the area of a full-screen window that is 150 * partially or fully obscured by the status bar, navigation bar, IME or other system windows. 151 * </p> 152 * 153 * @return The right system window inset 154 */ getSystemWindowInsetRight()155 public int getSystemWindowInsetRight() { 156 return mSystemWindowInsets.right; 157 } 158 159 /** 160 * Returns the bottom system window inset in pixels. 161 * 162 * <p>The system window inset represents the area of a full-screen window that is 163 * partially or fully obscured by the status bar, navigation bar, IME or other system windows. 164 * </p> 165 * 166 * @return The bottom system window inset 167 */ getSystemWindowInsetBottom()168 public int getSystemWindowInsetBottom() { 169 return mSystemWindowInsets.bottom; 170 } 171 172 /** 173 * Returns the left window decor inset in pixels. 174 * 175 * <p>The window decor inset represents the area of the window content area that is 176 * partially or fully obscured by decorations within the window provided by the framework. 177 * This can include action bars, title bars, toolbars, etc.</p> 178 * 179 * @return The left window decor inset 180 * @hide pending API 181 */ getWindowDecorInsetLeft()182 public int getWindowDecorInsetLeft() { 183 return mWindowDecorInsets.left; 184 } 185 186 /** 187 * Returns the top window decor inset in pixels. 188 * 189 * <p>The window decor inset represents the area of the window content area that is 190 * partially or fully obscured by decorations within the window provided by the framework. 191 * This can include action bars, title bars, toolbars, etc.</p> 192 * 193 * @return The top window decor inset 194 * @hide pending API 195 */ getWindowDecorInsetTop()196 public int getWindowDecorInsetTop() { 197 return mWindowDecorInsets.top; 198 } 199 200 /** 201 * Returns the right window decor inset in pixels. 202 * 203 * <p>The window decor inset represents the area of the window content area that is 204 * partially or fully obscured by decorations within the window provided by the framework. 205 * This can include action bars, title bars, toolbars, etc.</p> 206 * 207 * @return The right window decor inset 208 * @hide pending API 209 */ getWindowDecorInsetRight()210 public int getWindowDecorInsetRight() { 211 return mWindowDecorInsets.right; 212 } 213 214 /** 215 * Returns the bottom window decor inset in pixels. 216 * 217 * <p>The window decor inset represents the area of the window content area that is 218 * partially or fully obscured by decorations within the window provided by the framework. 219 * This can include action bars, title bars, toolbars, etc.</p> 220 * 221 * @return The bottom window decor inset 222 * @hide pending API 223 */ getWindowDecorInsetBottom()224 public int getWindowDecorInsetBottom() { 225 return mWindowDecorInsets.bottom; 226 } 227 228 /** 229 * Returns true if this WindowInsets has nonzero system window insets. 230 * 231 * <p>The system window inset represents the area of a full-screen window that is 232 * partially or fully obscured by the status bar, navigation bar, IME or other system windows. 233 * </p> 234 * 235 * @return true if any of the system window inset values are nonzero 236 */ hasSystemWindowInsets()237 public boolean hasSystemWindowInsets() { 238 return mSystemWindowInsets.left != 0 || mSystemWindowInsets.top != 0 || 239 mSystemWindowInsets.right != 0 || mSystemWindowInsets.bottom != 0; 240 } 241 242 /** 243 * Returns true if this WindowInsets has nonzero window decor insets. 244 * 245 * <p>The window decor inset represents the area of the window content area that is 246 * partially or fully obscured by decorations within the window provided by the framework. 247 * This can include action bars, title bars, toolbars, etc.</p> 248 * 249 * @return true if any of the window decor inset values are nonzero 250 * @hide pending API 251 */ hasWindowDecorInsets()252 public boolean hasWindowDecorInsets() { 253 return mWindowDecorInsets.left != 0 || mWindowDecorInsets.top != 0 || 254 mWindowDecorInsets.right != 0 || mWindowDecorInsets.bottom != 0; 255 } 256 257 /** 258 * Returns true if this WindowInsets has any nonzero insets. 259 * 260 * @return true if any inset values are nonzero 261 */ hasInsets()262 public boolean hasInsets() { 263 return hasSystemWindowInsets() || hasWindowDecorInsets() || hasStableInsets(); 264 } 265 266 /** 267 * Check if these insets have been fully consumed. 268 * 269 * <p>Insets are considered "consumed" if the applicable <code>consume*</code> methods 270 * have been called such that all insets have been set to zero. This affects propagation of 271 * insets through the view hierarchy; insets that have not been fully consumed will continue 272 * to propagate down to child views.</p> 273 * 274 * <p>The result of this method is equivalent to the return value of 275 * {@link View#fitSystemWindows(android.graphics.Rect)}.</p> 276 * 277 * @return true if the insets have been fully consumed. 278 */ isConsumed()279 public boolean isConsumed() { 280 return mSystemWindowInsetsConsumed && mWindowDecorInsetsConsumed && mStableInsetsConsumed; 281 } 282 283 /** 284 * Returns true if the associated window has a round shape. 285 * 286 * <p>A round window's left, top, right and bottom edges reach all the way to the 287 * associated edges of the window but the corners may not be visible. Views responding 288 * to round insets should take care to not lay out critical elements within the corners 289 * where they may not be accessible.</p> 290 * 291 * @return True if the window is round 292 */ isRound()293 public boolean isRound() { 294 return mIsRound; 295 } 296 297 /** 298 * Returns a copy of this WindowInsets with the system window insets fully consumed. 299 * 300 * @return A modified copy of this WindowInsets 301 */ consumeSystemWindowInsets()302 public WindowInsets consumeSystemWindowInsets() { 303 final WindowInsets result = new WindowInsets(this); 304 result.mSystemWindowInsets = EMPTY_RECT; 305 result.mSystemWindowInsetsConsumed = true; 306 return result; 307 } 308 309 /** 310 * Returns a copy of this WindowInsets with selected system window insets fully consumed. 311 * 312 * @param left true to consume the left system window inset 313 * @param top true to consume the top system window inset 314 * @param right true to consume the right system window inset 315 * @param bottom true to consume the bottom system window inset 316 * @return A modified copy of this WindowInsets 317 * @hide pending API 318 */ consumeSystemWindowInsets(boolean left, boolean top, boolean right, boolean bottom)319 public WindowInsets consumeSystemWindowInsets(boolean left, boolean top, 320 boolean right, boolean bottom) { 321 if (left || top || right || bottom) { 322 final WindowInsets result = new WindowInsets(this); 323 result.mSystemWindowInsets = new Rect( 324 left ? 0 : mSystemWindowInsets.left, 325 top ? 0 : mSystemWindowInsets.top, 326 right ? 0 : mSystemWindowInsets.right, 327 bottom ? 0 : mSystemWindowInsets.bottom); 328 return result; 329 } 330 return this; 331 } 332 333 /** 334 * Returns a copy of this WindowInsets with selected system window insets replaced 335 * with new values. 336 * 337 * @param left New left inset in pixels 338 * @param top New top inset in pixels 339 * @param right New right inset in pixels 340 * @param bottom New bottom inset in pixels 341 * @return A modified copy of this WindowInsets 342 */ replaceSystemWindowInsets(int left, int top, int right, int bottom)343 public WindowInsets replaceSystemWindowInsets(int left, int top, 344 int right, int bottom) { 345 final WindowInsets result = new WindowInsets(this); 346 result.mSystemWindowInsets = new Rect(left, top, right, bottom); 347 return result; 348 } 349 350 /** 351 * Returns a copy of this WindowInsets with selected system window insets replaced 352 * with new values. 353 * 354 * @param systemWindowInsets New system window insets. Each field is the inset in pixels 355 * for that edge 356 * @return A modified copy of this WindowInsets 357 */ replaceSystemWindowInsets(Rect systemWindowInsets)358 public WindowInsets replaceSystemWindowInsets(Rect systemWindowInsets) { 359 final WindowInsets result = new WindowInsets(this); 360 result.mSystemWindowInsets = new Rect(systemWindowInsets); 361 return result; 362 } 363 364 /** 365 * @hide 366 */ consumeWindowDecorInsets()367 public WindowInsets consumeWindowDecorInsets() { 368 final WindowInsets result = new WindowInsets(this); 369 result.mWindowDecorInsets.set(0, 0, 0, 0); 370 result.mWindowDecorInsetsConsumed = true; 371 return result; 372 } 373 374 /** 375 * @hide 376 */ consumeWindowDecorInsets(boolean left, boolean top, boolean right, boolean bottom)377 public WindowInsets consumeWindowDecorInsets(boolean left, boolean top, 378 boolean right, boolean bottom) { 379 if (left || top || right || bottom) { 380 final WindowInsets result = new WindowInsets(this); 381 result.mWindowDecorInsets = new Rect(left ? 0 : mWindowDecorInsets.left, 382 top ? 0 : mWindowDecorInsets.top, 383 right ? 0 : mWindowDecorInsets.right, 384 bottom ? 0 : mWindowDecorInsets.bottom); 385 return result; 386 } 387 return this; 388 } 389 390 /** 391 * @hide 392 */ replaceWindowDecorInsets(int left, int top, int right, int bottom)393 public WindowInsets replaceWindowDecorInsets(int left, int top, int right, int bottom) { 394 final WindowInsets result = new WindowInsets(this); 395 result.mWindowDecorInsets = new Rect(left, top, right, bottom); 396 return result; 397 } 398 399 /** 400 * Returns the top stable inset in pixels. 401 * 402 * <p>The stable inset represents the area of a full-screen window that <b>may</b> be 403 * partially or fully obscured by the system UI elements. This value does not change 404 * based on the visibility state of those elements; for example, if the status bar is 405 * normally shown, but temporarily hidden, the stable inset will still provide the inset 406 * associated with the status bar being shown.</p> 407 * 408 * @return The top stable inset 409 */ getStableInsetTop()410 public int getStableInsetTop() { 411 return mStableInsets.top; 412 } 413 414 /** 415 * Returns the left stable inset in pixels. 416 * 417 * <p>The stable inset represents the area of a full-screen window that <b>may</b> be 418 * partially or fully obscured by the system UI elements. This value does not change 419 * based on the visibility state of those elements; for example, if the status bar is 420 * normally shown, but temporarily hidden, the stable inset will still provide the inset 421 * associated with the status bar being shown.</p> 422 * 423 * @return The left stable inset 424 */ getStableInsetLeft()425 public int getStableInsetLeft() { 426 return mStableInsets.left; 427 } 428 429 /** 430 * Returns the right stable inset in pixels. 431 * 432 * <p>The stable inset represents the area of a full-screen window that <b>may</b> be 433 * partially or fully obscured by the system UI elements. This value does not change 434 * based on the visibility state of those elements; for example, if the status bar is 435 * normally shown, but temporarily hidden, the stable inset will still provide the inset 436 * associated with the status bar being shown.</p> 437 * 438 * @return The right stable inset 439 */ getStableInsetRight()440 public int getStableInsetRight() { 441 return mStableInsets.right; 442 } 443 444 /** 445 * Returns the bottom stable inset in pixels. 446 * 447 * <p>The stable inset represents the area of a full-screen window that <b>may</b> be 448 * partially or fully obscured by the system UI elements. This value does not change 449 * based on the visibility state of those elements; for example, if the status bar is 450 * normally shown, but temporarily hidden, the stable inset will still provide the inset 451 * associated with the status bar being shown.</p> 452 * 453 * @return The bottom stable inset 454 */ getStableInsetBottom()455 public int getStableInsetBottom() { 456 return mStableInsets.bottom; 457 } 458 459 /** 460 * Returns true if this WindowInsets has nonzero stable insets. 461 * 462 * <p>The stable inset represents the area of a full-screen window that <b>may</b> be 463 * partially or fully obscured by the system UI elements. This value does not change 464 * based on the visibility state of those elements; for example, if the status bar is 465 * normally shown, but temporarily hidden, the stable inset will still provide the inset 466 * associated with the status bar being shown.</p> 467 * 468 * @return true if any of the stable inset values are nonzero 469 */ hasStableInsets()470 public boolean hasStableInsets() { 471 return mStableInsets.top != 0 || mStableInsets.left != 0 || mStableInsets.right != 0 472 || mStableInsets.bottom != 0; 473 } 474 475 /** 476 * Returns a copy of this WindowInsets with the stable insets fully consumed. 477 * 478 * @return A modified copy of this WindowInsets 479 */ consumeStableInsets()480 public WindowInsets consumeStableInsets() { 481 final WindowInsets result = new WindowInsets(this); 482 result.mStableInsets = EMPTY_RECT; 483 result.mStableInsetsConsumed = true; 484 return result; 485 } 486 487 /** 488 * @hide 489 */ shouldAlwaysConsumeNavBar()490 public boolean shouldAlwaysConsumeNavBar() { 491 return mAlwaysConsumeNavBar; 492 } 493 494 @Override toString()495 public String toString() { 496 return "WindowInsets{systemWindowInsets=" + mSystemWindowInsets 497 + " windowDecorInsets=" + mWindowDecorInsets 498 + " stableInsets=" + mStableInsets + 499 (isRound() ? " round}" : "}"); 500 } 501 } 502