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 165 /** Set the flags of this provider. */ setFlags(@lags int flags)166 public InsetsFrameProvider setFlags(@Flags int flags) { 167 mFlags = flags; 168 return this; 169 } 170 setFlags(@lags int flags, @Flags int mask)171 public InsetsFrameProvider setFlags(@Flags int flags, @Flags int mask) { 172 mFlags = (mFlags & ~mask) | (flags & mask); 173 return this; 174 } 175 getFlags()176 public @Flags int getFlags() { 177 return mFlags; 178 } 179 hasFlags(@lags int mask)180 public boolean hasFlags(@Flags int mask) { 181 return (mFlags & mask) == mask; 182 } 183 setInsetsSize(Insets insetsSize)184 public InsetsFrameProvider setInsetsSize(Insets insetsSize) { 185 mInsetsSize = insetsSize; 186 return this; 187 } 188 getInsetsSize()189 public Insets getInsetsSize() { 190 return mInsetsSize; 191 } 192 setArbitraryRectangle(Rect rect)193 public InsetsFrameProvider setArbitraryRectangle(Rect rect) { 194 mArbitraryRectangle = new Rect(rect); 195 return this; 196 } 197 getArbitraryRectangle()198 public Rect getArbitraryRectangle() { 199 return mArbitraryRectangle; 200 } 201 setInsetsSizeOverrides(InsetsSizeOverride[] insetsSizeOverrides)202 public InsetsFrameProvider setInsetsSizeOverrides(InsetsSizeOverride[] insetsSizeOverrides) { 203 mInsetsSizeOverrides = insetsSizeOverrides; 204 return this; 205 } 206 getInsetsSizeOverrides()207 public InsetsSizeOverride[] getInsetsSizeOverrides() { 208 return mInsetsSizeOverrides; 209 } 210 setMinimalInsetsSizeInDisplayCutoutSafe( Insets minimalInsetsSizeInDisplayCutoutSafe)211 public InsetsFrameProvider setMinimalInsetsSizeInDisplayCutoutSafe( 212 Insets minimalInsetsSizeInDisplayCutoutSafe) { 213 mMinimalInsetsSizeInDisplayCutoutSafe = minimalInsetsSizeInDisplayCutoutSafe; 214 return this; 215 } 216 getMinimalInsetsSizeInDisplayCutoutSafe()217 public Insets getMinimalInsetsSizeInDisplayCutoutSafe() { 218 return mMinimalInsetsSizeInDisplayCutoutSafe; 219 } 220 221 /** 222 * Sets the bounding rectangles within and relative to the source frame. 223 */ setBoundingRects(@ullable Rect[] boundingRects)224 public InsetsFrameProvider setBoundingRects(@Nullable Rect[] boundingRects) { 225 mBoundingRects = boundingRects == null ? null : boundingRects.clone(); 226 return this; 227 } 228 229 /** 230 * Returns the arbitrary bounding rects, or null if none were set. 231 */ 232 @Nullable getBoundingRects()233 public Rect[] getBoundingRects() { 234 return mBoundingRects; 235 } 236 237 @Override describeContents()238 public int describeContents() { 239 return 0; 240 } 241 242 @Override toString()243 public String toString() { 244 final StringBuilder sb = new StringBuilder("InsetsFrameProvider: {"); 245 sb.append("id=#").append(Integer.toHexString(mId)); 246 sb.append(", index=").append(getIndex()); 247 sb.append(", type=").append(WindowInsets.Type.toString(getType())); 248 sb.append(", source=").append(sourceToString(mSource)); 249 sb.append(", flags=[").append(InsetsSource.flagsToString(mFlags)).append("]"); 250 if (mInsetsSize != null) { 251 sb.append(", insetsSize=").append(mInsetsSize); 252 } 253 if (mInsetsSizeOverrides != null) { 254 sb.append(", insetsSizeOverrides=").append(Arrays.toString(mInsetsSizeOverrides)); 255 } 256 if (mArbitraryRectangle != null) { 257 sb.append(", mArbitraryRectangle=").append(mArbitraryRectangle.toShortString()); 258 } 259 if (mMinimalInsetsSizeInDisplayCutoutSafe != null) { 260 sb.append(", mMinimalInsetsSizeInDisplayCutoutSafe=") 261 .append(mMinimalInsetsSizeInDisplayCutoutSafe); 262 } 263 if (mBoundingRects != null) { 264 sb.append(", mBoundingRects=").append(Arrays.toString(mBoundingRects)); 265 } 266 sb.append("}"); 267 return sb.toString(); 268 } 269 sourceToString(int source)270 private static String sourceToString(int source) { 271 switch (source) { 272 case SOURCE_DISPLAY: 273 return "DISPLAY"; 274 case SOURCE_CONTAINER_BOUNDS: 275 return "CONTAINER_BOUNDS"; 276 case SOURCE_FRAME: 277 return "FRAME"; 278 case SOURCE_ARBITRARY_RECTANGLE: 279 return "ARBITRARY_RECTANGLE"; 280 } 281 return "UNDEFINED"; 282 } 283 InsetsFrameProvider(Parcel in)284 public InsetsFrameProvider(Parcel in) { 285 mId = in.readInt(); 286 mSource = in.readInt(); 287 mFlags = in.readInt(); 288 mInsetsSize = in.readTypedObject(Insets.CREATOR); 289 mInsetsSizeOverrides = in.createTypedArray(InsetsSizeOverride.CREATOR); 290 mArbitraryRectangle = in.readTypedObject(Rect.CREATOR); 291 mMinimalInsetsSizeInDisplayCutoutSafe = in.readTypedObject(Insets.CREATOR); 292 mBoundingRects = in.createTypedArray(Rect.CREATOR); 293 } 294 295 @Override writeToParcel(Parcel out, int flags)296 public void writeToParcel(Parcel out, int flags) { 297 out.writeInt(mId); 298 out.writeInt(mSource); 299 out.writeInt(mFlags); 300 out.writeTypedObject(mInsetsSize, flags); 301 out.writeTypedArray(mInsetsSizeOverrides, flags); 302 out.writeTypedObject(mArbitraryRectangle, flags); 303 out.writeTypedObject(mMinimalInsetsSizeInDisplayCutoutSafe, flags); 304 out.writeTypedArray(mBoundingRects, flags); 305 } 306 idEquals(InsetsFrameProvider o)307 public boolean idEquals(InsetsFrameProvider o) { 308 return mId == o.mId; 309 } 310 311 @Override equals(Object o)312 public boolean equals(Object o) { 313 if (this == o) { 314 return true; 315 } 316 if (o == null || getClass() != o.getClass()) { 317 return false; 318 } 319 final InsetsFrameProvider other = (InsetsFrameProvider) o; 320 return mId == other.mId && mSource == other.mSource && mFlags == other.mFlags 321 && Objects.equals(mInsetsSize, other.mInsetsSize) 322 && Arrays.equals(mInsetsSizeOverrides, other.mInsetsSizeOverrides) 323 && Objects.equals(mArbitraryRectangle, other.mArbitraryRectangle) 324 && Objects.equals(mMinimalInsetsSizeInDisplayCutoutSafe, 325 other.mMinimalInsetsSizeInDisplayCutoutSafe) 326 && Arrays.equals(mBoundingRects, other.mBoundingRects); 327 } 328 329 @Override hashCode()330 public int hashCode() { 331 return Objects.hash(mId, mSource, mFlags, mInsetsSize, 332 Arrays.hashCode(mInsetsSizeOverrides), mArbitraryRectangle, 333 mMinimalInsetsSizeInDisplayCutoutSafe, Arrays.hashCode(mBoundingRects)); 334 } 335 336 public static final @NonNull Parcelable.Creator<InsetsFrameProvider> CREATOR = 337 new Parcelable.Creator<>() { 338 @Override 339 public InsetsFrameProvider createFromParcel(Parcel in) { 340 return new InsetsFrameProvider(in); 341 } 342 343 @Override 344 public InsetsFrameProvider[] newArray(int size) { 345 return new InsetsFrameProvider[size]; 346 } 347 }; 348 349 /** 350 * Class to describe the insets size to be provided to window with specific window type. If not 351 * used, same insets size will be sent as instructed in the insetsSize and source. 352 * 353 * If the insetsSize of given type is set to {@code null}, the insets source frame will be used 354 * directly for that window type. 355 */ 356 public static class InsetsSizeOverride implements Parcelable { 357 358 private final int mWindowType; 359 private final Insets mInsetsSize; 360 InsetsSizeOverride(Parcel in)361 protected InsetsSizeOverride(Parcel in) { 362 mWindowType = in.readInt(); 363 mInsetsSize = in.readTypedObject(Insets.CREATOR); 364 } 365 InsetsSizeOverride(int windowType, Insets insetsSize)366 public InsetsSizeOverride(int windowType, Insets insetsSize) { 367 mWindowType = windowType; 368 mInsetsSize = insetsSize; 369 } getWindowType()370 public int getWindowType() { 371 return mWindowType; 372 } 373 getInsetsSize()374 public Insets getInsetsSize() { 375 return mInsetsSize; 376 } 377 378 public static final Creator<InsetsSizeOverride> CREATOR = new Creator<>() { 379 @Override 380 public InsetsSizeOverride createFromParcel(Parcel in) { 381 return new InsetsSizeOverride(in); 382 } 383 384 @Override 385 public InsetsSizeOverride[] newArray(int size) { 386 return new InsetsSizeOverride[size]; 387 } 388 }; 389 390 @Override describeContents()391 public int describeContents() { 392 return 0; 393 } 394 395 @Override writeToParcel(Parcel out, int flags)396 public void writeToParcel(Parcel out, int flags) { 397 out.writeInt(mWindowType); 398 out.writeTypedObject(mInsetsSize, flags); 399 } 400 401 @Override toString()402 public String toString() { 403 StringBuilder sb = new StringBuilder(32); 404 sb.append("TypedInsetsSize: {"); 405 sb.append("windowType=").append(ViewDebug.intToString( 406 WindowManager.LayoutParams.class, "type", mWindowType)); 407 sb.append(", insetsSize=").append(mInsetsSize); 408 sb.append("}"); 409 return sb.toString(); 410 } 411 412 @Override hashCode()413 public int hashCode() { 414 return Objects.hash(mWindowType, mInsetsSize); 415 } 416 } 417 } 418 419