/* * Copyright (C) 2021 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.window; import android.annotation.NonNull; import android.annotation.Nullable; import android.graphics.Matrix; import android.graphics.PointF; import android.graphics.Rect; import android.os.Parcel; import android.os.Parcelable; import android.view.SurfaceControl; import java.util.Arrays; import java.util.Objects; /** * Represents a set of {@link android.view.SurfaceControl.Transaction} operations used to * operate on the {@link android.view.SurfaceControl} for picture-in-picture. * * @hide */ public final class PictureInPictureSurfaceTransaction implements Parcelable { private static final float NOT_SET = -1f; public final float mAlpha; public final PointF mPosition; public final float[] mFloat9; // Though this can be determined by mFloat9, it's easier to set the value directly public final float mRotation; public final float mCornerRadius; public final float mShadowRadius; private final Rect mWindowCrop; private boolean mShouldDisableCanAffectSystemUiFlags; private PictureInPictureSurfaceTransaction(Parcel in) { mAlpha = in.readFloat(); mPosition = in.readTypedObject(PointF.CREATOR); mFloat9 = new float[9]; in.readFloatArray(mFloat9); mRotation = in.readFloat(); mCornerRadius = in.readFloat(); mShadowRadius = in.readFloat(); mWindowCrop = in.readTypedObject(Rect.CREATOR); mShouldDisableCanAffectSystemUiFlags = in.readBoolean(); } private PictureInPictureSurfaceTransaction(float alpha, @Nullable PointF position, @Nullable float[] float9, float rotation, float cornerRadius, float shadowRadius, @Nullable Rect windowCrop) { mAlpha = alpha; mPosition = position; if (float9 == null) { mFloat9 = new float[9]; Matrix.IDENTITY_MATRIX.getValues(mFloat9); mRotation = 0; } else { mFloat9 = Arrays.copyOf(float9, 9); mRotation = rotation; } mCornerRadius = cornerRadius; mShadowRadius = shadowRadius; mWindowCrop = (windowCrop == null) ? null : new Rect(windowCrop); } public PictureInPictureSurfaceTransaction(PictureInPictureSurfaceTransaction other) { this(other.mAlpha, other.mPosition, other.mFloat9, other.mRotation, other.mCornerRadius, other.mShadowRadius, other.mWindowCrop); mShouldDisableCanAffectSystemUiFlags = other.mShouldDisableCanAffectSystemUiFlags; } /** @return {@link Matrix} from {@link #mFloat9} */ public Matrix getMatrix() { final Matrix matrix = new Matrix(); matrix.setValues(mFloat9); return matrix; } /** @return {@code true} if this transaction contains setting corner radius. */ public boolean hasCornerRadiusSet() { return mCornerRadius > 0; } /** @return {@code true} if this transaction contains setting shadow radius. */ public boolean hasShadowRadiusSet() { return mShadowRadius > 0; } /** Sets the internal {@link #mShouldDisableCanAffectSystemUiFlags}. */ public void setShouldDisableCanAffectSystemUiFlags(boolean shouldDisable) { mShouldDisableCanAffectSystemUiFlags = shouldDisable; } /** @return {@code true} if we should disable Task#setCanAffectSystemUiFlags. */ public boolean getShouldDisableCanAffectSystemUiFlags() { return mShouldDisableCanAffectSystemUiFlags; } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof PictureInPictureSurfaceTransaction)) return false; PictureInPictureSurfaceTransaction that = (PictureInPictureSurfaceTransaction) o; return Objects.equals(mAlpha, that.mAlpha) && Objects.equals(mPosition, that.mPosition) && Arrays.equals(mFloat9, that.mFloat9) && Objects.equals(mRotation, that.mRotation) && Objects.equals(mCornerRadius, that.mCornerRadius) && Objects.equals(mShadowRadius, that.mShadowRadius) && Objects.equals(mWindowCrop, that.mWindowCrop) && mShouldDisableCanAffectSystemUiFlags == that.mShouldDisableCanAffectSystemUiFlags; } @Override public int hashCode() { return Objects.hash(mAlpha, mPosition, Arrays.hashCode(mFloat9), mRotation, mCornerRadius, mShadowRadius, mWindowCrop, mShouldDisableCanAffectSystemUiFlags); } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel out, int flags) { out.writeFloat(mAlpha); out.writeTypedObject(mPosition, 0 /* flags */); out.writeFloatArray(mFloat9); out.writeFloat(mRotation); out.writeFloat(mCornerRadius); out.writeFloat(mShadowRadius); out.writeTypedObject(mWindowCrop, 0 /* flags */); out.writeBoolean(mShouldDisableCanAffectSystemUiFlags); } @Override public String toString() { final Matrix matrix = getMatrix(); return "PictureInPictureSurfaceTransaction(" + " alpha=" + mAlpha + " position=" + mPosition + " matrix=" + matrix.toShortString() + " rotation=" + mRotation + " cornerRadius=" + mCornerRadius + " shadowRadius=" + mShadowRadius + " crop=" + mWindowCrop + " shouldDisableCanAffectSystemUiFlags" + mShouldDisableCanAffectSystemUiFlags + ")"; } /** Applies {@link PictureInPictureSurfaceTransaction} to a given leash. */ public static void apply(@NonNull PictureInPictureSurfaceTransaction surfaceTransaction, @NonNull SurfaceControl surfaceControl, @NonNull SurfaceControl.Transaction tx) { final Matrix matrix = surfaceTransaction.getMatrix(); tx.setMatrix(surfaceControl, matrix, new float[9]); if (surfaceTransaction.mPosition != null) { tx.setPosition(surfaceControl, surfaceTransaction.mPosition.x, surfaceTransaction.mPosition.y); } if (surfaceTransaction.mWindowCrop != null) { tx.setWindowCrop(surfaceControl, surfaceTransaction.mWindowCrop); } if (surfaceTransaction.hasCornerRadiusSet()) { tx.setCornerRadius(surfaceControl, surfaceTransaction.mCornerRadius); } if (surfaceTransaction.hasShadowRadiusSet()) { tx.setShadowRadius(surfaceControl, surfaceTransaction.mShadowRadius); } if (surfaceTransaction.mAlpha != NOT_SET) { tx.setAlpha(surfaceControl, surfaceTransaction.mAlpha); } } public static final @android.annotation.NonNull Creator CREATOR = new Creator() { public PictureInPictureSurfaceTransaction createFromParcel(Parcel in) { return new PictureInPictureSurfaceTransaction(in); } public PictureInPictureSurfaceTransaction[] newArray(int size) { return new PictureInPictureSurfaceTransaction[size]; } }; public static class Builder { private float mAlpha = NOT_SET; private PointF mPosition; private float[] mFloat9; private float mRotation; private float mCornerRadius = NOT_SET; private float mShadowRadius = NOT_SET; private Rect mWindowCrop; public Builder setAlpha(float alpha) { mAlpha = alpha; return this; } public Builder setPosition(float x, float y) { mPosition = new PointF(x, y); return this; } public Builder setTransform(@NonNull float[] float9, float rotation) { mFloat9 = Arrays.copyOf(float9, 9); mRotation = rotation; return this; } public Builder setCornerRadius(float cornerRadius) { mCornerRadius = cornerRadius; return this; } public Builder setShadowRadius(float shadowRadius) { mShadowRadius = shadowRadius; return this; } public Builder setWindowCrop(@NonNull Rect windowCrop) { mWindowCrop = new Rect(windowCrop); return this; } public PictureInPictureSurfaceTransaction build() { return new PictureInPictureSurfaceTransaction(mAlpha, mPosition, mFloat9, mRotation, mCornerRadius, mShadowRadius, mWindowCrop); } } }