blob: 83bdb087a53956a0f0fa29e2765e8215e774013c [file] [log] [blame]
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.view;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.graphics.Insets;
import android.graphics.Rect;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.view.InsetsSource.Flags;
import android.view.WindowInsets.Type.InsetsType;
import java.util.Arrays;
import java.util.Objects;
/**
* Insets provided by a window.
*
* The insets frame will by default as the window frame size. If the providers are set, the
* calculation result based on the source size will be used as the insets frame.
*
* The InsetsFrameProvider should be self-contained. Nothing describing the window itself, such as
* contentInsets, visibleInsets, etc. won't affect the insets providing to other windows when this
* is set.
* @hide
*/
public class InsetsFrameProvider implements Parcelable {
/**
* Uses the display frame as the source.
*/
public static final int SOURCE_DISPLAY = 0;
/**
* Uses the window bounds as the source.
*/
public static final int SOURCE_CONTAINER_BOUNDS = 1;
/**
* Uses the window frame as the source.
*/
public static final int SOURCE_FRAME = 2;
/**
* Uses {@link #mArbitraryRectangle} as the source.
*/
public static final int SOURCE_ARBITRARY_RECTANGLE = 3;
private final int mId;
/**
* The selection of the starting rectangle to be converted into source frame.
*/
private int mSource = SOURCE_FRAME;
/**
* This is used as the source frame only if SOURCE_ARBITRARY_RECTANGLE is applied.
*/
private Rect mArbitraryRectangle;
/**
* Modifies the starting rectangle selected by {@link #mSource}.
*
* For example, when the given source frame is (0, 0) - (100, 200), and the insetsSize is null,
* the source frame will be directly used as the final insets frame. If the insetsSize is set to
* (0, 0, 0, 50) instead, the insets frame will be a frame starting from the bottom side of the
* source frame with height of 50, i.e., (0, 150) - (100, 200).
*/
private Insets mInsetsSize = null;
/**
* Various behavioral options/flags. Default is none.
*
* @see Flags
*/
private @Flags int mFlags;
/**
* If null, the size set in insetsSize will be applied to all window types. If it contains
* element of some types, the insets reported to the window with that types will be overridden.
*/
private InsetsSizeOverride[] mInsetsSizeOverrides = null;
/**
* This field, if set, is indicating the insets needs to be at least the given size inside the
* display cutout safe area. This will be compared to the insets size calculated based on other
* attributes, and will be applied when this is larger. This is independent of the
* PRIVATE_FLAG_LAYOUT_SIZE_EXTENDED_BY_CUTOUT in LayoutParams, as this is not going to change
* the layout of the window, but only change the insets frame. This can be applied to insets
* calculated based on all three source frames.
*
* Be cautious, this will not be in effect for the window types whose insets size is overridden.
*/
private Insets mMinimalInsetsSizeInDisplayCutoutSafe = null;
/**
* Creates an InsetsFrameProvider which describes what frame an insets source should have.
*
* @param owner the owner of this provider. We might have multiple sources with the same type on
* a display, this is used to identify them.
* @param index the index of this provider. An owner might provide multiple sources with the
* same type, this is used to identify them.
* The value must be in a range of [0, 2047].
* @param type the {@link InsetsType}.
* @see InsetsSource#createId(Object, int, int)
*/
public InsetsFrameProvider(Object owner, @IntRange(from = 0, to = 2047) int index,
@InsetsType int type) {
mId = InsetsSource.createId(owner, index, type);
}
/**
* Returns an unique integer which identifies the insets source.
*/
public int getId() {
return mId;
}
/**
* Returns the index specified in {@link #InsetsFrameProvider(IBinder, int, int)}.
*/
public int getIndex() {
return InsetsSource.getIndex(mId);
}
/**
* Returns the {@link InsetsType} specified in {@link #InsetsFrameProvider(IBinder, int, int)}.
*/
public int getType() {
return InsetsSource.getType(mId);
}
public InsetsFrameProvider setSource(int source) {
mSource = source;
return this;
}
public int getSource() {
return mSource;
}
public InsetsFrameProvider setFlags(@Flags int flags, @Flags int mask) {
mFlags = (mFlags & ~mask) | (flags & mask);
return this;
}
public @Flags int getFlags() {
return mFlags;
}
public boolean hasFlags(@Flags int mask) {
return (mFlags & mask) == mask;
}
public InsetsFrameProvider setInsetsSize(Insets insetsSize) {
mInsetsSize = insetsSize;
return this;
}
public Insets getInsetsSize() {
return mInsetsSize;
}
public InsetsFrameProvider setArbitraryRectangle(Rect rect) {
mArbitraryRectangle = new Rect(rect);
return this;
}
public Rect getArbitraryRectangle() {
return mArbitraryRectangle;
}
public InsetsFrameProvider setInsetsSizeOverrides(InsetsSizeOverride[] insetsSizeOverrides) {
mInsetsSizeOverrides = insetsSizeOverrides;
return this;
}
public InsetsSizeOverride[] getInsetsSizeOverrides() {
return mInsetsSizeOverrides;
}
public InsetsFrameProvider setMinimalInsetsSizeInDisplayCutoutSafe(
Insets minimalInsetsSizeInDisplayCutoutSafe) {
mMinimalInsetsSizeInDisplayCutoutSafe = minimalInsetsSizeInDisplayCutoutSafe;
return this;
}
public Insets getMinimalInsetsSizeInDisplayCutoutSafe() {
return mMinimalInsetsSizeInDisplayCutoutSafe;
}
@Override
public int describeContents() {
return 0;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("InsetsFrameProvider: {");
sb.append("id=#").append(Integer.toHexString(mId));
sb.append(", index=").append(getIndex());
sb.append(", type=").append(WindowInsets.Type.toString(getType()));
sb.append(", source=").append(sourceToString(mSource));
sb.append(", flags=[").append(InsetsSource.flagsToString(mFlags)).append("]");
if (mInsetsSize != null) {
sb.append(", insetsSize=").append(mInsetsSize);
}
if (mInsetsSizeOverrides != null) {
sb.append(", insetsSizeOverrides=").append(Arrays.toString(mInsetsSizeOverrides));
}
if (mArbitraryRectangle != null) {
sb.append(", mArbitraryRectangle=").append(mArbitraryRectangle.toShortString());
}
if (mMinimalInsetsSizeInDisplayCutoutSafe != null) {
sb.append(", mMinimalInsetsSizeInDisplayCutoutSafe=")
.append(mMinimalInsetsSizeInDisplayCutoutSafe);
}
sb.append("}");
return sb.toString();
}
private static String sourceToString(int source) {
switch (source) {
case SOURCE_DISPLAY:
return "DISPLAY";
case SOURCE_CONTAINER_BOUNDS:
return "CONTAINER_BOUNDS";
case SOURCE_FRAME:
return "FRAME";
case SOURCE_ARBITRARY_RECTANGLE:
return "ARBITRARY_RECTANGLE";
}
return "UNDEFINED";
}
public InsetsFrameProvider(Parcel in) {
mId = in.readInt();
mSource = in.readInt();
mFlags = in.readInt();
mInsetsSize = in.readTypedObject(Insets.CREATOR);
mInsetsSizeOverrides = in.createTypedArray(InsetsSizeOverride.CREATOR);
mArbitraryRectangle = in.readTypedObject(Rect.CREATOR);
mMinimalInsetsSizeInDisplayCutoutSafe = in.readTypedObject(Insets.CREATOR);
}
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeInt(mId);
out.writeInt(mSource);
out.writeInt(mFlags);
out.writeTypedObject(mInsetsSize, flags);
out.writeTypedArray(mInsetsSizeOverrides, flags);
out.writeTypedObject(mArbitraryRectangle, flags);
out.writeTypedObject(mMinimalInsetsSizeInDisplayCutoutSafe, flags);
}
public boolean idEquals(InsetsFrameProvider o) {
return mId == o.mId;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final InsetsFrameProvider other = (InsetsFrameProvider) o;
return mId == other.mId && mSource == other.mSource && mFlags == other.mFlags
&& Objects.equals(mInsetsSize, other.mInsetsSize)
&& Arrays.equals(mInsetsSizeOverrides, other.mInsetsSizeOverrides)
&& Objects.equals(mArbitraryRectangle, other.mArbitraryRectangle)
&& Objects.equals(mMinimalInsetsSizeInDisplayCutoutSafe,
other.mMinimalInsetsSizeInDisplayCutoutSafe);
}
@Override
public int hashCode() {
return Objects.hash(mId, mSource, mFlags, mInsetsSize,
Arrays.hashCode(mInsetsSizeOverrides), mArbitraryRectangle,
mMinimalInsetsSizeInDisplayCutoutSafe);
}
public static final @NonNull Parcelable.Creator<InsetsFrameProvider> CREATOR =
new Parcelable.Creator<>() {
@Override
public InsetsFrameProvider createFromParcel(Parcel in) {
return new InsetsFrameProvider(in);
}
@Override
public InsetsFrameProvider[] newArray(int size) {
return new InsetsFrameProvider[size];
}
};
/**
* Class to describe the insets size to be provided to window with specific window type. If not
* used, same insets size will be sent as instructed in the insetsSize and source.
*
* If the insetsSize of given type is set to {@code null}, the insets source frame will be used
* directly for that window type.
*/
public static class InsetsSizeOverride implements Parcelable {
private final int mWindowType;
private final Insets mInsetsSize;
protected InsetsSizeOverride(Parcel in) {
mWindowType = in.readInt();
mInsetsSize = in.readTypedObject(Insets.CREATOR);
}
public InsetsSizeOverride(int windowType, Insets insetsSize) {
mWindowType = windowType;
mInsetsSize = insetsSize;
}
public int getWindowType() {
return mWindowType;
}
public Insets getInsetsSize() {
return mInsetsSize;
}
public static final Creator<InsetsSizeOverride> CREATOR = new Creator<>() {
@Override
public InsetsSizeOverride createFromParcel(Parcel in) {
return new InsetsSizeOverride(in);
}
@Override
public InsetsSizeOverride[] newArray(int size) {
return new InsetsSizeOverride[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeInt(mWindowType);
out.writeTypedObject(mInsetsSize, flags);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(32);
sb.append("TypedInsetsSize: {");
sb.append("windowType=").append(ViewDebug.intToString(
WindowManager.LayoutParams.class, "type", mWindowType));
sb.append(", insetsSize=").append(mInsetsSize);
sb.append("}");
return sb.toString();
}
@Override
public int hashCode() {
return Objects.hash(mWindowType, mInsetsSize);
}
}
}