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