1/*
2 * Copyright (C) 2016 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
17package android.support.v4.view;
18
19import static android.os.Build.VERSION.SDK_INT;
20
21import android.graphics.Rect;
22import android.view.WindowInsets;
23
24/**
25 * Describes a set of insets for window content.
26 *
27 * <p>WindowInsetsCompats are immutable and may be expanded to include more inset types in the
28 * future. To adjust insets, use one of the supplied clone methods to obtain a new
29 * WindowInsetsCompat instance with the adjusted properties.</p>
30 */
31public class WindowInsetsCompat {
32    private final Object mInsets;
33
34    private WindowInsetsCompat(Object insets) {
35        mInsets = insets;
36    }
37
38    /**
39     * Constructs a new WindowInsetsCompat, copying all values from a source WindowInsetsCompat.
40     *
41     * @param src source from which values are copied
42     */
43    public WindowInsetsCompat(WindowInsetsCompat src) {
44        if (SDK_INT >= 20) {
45            mInsets = src == null ? null : new WindowInsets((WindowInsets) src.mInsets);
46        } else {
47            mInsets = null;
48        }
49    }
50
51    /**
52     * Returns the left system window inset in pixels.
53     *
54     * <p>The system window inset represents the area of a full-screen window that is
55     * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
56     * </p>
57     *
58     * @return The left system window inset
59     */
60    public int getSystemWindowInsetLeft() {
61        if (SDK_INT >= 20) {
62            return ((WindowInsets) mInsets).getSystemWindowInsetLeft();
63        } else {
64            return 0;
65        }
66    }
67
68    /**
69     * Returns the top system window inset in pixels.
70     *
71     * <p>The system window inset represents the area of a full-screen window that is
72     * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
73     * </p>
74     *
75     * @return The top system window inset
76     */
77    public int getSystemWindowInsetTop() {
78        if (SDK_INT >= 20) {
79            return ((WindowInsets) mInsets).getSystemWindowInsetTop();
80        } else {
81            return 0;
82        }
83    }
84
85    /**
86     * Returns the right system window inset in pixels.
87     *
88     * <p>The system window inset represents the area of a full-screen window that is
89     * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
90     * </p>
91     *
92     * @return The right system window inset
93     */
94    public int getSystemWindowInsetRight() {
95        if (SDK_INT >= 20) {
96            return ((WindowInsets) mInsets).getSystemWindowInsetRight();
97        } else {
98            return 0;
99        }
100    }
101
102    /**
103     * Returns the bottom system window inset in pixels.
104     *
105     * <p>The system window inset represents the area of a full-screen window that is
106     * partially or fully obscured by the status bar, navigation bar, IME or other system windows.
107     * </p>
108     *
109     * @return The bottom system window inset
110     */
111    public int getSystemWindowInsetBottom() {
112        if (SDK_INT >= 20) {
113            return ((WindowInsets) mInsets).getSystemWindowInsetBottom();
114        } else {
115            return 0;
116        }
117    }
118
119    /**
120     * Returns true if this WindowInsets has nonzero system window insets.
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 true if any of the system window inset values are nonzero
127     */
128    public boolean hasSystemWindowInsets() {
129        if (SDK_INT >= 20) {
130            return ((WindowInsets) mInsets).hasSystemWindowInsets();
131        } else {
132            return false;
133        }
134    }
135
136    /**
137     * Returns true if this WindowInsets has any nonzero insets.
138     *
139     * @return true if any inset values are nonzero
140     */
141    public boolean hasInsets() {
142        if (SDK_INT >= 20) {
143            return ((WindowInsets) mInsets).hasInsets();
144        } else {
145            return false;
146        }
147    }
148
149    /**
150     * Check if these insets have been fully consumed.
151     *
152     * <p>Insets are considered "consumed" if the applicable <code>consume*</code> methods
153     * have been called such that all insets have been set to zero. This affects propagation of
154     * insets through the view hierarchy; insets that have not been fully consumed will continue
155     * to propagate down to child views.</p>
156     *
157     * <p>The result of this method is equivalent to the return value of
158     * {@link android.view.View#fitSystemWindows(android.graphics.Rect)}.</p>
159     *
160     * @return true if the insets have been fully consumed.
161     */
162    public boolean isConsumed() {
163        if (SDK_INT >= 21) {
164            return ((WindowInsets) mInsets).isConsumed();
165        } else {
166            return false;
167        }
168    }
169
170    /**
171     * Returns true if the associated window has a round shape.
172     *
173     * <p>A round window's left, top, right and bottom edges reach all the way to the
174     * associated edges of the window but the corners may not be visible. Views responding
175     * to round insets should take care to not lay out critical elements within the corners
176     * where they may not be accessible.</p>
177     *
178     * @return True if the window is round
179     */
180    public boolean isRound() {
181        if (SDK_INT >= 20) {
182            return ((WindowInsets) mInsets).isRound();
183        } else {
184            return false;
185        }
186    }
187
188    /**
189     * Returns a copy of this WindowInsets with the system window insets fully consumed.
190     *
191     * @return A modified copy of this WindowInsets
192     */
193    public WindowInsetsCompat consumeSystemWindowInsets() {
194        if (SDK_INT >= 20) {
195            return new WindowInsetsCompat(((WindowInsets) mInsets).consumeSystemWindowInsets());
196        } else {
197            return null;
198        }
199    }
200
201    /**
202     * Returns a copy of this WindowInsets with selected system window insets replaced
203     * with new values.
204     *
205     * @param left New left inset in pixels
206     * @param top New top inset in pixels
207     * @param right New right inset in pixels
208     * @param bottom New bottom inset in pixels
209     * @return A modified copy of this WindowInsets
210     */
211    public WindowInsetsCompat replaceSystemWindowInsets(int left, int top, int right, int bottom) {
212        if (SDK_INT >= 20) {
213            return new WindowInsetsCompat(
214                    ((WindowInsets) mInsets).replaceSystemWindowInsets(left, top, right, bottom));
215        } else {
216            return null;
217        }
218    }
219
220    /**
221     * Returns a copy of this WindowInsets with selected system window insets replaced
222     * with new values.
223     *
224     * @param systemWindowInsets New system window insets. Each field is the inset in pixels
225     *                           for that edge
226     * @return A modified copy of this WindowInsets
227     */
228    public WindowInsetsCompat replaceSystemWindowInsets(Rect systemWindowInsets) {
229        if (SDK_INT >= 21) {
230            return new WindowInsetsCompat(
231                    ((WindowInsets) mInsets).replaceSystemWindowInsets(systemWindowInsets));
232        } else {
233            return null;
234        }
235    }
236
237    /**
238     * Returns the top stable inset in pixels.
239     *
240     * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
241     * partially or fully obscured by the system UI elements.  This value does not change
242     * based on the visibility state of those elements; for example, if the status bar is
243     * normally shown, but temporarily hidden, the stable inset will still provide the inset
244     * associated with the status bar being shown.</p>
245     *
246     * @return The top stable inset
247     */
248    public int getStableInsetTop() {
249        if (SDK_INT >= 21) {
250            return ((WindowInsets) mInsets).getStableInsetTop();
251        } else {
252            return 0;
253        }
254    }
255
256    /**
257     * Returns the left stable inset in pixels.
258     *
259     * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
260     * partially or fully obscured by the system UI elements.  This value does not change
261     * based on the visibility state of those elements; for example, if the status bar is
262     * normally shown, but temporarily hidden, the stable inset will still provide the inset
263     * associated with the status bar being shown.</p>
264     *
265     * @return The left stable inset
266     */
267    public int getStableInsetLeft() {
268        if (SDK_INT >= 21) {
269            return ((WindowInsets) mInsets).getStableInsetLeft();
270        } else {
271            return 0;
272        }
273    }
274
275    /**
276     * Returns the right stable inset in pixels.
277     *
278     * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
279     * partially or fully obscured by the system UI elements.  This value does not change
280     * based on the visibility state of those elements; for example, if the status bar is
281     * normally shown, but temporarily hidden, the stable inset will still provide the inset
282     * associated with the status bar being shown.</p>
283     *
284     * @return The right stable inset
285     */
286    public int getStableInsetRight() {
287        if (SDK_INT >= 21) {
288            return ((WindowInsets) mInsets).getStableInsetRight();
289        } else {
290            return 0;
291        }
292    }
293
294
295    /**
296     * Returns the bottom stable inset in pixels.
297     *
298     * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
299     * partially or fully obscured by the system UI elements.  This value does not change
300     * based on the visibility state of those elements; for example, if the status bar is
301     * normally shown, but temporarily hidden, the stable inset will still provide the inset
302     * associated with the status bar being shown.</p>
303     *
304     * @return The bottom stable inset
305     */
306    public int getStableInsetBottom() {
307        if (SDK_INT >= 21) {
308            return ((WindowInsets) mInsets).getStableInsetBottom();
309        } else {
310            return 0;
311        }
312    }
313
314    /**
315     * Returns true if this WindowInsets has nonzero stable insets.
316     *
317     * <p>The stable inset represents the area of a full-screen window that <b>may</b> be
318     * partially or fully obscured by the system UI elements.  This value does not change
319     * based on the visibility state of those elements; for example, if the status bar is
320     * normally shown, but temporarily hidden, the stable inset will still provide the inset
321     * associated with the status bar being shown.</p>
322     *
323     * @return true if any of the stable inset values are nonzero
324     */
325    public boolean hasStableInsets() {
326        if (SDK_INT >= 21) {
327            return ((WindowInsets) mInsets).hasStableInsets();
328        } else {
329            return false;
330        }
331    }
332
333    /**
334     * Returns a copy of this WindowInsets with the stable insets fully consumed.
335     *
336     * @return A modified copy of this WindowInsetsCompat
337     */
338    public WindowInsetsCompat consumeStableInsets() {
339        if (SDK_INT >= 21) {
340            return new WindowInsetsCompat(((WindowInsets) mInsets).consumeStableInsets());
341        } else {
342            return null;
343        }
344    }
345
346    @Override
347    public boolean equals(Object o) {
348        if (this == o) {
349            return true;
350        }
351        if (o == null || getClass() != o.getClass()) {
352            return false;
353        }
354        WindowInsetsCompat other = (WindowInsetsCompat) o;
355        return mInsets == null ? other.mInsets == null : mInsets.equals(other.mInsets);
356    }
357
358    @Override
359    public int hashCode() {
360        return mInsets == null ? 0 : mInsets.hashCode();
361    }
362
363    static WindowInsetsCompat wrap(Object insets) {
364        return insets == null ? null : new WindowInsetsCompat(insets);
365    }
366
367    static Object unwrap(WindowInsetsCompat insets) {
368        return insets == null ? null : insets.mInsets;
369    }
370}
371