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