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.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 */
     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      */
     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 */
     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      */
     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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    253     public boolean hasInsets() {
    254         return hasSystemWindowInsets() || hasWindowDecorInsets();
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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
    479     public String toString() {
    480         return "WindowInsets{systemWindowInsets=" + mSystemWindowInsets
    481                 + " windowDecorInsets=" + mWindowDecorInsets
    482                 + " stableInsets=" + mStableInsets +
    483                 (isRound() ? " round}" : "}");
    484     }
    485 }
    486