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