• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 com.android.wm.shell.pip;
18 
19 import android.content.Context;
20 import android.graphics.Matrix;
21 import android.graphics.Rect;
22 import android.graphics.RectF;
23 import android.view.SurfaceControl;
24 
25 import com.android.wm.shell.R;
26 
27 /**
28  * Abstracts the common operations on {@link SurfaceControl.Transaction} for PiP transition.
29  */
30 public class PipSurfaceTransactionHelper {
31     /** for {@link #scale(SurfaceControl.Transaction, SurfaceControl, Rect, Rect)} operation */
32     private final Matrix mTmpTransform = new Matrix();
33     private final float[] mTmpFloat9 = new float[9];
34     private final RectF mTmpSourceRectF = new RectF();
35     private final RectF mTmpDestinationRectF = new RectF();
36     private final Rect mTmpDestinationRect = new Rect();
37 
38     private int mCornerRadius;
39 
40     /**
41      * Called when display size or font size of settings changed
42      *
43      * @param context the current context
44      */
onDensityOrFontScaleChanged(Context context)45     public void onDensityOrFontScaleChanged(Context context) {
46         mCornerRadius = context.getResources().getDimensionPixelSize(R.dimen.pip_corner_radius);
47     }
48 
49     /**
50      * Operates the alpha on a given transaction and leash
51      * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
52      */
alpha(SurfaceControl.Transaction tx, SurfaceControl leash, float alpha)53     public PipSurfaceTransactionHelper alpha(SurfaceControl.Transaction tx, SurfaceControl leash,
54             float alpha) {
55         tx.setAlpha(leash, alpha);
56         return this;
57     }
58 
59     /**
60      * Operates the crop (and position) on a given transaction and leash
61      * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
62      */
crop(SurfaceControl.Transaction tx, SurfaceControl leash, Rect destinationBounds)63     public PipSurfaceTransactionHelper crop(SurfaceControl.Transaction tx, SurfaceControl leash,
64             Rect destinationBounds) {
65         tx.setWindowCrop(leash, destinationBounds.width(), destinationBounds.height())
66                 .setPosition(leash, destinationBounds.left, destinationBounds.top);
67         return this;
68     }
69 
70     /**
71      * Operates the scale (setMatrix) on a given transaction and leash
72      * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
73      */
scale(SurfaceControl.Transaction tx, SurfaceControl leash, Rect sourceBounds, Rect destinationBounds)74     public PipSurfaceTransactionHelper scale(SurfaceControl.Transaction tx, SurfaceControl leash,
75             Rect sourceBounds, Rect destinationBounds) {
76         return scale(tx, leash, sourceBounds, destinationBounds, 0 /* degrees */);
77     }
78 
79     /**
80      * Operates the scale (setMatrix) on a given transaction and leash, along with a rotation.
81      * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
82      */
scale(SurfaceControl.Transaction tx, SurfaceControl leash, Rect sourceBounds, Rect destinationBounds, float degrees)83     public PipSurfaceTransactionHelper scale(SurfaceControl.Transaction tx, SurfaceControl leash,
84             Rect sourceBounds, Rect destinationBounds, float degrees) {
85         mTmpSourceRectF.set(sourceBounds);
86         // We want the matrix to position the surface relative to the screen coordinates so offset
87         // the source to 0,0
88         mTmpSourceRectF.offsetTo(0, 0);
89         mTmpDestinationRectF.set(destinationBounds);
90         mTmpTransform.setRectToRect(mTmpSourceRectF, mTmpDestinationRectF, Matrix.ScaleToFit.FILL);
91         mTmpTransform.postRotate(degrees,
92                 mTmpDestinationRectF.centerX(), mTmpDestinationRectF.centerY());
93         tx.setMatrix(leash, mTmpTransform, mTmpFloat9);
94         return this;
95     }
96 
97     /**
98      * Operates the scale (setMatrix) on a given transaction and leash
99      * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
100      */
scaleAndCrop(SurfaceControl.Transaction tx, SurfaceControl leash, Rect sourceBounds, Rect destinationBounds, Rect insets)101     public PipSurfaceTransactionHelper scaleAndCrop(SurfaceControl.Transaction tx,
102             SurfaceControl leash,
103             Rect sourceBounds, Rect destinationBounds, Rect insets) {
104         mTmpSourceRectF.set(sourceBounds);
105         mTmpDestinationRect.set(sourceBounds);
106         mTmpDestinationRect.inset(insets);
107         // Scale by the shortest edge and offset such that the top/left of the scaled inset source
108         // rect aligns with the top/left of the destination bounds
109         final float scale = sourceBounds.width() <= sourceBounds.height()
110                 ? (float) destinationBounds.width() / sourceBounds.width()
111                 : (float) destinationBounds.height() / sourceBounds.height();
112         final float left = destinationBounds.left - insets.left * scale;
113         final float top = destinationBounds.top - insets.top * scale;
114         mTmpTransform.setScale(scale, scale);
115         tx.setMatrix(leash, mTmpTransform, mTmpFloat9)
116                 .setWindowCrop(leash, mTmpDestinationRect)
117                 .setPosition(leash, left, top);
118         return this;
119     }
120 
121     /**
122      * Operates the rotation according to the given degrees and scale (setMatrix) according to the
123      * source bounds and rotated destination bounds. The crop will be the unscaled source bounds.
124      * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
125      */
rotateAndScaleWithCrop(SurfaceControl.Transaction tx, SurfaceControl leash, Rect sourceBounds, Rect destinationBounds, Rect insets, float degrees, float positionX, float positionY, boolean isExpanding, boolean clockwise)126     public PipSurfaceTransactionHelper rotateAndScaleWithCrop(SurfaceControl.Transaction tx,
127             SurfaceControl leash, Rect sourceBounds, Rect destinationBounds, Rect insets,
128             float degrees, float positionX, float positionY, boolean isExpanding,
129             boolean clockwise) {
130         mTmpDestinationRect.set(sourceBounds);
131         mTmpDestinationRect.inset(insets);
132         final int srcW = mTmpDestinationRect.width();
133         final int srcH = mTmpDestinationRect.height();
134         final int destW = destinationBounds.width();
135         final int destH = destinationBounds.height();
136         // Scale by the short side so there won't be empty area if the aspect ratio of source and
137         // destination are different.
138         final float scale = srcW <= srcH ? (float) destW / srcW : (float) destH / srcH;
139         final Rect crop = mTmpDestinationRect;
140         crop.set(0, 0, destW, destH);
141         // Inverse scale for crop to fit in screen coordinates.
142         crop.scale(1 / scale);
143         crop.offset(insets.left, insets.top);
144         if (isExpanding) {
145             // Expand bounds (shrink insets) in source orientation.
146             positionX -= insets.left * scale;
147             positionY -= insets.top * scale;
148         } else {
149             // Shrink bounds (expand insets) in destination orientation.
150             if (clockwise) {
151                 positionX -= insets.top * scale;
152                 positionY += insets.left * scale;
153             } else {
154                 positionX += insets.top * scale;
155                 positionY -= insets.left * scale;
156             }
157         }
158         mTmpTransform.setScale(scale, scale);
159         mTmpTransform.postRotate(degrees);
160         mTmpTransform.postTranslate(positionX, positionY);
161         tx.setMatrix(leash, mTmpTransform, mTmpFloat9).setWindowCrop(leash, crop);
162         return this;
163     }
164 
165     /**
166      * Resets the scale (setMatrix) on a given transaction and leash if there's any
167      *
168      * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
169      */
resetScale(SurfaceControl.Transaction tx, SurfaceControl leash, Rect destinationBounds)170     public PipSurfaceTransactionHelper resetScale(SurfaceControl.Transaction tx,
171             SurfaceControl leash,
172             Rect destinationBounds) {
173         tx.setMatrix(leash, Matrix.IDENTITY_MATRIX, mTmpFloat9)
174                 .setPosition(leash, destinationBounds.left, destinationBounds.top);
175         return this;
176     }
177 
178     /**
179      * Operates the round corner radius on a given transaction and leash
180      * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
181      */
round(SurfaceControl.Transaction tx, SurfaceControl leash, boolean applyCornerRadius)182     public PipSurfaceTransactionHelper round(SurfaceControl.Transaction tx, SurfaceControl leash,
183             boolean applyCornerRadius) {
184         tx.setCornerRadius(leash, applyCornerRadius ? mCornerRadius : 0);
185         return this;
186     }
187 
188     /**
189      * Operates the round corner radius on a given transaction and leash, scaled by bounds
190      * @return same {@link PipSurfaceTransactionHelper} instance for method chaining
191      */
round(SurfaceControl.Transaction tx, SurfaceControl leash, Rect fromBounds, Rect toBounds)192     public PipSurfaceTransactionHelper round(SurfaceControl.Transaction tx, SurfaceControl leash,
193             Rect fromBounds, Rect toBounds) {
194         final float scale = (float) (Math.hypot(fromBounds.width(), fromBounds.height())
195                 / Math.hypot(toBounds.width(), toBounds.height()));
196         tx.setCornerRadius(leash, mCornerRadius * scale);
197         return this;
198     }
199 
200     /**
201      * Re-parents the snapshot to the parent's surface control and shows it.
202      */
reparentAndShowSurfaceSnapshot( SurfaceControl.Transaction t, SurfaceControl parent, SurfaceControl snapshot)203     public PipSurfaceTransactionHelper reparentAndShowSurfaceSnapshot(
204             SurfaceControl.Transaction t, SurfaceControl parent, SurfaceControl snapshot) {
205         t.reparent(snapshot, parent);
206         t.setLayer(snapshot, Integer.MAX_VALUE);
207         t.show(snapshot);
208         t.apply();
209         return this;
210     }
211 
212     public interface SurfaceControlTransactionFactory {
getTransaction()213         SurfaceControl.Transaction getTransaction();
214     }
215 }
216