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