1 /*
2  * Copyright (C) 2022 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 package android.view;
18 
19 import android.annotation.IntRange;
20 import android.annotation.NonNull;
21 import android.graphics.Insets;
22 import android.graphics.Rect;
23 import android.os.IBinder;
24 import android.os.Parcel;
25 import android.os.Parcelable;
26 import android.view.InsetsSource.Flags;
27 import android.view.WindowInsets.Type.InsetsType;
28 
29 import java.util.Arrays;
30 import java.util.Objects;
31 
32 /**
33  * Insets provided by a window.
34  *
35  * The insets frame will by default as the window frame size. If the providers are set, the
36  * calculation result based on the source size will be used as the insets frame.
37  *
38  * The InsetsFrameProvider should be self-contained. Nothing describing the window itself, such as
39  * contentInsets, visibleInsets, etc. won't affect the insets providing to other windows when this
40  * is set.
41  * @hide
42  */
43 public class InsetsFrameProvider implements Parcelable {
44 
45     /**
46      * Uses the display frame as the source.
47      */
48     public static final int SOURCE_DISPLAY = 0;
49 
50     /**
51      * Uses the window bounds as the source.
52      */
53     public static final int SOURCE_CONTAINER_BOUNDS = 1;
54 
55     /**
56      * Uses the window frame as the source.
57      */
58     public static final int SOURCE_FRAME = 2;
59 
60     /**
61      * Uses {@link #mArbitraryRectangle} as the source.
62      */
63     public static final int SOURCE_ARBITRARY_RECTANGLE = 3;
64 
65     private final int mId;
66 
67     /**
68      * The selection of the starting rectangle to be converted into source frame.
69      */
70     private int mSource = SOURCE_FRAME;
71 
72     /**
73      * This is used as the source frame only if SOURCE_ARBITRARY_RECTANGLE is applied.
74      */
75     private Rect mArbitraryRectangle;
76 
77     /**
78      * Modifies the starting rectangle selected by {@link #mSource}.
79      *
80      * For example, when the given source frame is (0, 0) - (100, 200), and the insetsSize is null,
81      * the source frame will be directly used as the final insets frame. If the insetsSize is set to
82      * (0, 0, 0, 50) instead, the insets frame will be a frame starting from the bottom side of the
83      * source frame with height of 50, i.e., (0, 150) - (100, 200).
84      */
85     private Insets mInsetsSize = null;
86 
87     /**
88      * Various behavioral options/flags. Default is none.
89      *
90      * @see Flags
91      */
92     private @Flags int mFlags;
93 
94     /**
95      * If null, the size set in insetsSize will be applied to all window types. If it contains
96      * element of some types, the insets reported to the window with that types will be overridden.
97      */
98     private InsetsSizeOverride[] mInsetsSizeOverrides = null;
99 
100     /**
101      * This field, if set, is indicating the insets needs to be at least the given size inside the
102      * display cutout safe area. This will be compared to the insets size calculated based on other
103      * attributes, and will be applied when this is larger. This is independent of the
104      * PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT in LayoutParams, as this is not going to change
105      * the layout of the window, but only change the insets frame. This can be applied to insets
106      * calculated based on all three source frames.
107      *
108      * Be cautious, this will not be in effect for the window types whose insets size is overridden.
109      */
110     private Insets mMinimalInsetsSizeInDisplayCutoutSafe = null;
111 
112     /**
113      * Creates an InsetsFrameProvider which describes what frame an insets source should have.
114      *
115      * @param owner the owner of this provider. We might have multiple sources with the same type on
116      *              a display, this is used to identify them.
117      * @param index the index of this provider. An owner might provide multiple sources with the
118      *              same type, this is used to identify them.
119      *              The value must be in a range of [0, 2047].
120      * @param type the {@link InsetsType}.
121      * @see InsetsSource#createId(Object, int, int)
122      */
InsetsFrameProvider(Object owner, @IntRange(from = 0, to = 2047) int index, @InsetsType int type)123     public InsetsFrameProvider(Object owner, @IntRange(from = 0, to = 2047) int index,
124             @InsetsType int type) {
125         mId = InsetsSource.createId(owner, index, type);
126     }
127 
128     /**
129      * Returns an unique integer which identifies the insets source.
130      */
getId()131     public int getId() {
132         return mId;
133     }
134 
135     /**
136      * Returns the index specified in {@link #InsetsFrameProvider(IBinder, int, int)}.
137      */
getIndex()138     public int getIndex() {
139         return InsetsSource.getIndex(mId);
140     }
141 
142     /**
143      * Returns the {@link InsetsType} specified in {@link #InsetsFrameProvider(IBinder, int, int)}.
144      */
getType()145     public int getType() {
146         return InsetsSource.getType(mId);
147     }
148 
setSource(int source)149     public InsetsFrameProvider setSource(int source) {
150         mSource = source;
151         return this;
152     }
153 
getSource()154     public int getSource() {
155         return mSource;
156     }
157 
setFlags(@lags int flags, @Flags int mask)158     public InsetsFrameProvider setFlags(@Flags int flags, @Flags int mask) {
159         mFlags = (mFlags & ~mask) | (flags & mask);
160         return this;
161     }
162 
getFlags()163     public @Flags int getFlags() {
164         return mFlags;
165     }
166 
hasFlags(@lags int mask)167     public boolean hasFlags(@Flags int mask) {
168         return (mFlags & mask) == mask;
169     }
170 
setInsetsSize(Insets insetsSize)171     public InsetsFrameProvider setInsetsSize(Insets insetsSize) {
172         mInsetsSize = insetsSize;
173         return this;
174     }
175 
getInsetsSize()176     public Insets getInsetsSize() {
177         return mInsetsSize;
178     }
179 
setArbitraryRectangle(Rect rect)180     public InsetsFrameProvider setArbitraryRectangle(Rect rect) {
181         mArbitraryRectangle = new Rect(rect);
182         return this;
183     }
184 
getArbitraryRectangle()185     public Rect getArbitraryRectangle() {
186         return mArbitraryRectangle;
187     }
188 
setInsetsSizeOverrides(InsetsSizeOverride[] insetsSizeOverrides)189     public InsetsFrameProvider setInsetsSizeOverrides(InsetsSizeOverride[] insetsSizeOverrides) {
190         mInsetsSizeOverrides = insetsSizeOverrides;
191         return this;
192     }
193 
getInsetsSizeOverrides()194     public InsetsSizeOverride[] getInsetsSizeOverrides() {
195         return mInsetsSizeOverrides;
196     }
197 
setMinimalInsetsSizeInDisplayCutoutSafe( Insets minimalInsetsSizeInDisplayCutoutSafe)198     public InsetsFrameProvider setMinimalInsetsSizeInDisplayCutoutSafe(
199             Insets minimalInsetsSizeInDisplayCutoutSafe) {
200         mMinimalInsetsSizeInDisplayCutoutSafe = minimalInsetsSizeInDisplayCutoutSafe;
201         return this;
202     }
203 
getMinimalInsetsSizeInDisplayCutoutSafe()204     public Insets getMinimalInsetsSizeInDisplayCutoutSafe() {
205         return mMinimalInsetsSizeInDisplayCutoutSafe;
206     }
207 
208     @Override
describeContents()209     public int describeContents() {
210         return 0;
211     }
212 
213     @Override
toString()214     public String toString() {
215         final StringBuilder sb = new StringBuilder("InsetsFrameProvider: {");
216         sb.append("id=#").append(Integer.toHexString(mId));
217         sb.append(", index=").append(getIndex());
218         sb.append(", type=").append(WindowInsets.Type.toString(getType()));
219         sb.append(", source=").append(sourceToString(mSource));
220         sb.append(", flags=[").append(InsetsSource.flagsToString(mFlags)).append("]");
221         if (mInsetsSize != null) {
222             sb.append(", insetsSize=").append(mInsetsSize);
223         }
224         if (mInsetsSizeOverrides != null) {
225             sb.append(", insetsSizeOverrides=").append(Arrays.toString(mInsetsSizeOverrides));
226         }
227         if (mArbitraryRectangle != null) {
228             sb.append(", mArbitraryRectangle=").append(mArbitraryRectangle.toShortString());
229         }
230         if (mMinimalInsetsSizeInDisplayCutoutSafe != null) {
231             sb.append(", mMinimalInsetsSizeInDisplayCutoutSafe=")
232                     .append(mMinimalInsetsSizeInDisplayCutoutSafe);
233         }
234         sb.append("}");
235         return sb.toString();
236     }
237 
sourceToString(int source)238     private static String sourceToString(int source) {
239         switch (source) {
240             case SOURCE_DISPLAY:
241                 return "DISPLAY";
242             case SOURCE_CONTAINER_BOUNDS:
243                 return "CONTAINER_BOUNDS";
244             case SOURCE_FRAME:
245                 return "FRAME";
246             case SOURCE_ARBITRARY_RECTANGLE:
247                 return "ARBITRARY_RECTANGLE";
248         }
249         return "UNDEFINED";
250     }
251 
InsetsFrameProvider(Parcel in)252     public InsetsFrameProvider(Parcel in) {
253         mId = in.readInt();
254         mSource = in.readInt();
255         mFlags = in.readInt();
256         mInsetsSize = in.readTypedObject(Insets.CREATOR);
257         mInsetsSizeOverrides = in.createTypedArray(InsetsSizeOverride.CREATOR);
258         mArbitraryRectangle = in.readTypedObject(Rect.CREATOR);
259         mMinimalInsetsSizeInDisplayCutoutSafe = in.readTypedObject(Insets.CREATOR);
260     }
261 
262     @Override
writeToParcel(Parcel out, int flags)263     public void writeToParcel(Parcel out, int flags) {
264         out.writeInt(mId);
265         out.writeInt(mSource);
266         out.writeInt(mFlags);
267         out.writeTypedObject(mInsetsSize, flags);
268         out.writeTypedArray(mInsetsSizeOverrides, flags);
269         out.writeTypedObject(mArbitraryRectangle, flags);
270         out.writeTypedObject(mMinimalInsetsSizeInDisplayCutoutSafe, flags);
271     }
272 
idEquals(InsetsFrameProvider o)273     public boolean idEquals(InsetsFrameProvider o) {
274         return mId == o.mId;
275     }
276 
277     @Override
equals(Object o)278     public boolean equals(Object o) {
279         if (this == o) {
280             return true;
281         }
282         if (o == null || getClass() != o.getClass()) {
283             return false;
284         }
285         final InsetsFrameProvider other = (InsetsFrameProvider) o;
286         return mId == other.mId && mSource == other.mSource && mFlags == other.mFlags
287                 && Objects.equals(mInsetsSize, other.mInsetsSize)
288                 && Arrays.equals(mInsetsSizeOverrides, other.mInsetsSizeOverrides)
289                 && Objects.equals(mArbitraryRectangle, other.mArbitraryRectangle)
290                 && Objects.equals(mMinimalInsetsSizeInDisplayCutoutSafe,
291                         other.mMinimalInsetsSizeInDisplayCutoutSafe);
292     }
293 
294     @Override
hashCode()295     public int hashCode() {
296         return Objects.hash(mId, mSource, mFlags, mInsetsSize,
297                 Arrays.hashCode(mInsetsSizeOverrides), mArbitraryRectangle,
298                 mMinimalInsetsSizeInDisplayCutoutSafe);
299     }
300 
301     public static final @NonNull Parcelable.Creator<InsetsFrameProvider> CREATOR =
302             new Parcelable.Creator<>() {
303                 @Override
304                 public InsetsFrameProvider createFromParcel(Parcel in) {
305                     return new InsetsFrameProvider(in);
306                 }
307 
308                 @Override
309                 public InsetsFrameProvider[] newArray(int size) {
310                     return new InsetsFrameProvider[size];
311                 }
312             };
313 
314     /**
315      * Class to describe the insets size to be provided to window with specific window type. If not
316      * used, same insets size will be sent as instructed in the insetsSize and source.
317      *
318      * If the insetsSize of given type is set to {@code null}, the insets source frame will be used
319      * directly for that window type.
320      */
321     public static class InsetsSizeOverride implements Parcelable {
322 
323         private final int mWindowType;
324         private final Insets mInsetsSize;
325 
InsetsSizeOverride(Parcel in)326         protected InsetsSizeOverride(Parcel in) {
327             mWindowType = in.readInt();
328             mInsetsSize = in.readTypedObject(Insets.CREATOR);
329         }
330 
InsetsSizeOverride(int windowType, Insets insetsSize)331         public InsetsSizeOverride(int windowType, Insets insetsSize) {
332             mWindowType = windowType;
333             mInsetsSize = insetsSize;
334         }
getWindowType()335         public int getWindowType() {
336             return mWindowType;
337         }
338 
getInsetsSize()339         public Insets getInsetsSize() {
340             return mInsetsSize;
341         }
342 
343         public static final Creator<InsetsSizeOverride> CREATOR = new Creator<>() {
344             @Override
345             public InsetsSizeOverride createFromParcel(Parcel in) {
346                 return new InsetsSizeOverride(in);
347             }
348 
349             @Override
350             public InsetsSizeOverride[] newArray(int size) {
351                 return new InsetsSizeOverride[size];
352             }
353         };
354 
355         @Override
describeContents()356         public int describeContents() {
357             return 0;
358         }
359 
360         @Override
writeToParcel(Parcel out, int flags)361         public void writeToParcel(Parcel out, int flags) {
362             out.writeInt(mWindowType);
363             out.writeTypedObject(mInsetsSize, flags);
364         }
365 
366         @Override
toString()367         public String toString() {
368             StringBuilder sb = new StringBuilder(32);
369             sb.append("TypedInsetsSize: {");
370             sb.append("windowType=").append(ViewDebug.intToString(
371                     WindowManager.LayoutParams.class, "type", mWindowType));
372             sb.append(", insetsSize=").append(mInsetsSize);
373             sb.append("}");
374             return sb.toString();
375         }
376 
377         @Override
hashCode()378         public int hashCode() {
379             return Objects.hash(mWindowType, mInsetsSize);
380         }
381     }
382 }
383 
384