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