Home | History | Annotate | Download | only in view
      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 */
     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      */
    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 */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    536     public boolean shouldAlwaysConsumeNavBar() {
    537         return mAlwaysConsumeNavBar;
    538     }
    539 
    540     @Override
    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      */
    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      */
    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
    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
    626     public int hashCode() {
    627         return Objects.hash(mSystemWindowInsets, mWindowDecorInsets, mStableInsets, mIsRound,
    628                 mDisplayCutout, mAlwaysConsumeNavBar, mSystemWindowInsetsConsumed,
    629                 mWindowDecorInsetsConsumed, mStableInsetsConsumed, mDisplayCutoutConsumed);
    630     }
    631 
    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      */
    646     boolean isSystemWindowInsetsConsumed() {
    647         return mSystemWindowInsetsConsumed;
    648     }
    649 }
    650