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