1 /*
2  * Copyright (C) 2021 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.window;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.graphics.Matrix;
22 import android.graphics.PointF;
23 import android.graphics.Rect;
24 import android.os.Parcel;
25 import android.os.Parcelable;
26 import android.view.SurfaceControl;
27 
28 import java.util.Arrays;
29 import java.util.Objects;
30 
31 /**
32  * Represents a set of {@link android.view.SurfaceControl.Transaction} operations used to
33  * operate on the {@link android.view.SurfaceControl} for picture-in-picture.
34  *
35  * @hide
36  */
37 public final class PictureInPictureSurfaceTransaction implements Parcelable {
38     private static final float NOT_SET = -1f;
39 
40     public final float mAlpha;
41     public final PointF mPosition;
42 
43     public final float[] mFloat9;
44 
45     // Though this can be determined by mFloat9, it's easier to set the value directly
46     public final float mRotation;
47 
48     public final float mCornerRadius;
49 
50     private final Rect mWindowCrop;
51 
PictureInPictureSurfaceTransaction(Parcel in)52     private PictureInPictureSurfaceTransaction(Parcel in) {
53         mAlpha = in.readFloat();
54         mPosition = in.readTypedObject(PointF.CREATOR);
55         mFloat9 = new float[9];
56         in.readFloatArray(mFloat9);
57         mRotation = in.readFloat();
58         mCornerRadius = in.readFloat();
59         mWindowCrop = in.readTypedObject(Rect.CREATOR);
60     }
61 
PictureInPictureSurfaceTransaction(float alpha, @Nullable PointF position, @Nullable float[] float9, float rotation, float cornerRadius, @Nullable Rect windowCrop)62     private PictureInPictureSurfaceTransaction(float alpha, @Nullable PointF position,
63             @Nullable float[] float9, float rotation, float cornerRadius,
64             @Nullable Rect windowCrop) {
65         mAlpha = alpha;
66         mPosition = position;
67         if (float9 == null) {
68             mFloat9 = new float[9];
69             Matrix.IDENTITY_MATRIX.getValues(mFloat9);
70             mRotation = 0;
71         } else {
72             mFloat9 = Arrays.copyOf(float9, 9);
73             mRotation = rotation;
74         }
75         mCornerRadius = cornerRadius;
76         mWindowCrop = (windowCrop == null) ? null : new Rect(windowCrop);
77     }
78 
PictureInPictureSurfaceTransaction(PictureInPictureSurfaceTransaction other)79     public PictureInPictureSurfaceTransaction(PictureInPictureSurfaceTransaction other) {
80         this(other.mAlpha, other.mPosition,
81                 other.mFloat9, other.mRotation, other.mCornerRadius, other.mWindowCrop);
82     }
83 
84     /** @return {@link Matrix} from {@link #mFloat9} */
getMatrix()85     public Matrix getMatrix() {
86         final Matrix matrix = new Matrix();
87         matrix.setValues(mFloat9);
88         return matrix;
89     }
90 
91     /** @return {@code true} if this transaction contains setting corner radius. */
hasCornerRadiusSet()92     public boolean hasCornerRadiusSet() {
93         return mCornerRadius > 0;
94     }
95 
96     @Override
equals(Object o)97     public boolean equals(Object o) {
98         if (this == o) return true;
99         if (!(o instanceof PictureInPictureSurfaceTransaction)) return false;
100         PictureInPictureSurfaceTransaction that = (PictureInPictureSurfaceTransaction) o;
101         return Objects.equals(mAlpha, that.mAlpha)
102                 && Objects.equals(mPosition, that.mPosition)
103                 && Arrays.equals(mFloat9, that.mFloat9)
104                 && Objects.equals(mRotation, that.mRotation)
105                 && Objects.equals(mCornerRadius, that.mCornerRadius)
106                 && Objects.equals(mWindowCrop, that.mWindowCrop);
107     }
108 
109     @Override
hashCode()110     public int hashCode() {
111         return Objects.hash(mAlpha, mPosition, Arrays.hashCode(mFloat9),
112                 mRotation, mCornerRadius, mWindowCrop);
113     }
114 
115     @Override
describeContents()116     public int describeContents() {
117         return 0;
118     }
119 
120     @Override
writeToParcel(Parcel out, int flags)121     public void writeToParcel(Parcel out, int flags) {
122         out.writeFloat(mAlpha);
123         out.writeTypedObject(mPosition, 0 /* flags */);
124         out.writeFloatArray(mFloat9);
125         out.writeFloat(mRotation);
126         out.writeFloat(mCornerRadius);
127         out.writeTypedObject(mWindowCrop, 0 /* flags */);
128     }
129 
130     @Override
toString()131     public String toString() {
132         final Matrix matrix = getMatrix();
133         return "PictureInPictureSurfaceTransaction("
134                 + " alpha=" + mAlpha
135                 + " position=" + mPosition
136                 + " matrix=" + matrix.toShortString()
137                 + " rotation=" + mRotation
138                 + " cornerRadius=" + mCornerRadius
139                 + " crop=" + mWindowCrop
140                 + ")";
141     }
142 
143     /** Applies {@link PictureInPictureSurfaceTransaction} to a given leash. */
apply(@onNull PictureInPictureSurfaceTransaction surfaceTransaction, @NonNull SurfaceControl surfaceControl, @NonNull SurfaceControl.Transaction tx)144     public static void apply(@NonNull PictureInPictureSurfaceTransaction surfaceTransaction,
145             @NonNull SurfaceControl surfaceControl,
146             @NonNull SurfaceControl.Transaction tx) {
147         final Matrix matrix = surfaceTransaction.getMatrix();
148         tx.setMatrix(surfaceControl, matrix, new float[9]);
149         if (surfaceTransaction.mPosition != null) {
150             tx.setPosition(surfaceControl,
151                     surfaceTransaction.mPosition.x, surfaceTransaction.mPosition.y);
152         }
153         if (surfaceTransaction.mWindowCrop != null) {
154             tx.setWindowCrop(surfaceControl, surfaceTransaction.mWindowCrop);
155         }
156         if (surfaceTransaction.hasCornerRadiusSet()) {
157             tx.setCornerRadius(surfaceControl, surfaceTransaction.mCornerRadius);
158         }
159         if (surfaceTransaction.mAlpha != NOT_SET) {
160             tx.setAlpha(surfaceControl, surfaceTransaction.mAlpha);
161         }
162     }
163 
164     public static final @android.annotation.NonNull Creator<PictureInPictureSurfaceTransaction>
165             CREATOR =
166             new Creator<PictureInPictureSurfaceTransaction>() {
167                 public PictureInPictureSurfaceTransaction createFromParcel(Parcel in) {
168                     return new PictureInPictureSurfaceTransaction(in);
169                 }
170                 public PictureInPictureSurfaceTransaction[] newArray(int size) {
171                     return new PictureInPictureSurfaceTransaction[size];
172                 }
173             };
174 
175     public static class Builder {
176         private float mAlpha = NOT_SET;
177         private PointF mPosition;
178         private float[] mFloat9;
179         private float mRotation;
180         private float mCornerRadius = NOT_SET;
181         private Rect mWindowCrop;
182 
setAlpha(float alpha)183         public Builder setAlpha(float alpha) {
184             mAlpha = alpha;
185             return this;
186         }
187 
setPosition(float x, float y)188         public Builder setPosition(float x, float y) {
189             mPosition = new PointF(x, y);
190             return this;
191         }
192 
setTransform(@onNull float[] float9, float rotation)193         public Builder setTransform(@NonNull float[] float9, float rotation) {
194             mFloat9 = Arrays.copyOf(float9, 9);
195             mRotation = rotation;
196             return this;
197         }
198 
setCornerRadius(float cornerRadius)199         public Builder setCornerRadius(float cornerRadius) {
200             mCornerRadius = cornerRadius;
201             return this;
202         }
203 
setWindowCrop(@onNull Rect windowCrop)204         public Builder setWindowCrop(@NonNull Rect windowCrop) {
205             mWindowCrop = new Rect(windowCrop);
206             return this;
207         }
208 
build()209         public PictureInPictureSurfaceTransaction build() {
210             return new PictureInPictureSurfaceTransaction(mAlpha, mPosition,
211                     mFloat9, mRotation, mCornerRadius, mWindowCrop);
212         }
213     }
214 }
215