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.annotation.Nullable;
21 import android.graphics.Rect;
22 
23 import com.android.internal.util.Preconditions;
24 
25 import java.util.Objects;
26 
27 /**
28  * Describes a set of insets for window content.
29  *
30  * <p>WindowInsets are immutable and may be expanded to include more inset types in the future.
31  * To adjust insets, use one of the supplied clone methods to obtain a new WindowInsets instance
32  * with the adjusted properties.</p>
33  *
34  * <p>Note: Before {@link android.os.Build.VERSION_CODES#P P}, WindowInsets instances were only
35  * immutable during a single layout pass (i.e. would return the same values between
36  * {@link View#onApplyWindowInsets} and {@link View#onLayout}, but could return other values
37  * otherwise). Starting with {@link android.os.Build.VERSION_CODES#P P}, WindowInsets are
38  * always immutable and implement equality.
39  *
40  * @see View.OnApplyWindowInsetsListener
41  * @see View#onApplyWindowInsets(WindowInsets)
42  */
43 public final class WindowInsets {
44 
45     private Rect mSystemWindowInsets;
46     private Rect mWindowDecorInsets;
47     private Rect mStableInsets;
48     private Rect mTempRect;
49     private boolean mIsRound;
50     private DisplayCutout mDisplayCutout;
51 
52     /**
53      * In multi-window we force show the navigation bar. Because we don't want that the surface size
54      * changes in this mode, we instead have a flag whether the navigation bar size should always
55      * be consumed, so the app is treated like there is no virtual navigation bar at all.
56      */
57     private boolean mAlwaysConsumeNavBar;
58 
59     private boolean mSystemWindowInsetsConsumed = false;
60     private boolean mWindowDecorInsetsConsumed = false;
61     private boolean mStableInsetsConsumed = false;
62     private boolean mDisplayCutoutConsumed = false;
63 
64     private static final Rect EMPTY_RECT = new Rect(0, 0, 0, 0);
65 
66     /**
67      * Since new insets may be added in the future that existing apps couldn't
68      * know about, this fully empty constant shouldn't be made available to apps
69      * since it would allow them to inadvertently consume unknown insets by returning it.
70      * @hide
71      */
72     public static final WindowInsets CONSUMED;
73 
74     static {
75         CONSUMED = new WindowInsets(null, null, null, false, false, null);
76     }
77 
78     /** @hide */
WindowInsets(Rect systemWindowInsets, Rect windowDecorInsets, Rect stableInsets, boolean isRound, boolean alwaysConsumeNavBar, DisplayCutout displayCutout)79     public WindowInsets(Rect systemWindowInsets, Rect windowDecorInsets, Rect stableInsets,
80             boolean isRound, boolean alwaysConsumeNavBar, DisplayCutout displayCutout) {
81         mSystemWindowInsetsConsumed = systemWindowInsets == null;
82         mSystemWindowInsets = mSystemWindowInsetsConsumed
83                 ? EMPTY_RECT : new Rect(systemWindowInsets);
84 
85         mWindowDecorInsetsConsumed = windowDecorInsets == null;
86         mWindowDecorInsets = mWindowDecorInsetsConsumed ? EMPTY_RECT : new Rect(windowDecorInsets);
87 
88         mStableInsetsConsumed = stableInsets == null;
89         mStableInsets = mStableInsetsConsumed ? EMPTY_RECT : new Rect(stableInsets);
90 
91         mIsRound = isRound;
92         mAlwaysConsumeNavBar = alwaysConsumeNavBar;
93 
94         mDisplayCutoutConsumed = displayCutout == null;
95         mDisplayCutout = (mDisplayCutoutConsumed || displayCutout.isEmpty())
96                 ? null : displayCutout;
97     }
98 
99     /**
100      * Construct a new WindowInsets, copying all values from a source WindowInsets.
101      *
102      * @param src Source to copy insets from
103      */
WindowInsets(WindowInsets src)104     public WindowInsets(WindowInsets src) {
105         mSystemWindowInsets = src.mSystemWindowInsets;
106         mWindowDecorInsets = src.mWindowDecorInsets;
107         mStableInsets = src.mStableInsets;
108         mSystemWindowInsetsConsumed = src.mSystemWindowInsetsConsumed;
109         mWindowDecorInsetsConsumed = src.mWindowDecorInsetsConsumed;
110         mStableInsetsConsumed = src.mStableInsetsConsumed;
111         mIsRound = src.mIsRound;
112         mAlwaysConsumeNavBar = src.mAlwaysConsumeNavBar;
113         mDisplayCutout = src.mDisplayCutout;
114         mDisplayCutoutConsumed = src.mDisplayCutoutConsumed;
115     }
116 
117     /** @hide */
WindowInsets(Rect systemWindowInsets)118     public WindowInsets(Rect systemWindowInsets) {
119         this(systemWindowInsets, null, null, false, false, null);
120     }
121 
122     /**
123      * Used to provide a safe copy of the system window insets to pass through
124      * to the existing fitSystemWindows method and other similar internals.
125      * @hide
126      */
getSystemWindowInsets()127     public Rect getSystemWindowInsets() {
128         if (mTempRect == null) {
129             mTempRect = new Rect();
130         }
131         if (mSystemWindowInsets != null) {
132             mTempRect.set(mSystemWindowInsets);
133         } else {
134             // If there were no system window insets, this is just empty.
135             mTempRect.setEmpty();
136         }
137         return mTempRect;
138     }
139 
140     /**
141      * Returns the left system window inset in pixels.
142      *
143      * <p>The system window inset represents the area of a full-screen window that is
144      * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
145      * </p>
146      *
147      * @return The left system window inset
148      */
getSystemWindowInsetLeft()149     public int getSystemWindowInsetLeft() {
150         return mSystemWindowInsets.left;
151     }
152 
153     /**
154      * Returns the top system window inset in pixels.
155      *
156      * <p>The system window inset represents the area of a full-screen window that is
157      * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
158      * </p>
159      *
160      * @return The top system window inset
161      */
getSystemWindowInsetTop()162     public int getSystemWindowInsetTop() {
163         return mSystemWindowInsets.top;
164     }
165 
166     /**
167      * Returns the right system window inset in pixels.
168      *
169      * <p>The system window inset represents the area of a full-screen window that is
170      * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
171      * </p>
172      *
173      * @return The right system window inset
174      */
getSystemWindowInsetRight()175     public int getSystemWindowInsetRight() {
176         return mSystemWindowInsets.right;
177     }
178 
179     /**
180      * Returns the bottom system window inset in pixels.
181      *
182      * <p>The system window inset represents the area of a full-screen window that is
183      * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
184      * </p>
185      *
186      * @return The bottom system window inset
187      */
getSystemWindowInsetBottom()188     public int getSystemWindowInsetBottom() {
189         return mSystemWindowInsets.bottom;
190     }
191 
192     /**
193      * Returns the left window decor inset in pixels.
194      *
195      * <p>The window decor inset represents the area of the window content area that is
196      * partially or fully obscured by decorations within the window provided by the framework.
197      * This can include action bars, title bars, toolbars, etc.</p>
198      *
199      * @return The left window decor inset
200      * @hide pending API
201      */
getWindowDecorInsetLeft()202     public int getWindowDecorInsetLeft() {
203         return mWindowDecorInsets.left;
204     }
205 
206     /**
207      * Returns the top window decor inset in pixels.
208      *
209      * <p>The window decor inset represents the area of the window content area that is
210      * partially or fully obscured by decorations within the window provided by the framework.
211      * This can include action bars, title bars, toolbars, etc.</p>
212      *
213      * @return The top window decor inset
214      * @hide pending API
215      */
getWindowDecorInsetTop()216     public int getWindowDecorInsetTop() {
217         return mWindowDecorInsets.top;
218     }
219 
220     /**
221      * Returns the right window decor inset in pixels.
222      *
223      * <p>The window decor inset represents the area of the window content area that is
224      * partially or fully obscured by decorations within the window provided by the framework.
225      * This can include action bars, title bars, toolbars, etc.</p>
226      *
227      * @return The right window decor inset
228      * @hide pending API
229      */
getWindowDecorInsetRight()230     public int getWindowDecorInsetRight() {
231         return mWindowDecorInsets.right;
232     }
233 
234     /**
235      * Returns the bottom window decor inset in pixels.
236      *
237      * <p>The window decor inset represents the area of the window content area that is
238      * partially or fully obscured by decorations within the window provided by the framework.
239      * This can include action bars, title bars, toolbars, etc.</p>
240      *
241      * @return The bottom window decor inset
242      * @hide pending API
243      */
getWindowDecorInsetBottom()244     public int getWindowDecorInsetBottom() {
245         return mWindowDecorInsets.bottom;
246     }
247 
248     /**
249      * Returns true if this WindowInsets has nonzero system window insets.
250      *
251      * <p>The system window inset represents the area of a full-screen window that is
252      * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
253      * </p>
254      *
255      * @return true if any of the system window inset values are nonzero
256      */
hasSystemWindowInsets()257     public boolean hasSystemWindowInsets() {
258         return mSystemWindowInsets.left != 0 || mSystemWindowInsets.top != 0 ||
259                 mSystemWindowInsets.right != 0 || mSystemWindowInsets.bottom != 0;
260     }
261 
262     /**
263      * Returns true if this WindowInsets has nonzero window decor insets.
264      *
265      * <p>The window decor inset represents the area of the window content area that is
266      * partially or fully obscured by decorations within the window provided by the framework.
267      * This can include action bars, title bars, toolbars, etc.</p>
268      *
269      * @return true if any of the window decor inset values are nonzero
270      * @hide pending API
271      */
hasWindowDecorInsets()272     public boolean hasWindowDecorInsets() {
273         return mWindowDecorInsets.left != 0 || mWindowDecorInsets.top != 0 ||
274                 mWindowDecorInsets.right != 0 || mWindowDecorInsets.bottom != 0;
275     }
276 
277     /**
278      * Returns true if this WindowInsets has any nonzero insets.
279      *
280      * @return true if any inset values are nonzero
281      */
hasInsets()282     public boolean hasInsets() {
283         return hasSystemWindowInsets() || hasWindowDecorInsets() || hasStableInsets()
284                 || mDisplayCutout != null;
285     }
286 
287     /**
288      * Returns the display cutout if there is one.
289      *
290      * @return the display cutout or null if there is none
291      * @see DisplayCutout
292      */
293     @Nullable
getDisplayCutout()294     public DisplayCutout getDisplayCutout() {
295         return mDisplayCutout;
296     }
297 
298     /**
299      * Returns a copy of this WindowInsets with the cutout fully consumed.
300      *
301      * @return A modified copy of this WindowInsets
302      */
consumeDisplayCutout()303     public WindowInsets consumeDisplayCutout() {
304         final WindowInsets result = new WindowInsets(this);
305         result.mDisplayCutout = null;
306         result.mDisplayCutoutConsumed = true;
307         return result;
308     }
309 
310 
311     /**
312      * Check if these insets have been fully consumed.
313      *
314      * <p>Insets are considered "consumed" if the applicable <code>consume*</code> methods
315      * have been called such that all insets have been set to zero. This affects propagation of
316      * insets through the view hierarchy; insets that have not been fully consumed will continue
317      * to propagate down to child views.</p>
318      *
319      * <p>The result of this method is equivalent to the return value of
320      * {@link View#fitSystemWindows(android.graphics.Rect)}.</p>
321      *
322      * @return true if the insets have been fully consumed.
323      */
isConsumed()324     public boolean isConsumed() {
325         return mSystemWindowInsetsConsumed && mWindowDecorInsetsConsumed && mStableInsetsConsumed
326                 && mDisplayCutoutConsumed;
327     }
328 
329     /**
330      * Returns true if the associated window has a round shape.
331      *
332      * <p>A round window's left, top, right and bottom edges reach all the way to the
333      * associated edges of the window but the corners may not be visible. Views responding
334      * to round insets should take care to not lay out critical elements within the corners
335      * where they may not be accessible.</p>
336      *
337      * @return True if the window is round
338      */
isRound()339     public boolean isRound() {
340         return mIsRound;
341     }
342 
343     /**
344      * Returns a copy of this WindowInsets with the system window insets fully consumed.
345      *
346      * @return A modified copy of this WindowInsets
347      */
consumeSystemWindowInsets()348     public WindowInsets consumeSystemWindowInsets() {
349         final WindowInsets result = new WindowInsets(this);
350         result.mSystemWindowInsets = EMPTY_RECT;
351         result.mSystemWindowInsetsConsumed = true;
352         return result;
353     }
354 
355     /**
356      * Returns a copy of this WindowInsets with selected system window insets fully consumed.
357      *
358      * @param left true to consume the left system window inset
359      * @param top true to consume the top system window inset
360      * @param right true to consume the right system window inset
361      * @param bottom true to consume the bottom system window inset
362      * @return A modified copy of this WindowInsets
363      * @hide pending API
364      */
consumeSystemWindowInsets(boolean left, boolean top, boolean right, boolean bottom)365     public WindowInsets consumeSystemWindowInsets(boolean left, boolean top,
366             boolean right, boolean bottom) {
367         if (left || top || right || bottom) {
368             final WindowInsets result = new WindowInsets(this);
369             result.mSystemWindowInsets = new Rect(
370                     left ? 0 : mSystemWindowInsets.left,
371                     top ? 0 : mSystemWindowInsets.top,
372                     right ? 0 : mSystemWindowInsets.right,
373                     bottom ? 0 : mSystemWindowInsets.bottom);
374             return result;
375         }
376         return this;
377     }
378 
379     /**
380      * Returns a copy of this WindowInsets with selected system window insets replaced
381      * with new values.
382      *
383      * @param left New left inset in pixels
384      * @param top New top inset in pixels
385      * @param right New right inset in pixels
386      * @param bottom New bottom inset in pixels
387      * @return A modified copy of this WindowInsets
388      */
replaceSystemWindowInsets(int left, int top, int right, int bottom)389     public WindowInsets replaceSystemWindowInsets(int left, int top,
390             int right, int bottom) {
391         final WindowInsets result = new WindowInsets(this);
392         result.mSystemWindowInsets = new Rect(left, top, right, bottom);
393         return result;
394     }
395 
396     /**
397      * Returns a copy of this WindowInsets with selected system window insets replaced
398      * with new values.
399      *
400      * @param systemWindowInsets New system window insets. Each field is the inset in pixels
401      *                           for that edge
402      * @return A modified copy of this WindowInsets
403      */
replaceSystemWindowInsets(Rect systemWindowInsets)404     public WindowInsets replaceSystemWindowInsets(Rect systemWindowInsets) {
405         final WindowInsets result = new WindowInsets(this);
406         result.mSystemWindowInsets = new Rect(systemWindowInsets);
407         return result;
408     }
409 
410     /**
411      * @hide
412      */
consumeWindowDecorInsets()413     public WindowInsets consumeWindowDecorInsets() {
414         final WindowInsets result = new WindowInsets(this);
415         result.mWindowDecorInsets.set(0, 0, 0, 0);
416         result.mWindowDecorInsetsConsumed = true;
417         return result;
418     }
419 
420     /**
421      * @hide
422      */
consumeWindowDecorInsets(boolean left, boolean top, boolean right, boolean bottom)423     public WindowInsets consumeWindowDecorInsets(boolean left, boolean top,
424             boolean right, boolean bottom) {
425         if (left || top || right || bottom) {
426             final WindowInsets result = new WindowInsets(this);
427             result.mWindowDecorInsets = new Rect(left ? 0 : mWindowDecorInsets.left,
428                     top ? 0 : mWindowDecorInsets.top,
429                     right ? 0 : mWindowDecorInsets.right,
430                     bottom ? 0 : mWindowDecorInsets.bottom);
431             return result;
432         }
433         return this;
434     }
435 
436     /**
437      * @hide
438      */
replaceWindowDecorInsets(int left, int top, int right, int bottom)439     public WindowInsets replaceWindowDecorInsets(int left, int top, int right, int bottom) {
440         final WindowInsets result = new WindowInsets(this);
441         result.mWindowDecorInsets = new Rect(left, top, right, bottom);
442         return result;
443     }
444 
445     /**
446      * Returns the top stable inset in pixels.
447      *
448      * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
449      * partially or fully obscured by the system UI elements.  This value does not change
450      * based on the visibility state of those elements; for example, if the status bar is
451      * normally shown, but temporarily hidden, the stable inset will still provide the inset
452      * associated with the status bar being shown.</p>
453      *
454      * @return The top stable inset
455      */
getStableInsetTop()456     public int getStableInsetTop() {
457         return mStableInsets.top;
458     }
459 
460     /**
461      * Returns the left stable inset in pixels.
462      *
463      * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
464      * partially or fully obscured by the system UI elements.  This value does not change
465      * based on the visibility state of those elements; for example, if the status bar is
466      * normally shown, but temporarily hidden, the stable inset will still provide the inset
467      * associated with the status bar being shown.</p>
468      *
469      * @return The left stable inset
470      */
getStableInsetLeft()471     public int getStableInsetLeft() {
472         return mStableInsets.left;
473     }
474 
475     /**
476      * Returns the right stable inset in pixels.
477      *
478      * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
479      * partially or fully obscured by the system UI elements.  This value does not change
480      * based on the visibility state of those elements; for example, if the status bar is
481      * normally shown, but temporarily hidden, the stable inset will still provide the inset
482      * associated with the status bar being shown.</p>
483      *
484      * @return The right stable inset
485      */
getStableInsetRight()486     public int getStableInsetRight() {
487         return mStableInsets.right;
488     }
489 
490     /**
491      * Returns the bottom stable inset in pixels.
492      *
493      * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
494      * partially or fully obscured by the system UI elements.  This value does not change
495      * based on the visibility state of those elements; for example, if the status bar is
496      * normally shown, but temporarily hidden, the stable inset will still provide the inset
497      * associated with the status bar being shown.</p>
498      *
499      * @return The bottom stable inset
500      */
getStableInsetBottom()501     public int getStableInsetBottom() {
502         return mStableInsets.bottom;
503     }
504 
505     /**
506      * Returns true if this WindowInsets has nonzero stable insets.
507      *
508      * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
509      * partially or fully obscured by the system UI elements.  This value does not change
510      * based on the visibility state of those elements; for example, if the status bar is
511      * normally shown, but temporarily hidden, the stable inset will still provide the inset
512      * associated with the status bar being shown.</p>
513      *
514      * @return true if any of the stable inset values are nonzero
515      */
hasStableInsets()516     public boolean hasStableInsets() {
517         return mStableInsets.top != 0 || mStableInsets.left != 0 || mStableInsets.right != 0
518                 || mStableInsets.bottom != 0;
519     }
520 
521     /**
522      * Returns a copy of this WindowInsets with the stable insets fully consumed.
523      *
524      * @return A modified copy of this WindowInsets
525      */
consumeStableInsets()526     public WindowInsets consumeStableInsets() {
527         final WindowInsets result = new WindowInsets(this);
528         result.mStableInsets = EMPTY_RECT;
529         result.mStableInsetsConsumed = true;
530         return result;
531     }
532 
533     /**
534      * @hide
535      */
shouldAlwaysConsumeNavBar()536     public boolean shouldAlwaysConsumeNavBar() {
537         return mAlwaysConsumeNavBar;
538     }
539 
540     @Override
toString()541     public String toString() {
542         return "WindowInsets{systemWindowInsets=" + mSystemWindowInsets
543                 + " windowDecorInsets=" + mWindowDecorInsets
544                 + " stableInsets=" + mStableInsets
545                 + (mDisplayCutout != null ? " cutout=" + mDisplayCutout : "")
546                 + (isRound() ? " round" : "")
547                 + "}";
548     }
549 
550     /**
551      * Returns a copy of this instance inset in the given directions.
552      *
553      * @see #inset(int, int, int, int)
554      * @hide
555      */
inset(Rect r)556     public WindowInsets inset(Rect r) {
557         return inset(r.left, r.top, r.right, r.bottom);
558     }
559 
560     /**
561      * Returns a copy of this instance inset in the given directions.
562      *
563      * This is intended for dispatching insets to areas of the window that are smaller than the
564      * current area.
565      *
566      * <p>Example:
567      * <pre>
568      * childView.dispatchApplyWindowInsets(insets.inset(
569      *         childMarginLeft, childMarginTop, childMarginBottom, childMarginRight));
570      * </pre>
571      *
572      * @param left the amount of insets to remove from the left. Must be non-negative.
573      * @param top the amount of insets to remove from the top. Must be non-negative.
574      * @param right the amount of insets to remove from the right. Must be non-negative.
575      * @param bottom the amount of insets to remove from the bottom. Must be non-negative.
576      *
577      * @return the inset insets
578      *
579      * @hide pending API
580      */
inset(int left, int top, int right, int bottom)581     public WindowInsets inset(int left, int top, int right, int bottom) {
582         Preconditions.checkArgumentNonnegative(left);
583         Preconditions.checkArgumentNonnegative(top);
584         Preconditions.checkArgumentNonnegative(right);
585         Preconditions.checkArgumentNonnegative(bottom);
586 
587         WindowInsets result = new WindowInsets(this);
588         if (!result.mSystemWindowInsetsConsumed) {
589             result.mSystemWindowInsets =
590                     insetInsets(result.mSystemWindowInsets, left, top, right, bottom);
591         }
592         if (!result.mWindowDecorInsetsConsumed) {
593             result.mWindowDecorInsets =
594                     insetInsets(result.mWindowDecorInsets, left, top, right, bottom);
595         }
596         if (!result.mStableInsetsConsumed) {
597             result.mStableInsets = insetInsets(result.mStableInsets, left, top, right, bottom);
598         }
599         if (mDisplayCutout != null) {
600             result.mDisplayCutout = result.mDisplayCutout.inset(left, top, right, bottom);
601             if (result.mDisplayCutout.isEmpty()) {
602                 result.mDisplayCutout = null;
603             }
604         }
605         return result;
606     }
607 
608     @Override
equals(Object o)609     public boolean equals(Object o) {
610         if (this == o) return true;
611         if (o == null || !(o instanceof WindowInsets)) return false;
612         WindowInsets that = (WindowInsets) o;
613         return mIsRound == that.mIsRound
614                 && mAlwaysConsumeNavBar == that.mAlwaysConsumeNavBar
615                 && mSystemWindowInsetsConsumed == that.mSystemWindowInsetsConsumed
616                 && mWindowDecorInsetsConsumed == that.mWindowDecorInsetsConsumed
617                 && mStableInsetsConsumed == that.mStableInsetsConsumed
618                 && mDisplayCutoutConsumed == that.mDisplayCutoutConsumed
619                 && Objects.equals(mSystemWindowInsets, that.mSystemWindowInsets)
620                 && Objects.equals(mWindowDecorInsets, that.mWindowDecorInsets)
621                 && Objects.equals(mStableInsets, that.mStableInsets)
622                 && Objects.equals(mDisplayCutout, that.mDisplayCutout);
623     }
624 
625     @Override
hashCode()626     public int hashCode() {
627         return Objects.hash(mSystemWindowInsets, mWindowDecorInsets, mStableInsets, mIsRound,
628                 mDisplayCutout, mAlwaysConsumeNavBar, mSystemWindowInsetsConsumed,
629                 mWindowDecorInsetsConsumed, mStableInsetsConsumed, mDisplayCutoutConsumed);
630     }
631 
insetInsets(Rect insets, int left, int top, int right, int bottom)632     private static Rect insetInsets(Rect insets, int left, int top, int right, int bottom) {
633         int newLeft = Math.max(0, insets.left - left);
634         int newTop = Math.max(0, insets.top - top);
635         int newRight = Math.max(0, insets.right - right);
636         int newBottom = Math.max(0, insets.bottom - bottom);
637         if (newLeft == left && newTop == top && newRight == right && newBottom == bottom) {
638             return insets;
639         }
640         return new Rect(newLeft, newTop, newRight, newBottom);
641     }
642 
643     /**
644      * @return whether system window insets have been consumed.
645      */
isSystemWindowInsetsConsumed()646     boolean isSystemWindowInsetsConsumed() {
647         return mSystemWindowInsetsConsumed;
648     }
649 }
650