• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT;
20 
21 import android.graphics.Insets;
22 import android.graphics.Rect;
23 import android.os.Parcel;
24 import android.os.Parcelable;
25 
26 import java.util.Arrays;
27 import java.util.Objects;
28 
29 /**
30  * Insets provided by a window.
31  *
32  * The insets frame will by default as the window frame size. If the providers are set, the
33  * calculation result based on the source size will be used as the insets frame.
34  * @hide
35  */
36 public class InsetsFrameProvider implements Parcelable {
37 
38     /**
39      * If specified in source field, the insets calculation will be based on the display frame.
40      */
41     public static final int SOURCE_DISPLAY = 0;
42 
43     /**
44      * If specified in source field, the insets calculation will be based on the window bounds. The
45      * container bounds can sometimes be different from the window frame. For example, when a task
46      * bar needs the entire screen to be prepared to showing the apps, the window container can take
47      * the entire display, or display area, but the window frame, as a result of the layout, will
48      * stay small until it actually taking the entire display to draw their view.
49      */
50     public static final int SOURCE_CONTAINER_BOUNDS = 1;
51 
52     /**
53      * If specified in source field, the insets calculation will be based on the window frame. This
54      * is also the default value of the source.
55      */
56     public static final int SOURCE_FRAME = 2;
57 
58     private static final int HAS_INSETS_SIZE = 1;
59     private static final int HAS_INSETS_SIZE_OVERRIDE = 2;
60 
61     private static Rect sTmpRect = new Rect();
62 
63     /**
64      * The type of insets to provide.
65      */
66     public @InsetsState.InternalInsetsType int type;
67 
68     /**
69      * The source of frame. By default, all adjustment will be based on the window frame, it
70      * can be set to window bounds or display bounds instead.
71      */
72     public int source = SOURCE_FRAME;
73 
74     /**
75      * The provided insets size based on the source frame. The result will be used as the insets
76      * size to windows other than IME. Only one side should be set.
77      *
78      * For example, when the given source frame is (0, 0) - (100, 200), and the insetsSize is null,
79      * the source frame will be directly used as the final insets frame. If the insetsSize is set to
80      * (0, 0, 0, 50) instead, the insets frame will be a frame starting from the bottom side of the
81      * source frame with height of 50, i.e., (0, 150) - (100, 200).
82      */
83     public Insets insetsSize = null;
84 
85     /**
86      * If null, the size set in insetsSize will be applied to all window types. If it contains
87      * element of some types, the insets reported to the window with that types will be overridden.
88      */
89     public InsetsSizeOverride[] insetsSizeOverrides = null;
90 
InsetsFrameProvider(int type)91     public InsetsFrameProvider(int type) {
92         this(type, SOURCE_FRAME, null, null);
93     }
94 
InsetsFrameProvider(int type, Insets insetsSize)95     public InsetsFrameProvider(int type, Insets insetsSize) {
96         this(type, SOURCE_FRAME, insetsSize, null);
97     }
98 
InsetsFrameProvider(int type, int source, Insets insetsSize, InsetsSizeOverride[] insetsSizeOverride)99     public InsetsFrameProvider(int type, int source, Insets insetsSize,
100             InsetsSizeOverride[] insetsSizeOverride) {
101         this.type = type;
102         this.source = source;
103         this.insetsSize = insetsSize;
104         this.insetsSizeOverrides = insetsSizeOverride;
105     }
106 
107     @Override
describeContents()108     public int describeContents() {
109         return 0;
110     }
111 
112     @Override
toString()113     public String toString() {
114         StringBuilder sb = new StringBuilder(32);
115         sb.append("InsetsFrameProvider: {");
116         sb.append("type=").append(InsetsState.typeToString(type));
117         sb.append(", source=");
118         switch (source) {
119             case SOURCE_DISPLAY:
120                 sb.append("SOURCE_DISPLAY");
121                 break;
122             case SOURCE_CONTAINER_BOUNDS:
123                 sb.append("SOURCE_CONTAINER_BOUNDS Bounds");
124                 break;
125             case SOURCE_FRAME:
126                 sb.append("SOURCE_FRAME");
127                 break;
128         }
129         if (insetsSize != null) {
130             sb.append(", insetsSize=").append(insetsSize);
131         }
132         if (insetsSizeOverrides != null) {
133             sb.append(", insetsSizeOverrides=").append(Arrays.toString(insetsSizeOverrides));
134         }
135         sb.append("}");
136         return sb.toString();
137     }
138 
InsetsFrameProvider(Parcel in)139     public InsetsFrameProvider(Parcel in) {
140         int insetsSizeModified = in.readInt();
141         type = in.readInt();
142         source = in.readInt();
143         if ((insetsSizeModified & HAS_INSETS_SIZE) != 0) {
144             insetsSize = Insets.CREATOR.createFromParcel(in);
145         }
146         if ((insetsSizeModified & HAS_INSETS_SIZE_OVERRIDE) != 0) {
147             insetsSizeOverrides = in.createTypedArray(InsetsSizeOverride.CREATOR);
148         }
149     }
150 
151     @Override
writeToParcel(Parcel out, int flags)152     public void writeToParcel(Parcel out, int flags) {
153         int insetsSizeModified = 0;
154         if (insetsSize != null) {
155             insetsSizeModified |= HAS_INSETS_SIZE;
156         }
157         if (insetsSizeOverrides != null) {
158             insetsSizeModified |= HAS_INSETS_SIZE_OVERRIDE;
159         }
160         out.writeInt(insetsSizeModified);
161         out.writeInt(type);
162         out.writeInt(source);
163         if (insetsSize != null) {
164             insetsSize.writeToParcel(out, flags);
165         }
166         if (insetsSizeOverrides != null) {
167             out.writeTypedArray(insetsSizeOverrides, flags);
168         }
169     }
170 
171     @Override
equals(Object o)172     public boolean equals(Object o) {
173         if (this == o) {
174             return true;
175         }
176         if (o == null || getClass() != o.getClass()) {
177             return false;
178         }
179         InsetsFrameProvider other = (InsetsFrameProvider) o;
180         return type == other.type && source == other.source
181                 && Objects.equals(insetsSize, other.insetsSize)
182                 && Arrays.equals(insetsSizeOverrides, other.insetsSizeOverrides);
183     }
184 
185     @Override
hashCode()186     public int hashCode() {
187         return Objects.hash(type, source, insetsSize, Arrays.hashCode(insetsSizeOverrides));
188     }
189 
190     public static final @android.annotation.NonNull Parcelable.Creator<InsetsFrameProvider>
191             CREATOR = new Parcelable.Creator<InsetsFrameProvider>() {
192                 @Override
193                 public InsetsFrameProvider createFromParcel(Parcel in) {
194                     return new InsetsFrameProvider(in);
195                 }
196 
197                 @Override
198                 public InsetsFrameProvider[] newArray(int size) {
199                     return new InsetsFrameProvider[size];
200                 }
201             };
202 
calculateInsetsFrame(Rect displayFrame, Rect containerBounds, Rect displayCutoutSafe, Rect inOutFrame, int source, Insets insetsSize, @WindowManager.LayoutParams.PrivateFlags int privateFlags)203     public static void calculateInsetsFrame(Rect displayFrame, Rect containerBounds,
204             Rect displayCutoutSafe, Rect inOutFrame, int source, Insets insetsSize,
205             @WindowManager.LayoutParams.PrivateFlags int privateFlags) {
206         boolean extendByCutout = false;
207         if (source == InsetsFrameProvider.SOURCE_DISPLAY) {
208             inOutFrame.set(displayFrame);
209         } else if (source == InsetsFrameProvider.SOURCE_CONTAINER_BOUNDS) {
210             inOutFrame.set(containerBounds);
211         } else {
212             extendByCutout = (privateFlags & PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT) != 0;
213         }
214         if (insetsSize == null) {
215             return;
216         }
217         // Only one side of the provider shall be applied. Check in the order of left - top -
218         // right - bottom, only the first non-zero value will be applied.
219         if (insetsSize.left != 0) {
220             inOutFrame.right = inOutFrame.left + insetsSize.left;
221         } else if (insetsSize.top != 0) {
222             inOutFrame.bottom = inOutFrame.top + insetsSize.top;
223         } else if (insetsSize.right != 0) {
224             inOutFrame.left = inOutFrame.right - insetsSize.right;
225         } else if (insetsSize.bottom != 0) {
226             inOutFrame.top = inOutFrame.bottom - insetsSize.bottom;
227         } else {
228             inOutFrame.setEmpty();
229         }
230 
231         if (extendByCutout) {
232             WindowLayout.extendFrameByCutout(displayCutoutSafe, displayFrame, inOutFrame, sTmpRect);
233         }
234     }
235 
236     /**
237      * Class to describe the insets size to be provided to window with specific window type. If not
238      * used, same insets size will be sent as instructed in the insetsSize and source.
239      */
240     public static class InsetsSizeOverride implements Parcelable {
241         public final int windowType;
242         public Insets insetsSize;
243 
InsetsSizeOverride(Parcel in)244         protected InsetsSizeOverride(Parcel in) {
245             windowType = in.readInt();
246             insetsSize = in.readParcelable(null, android.graphics.Insets.class);
247         }
248 
InsetsSizeOverride(int type, Insets size)249         public InsetsSizeOverride(int type, Insets size) {
250             windowType = type;
251             insetsSize = size;
252         }
253 
254         public static final Creator<InsetsSizeOverride> CREATOR =
255                 new Creator<InsetsSizeOverride>() {
256             @Override
257             public InsetsSizeOverride createFromParcel(Parcel in) {
258                 return new InsetsSizeOverride(in);
259             }
260 
261             @Override
262             public InsetsSizeOverride[] newArray(int size) {
263                 return new InsetsSizeOverride[size];
264             }
265         };
266 
267         @Override
describeContents()268         public int describeContents() {
269             return 0;
270         }
271 
272         @Override
writeToParcel(Parcel out, int flags)273         public void writeToParcel(Parcel out, int flags) {
274             out.writeInt(windowType);
275             out.writeParcelable(insetsSize, flags);
276         }
277 
278         @Override
toString()279         public String toString() {
280             StringBuilder sb = new StringBuilder(32);
281             sb.append("TypedInsetsSize: {");
282             sb.append("windowType=").append(windowType);
283             sb.append(", insetsSize=").append(insetsSize);
284             sb.append("}");
285             return sb.toString();
286         }
287 
288         @Override
hashCode()289         public int hashCode() {
290             return Objects.hash(windowType, insetsSize);
291         }
292     }
293 }
294 
295