• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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.SuppressLint;
20 import android.graphics.Matrix;
21 import android.graphics.Rect;
22 import android.view.SurfaceControl.Transaction;
23 
24 import com.android.internal.annotations.VisibleForTesting;
25 
26 import java.util.function.Consumer;
27 
28 /**
29  * Helper class to apply surface transactions in sync with RenderThread.
30  * @hide
31  */
32 public class SyncRtSurfaceTransactionApplier {
33 
34     public static final int FLAG_ALL = 0xffffffff;
35     public static final int FLAG_ALPHA = 1;
36     public static final int FLAG_MATRIX = 1 << 1;
37     public static final int FLAG_WINDOW_CROP = 1 << 2;
38     public static final int FLAG_LAYER = 1 << 3;
39     public static final int FLAG_CORNER_RADIUS = 1 << 4;
40     public static final int FLAG_BACKGROUND_BLUR_RADIUS = 1 << 5;
41     public static final int FLAG_VISIBILITY = 1 << 6;
42     public static final int FLAG_TRANSACTION = 1 << 7;
43     public static final int FLAG_EARLY_WAKEUP_START = 1 << 8;
44     public static final int FLAG_EARLY_WAKEUP_END = 1 << 9;
45     public static final int FLAG_OPAQUE = 1 << 10;
46 
47     private SurfaceControl mTargetSc;
48     private final ViewRootImpl mTargetViewRootImpl;
49     private final float[] mTmpFloat9 = new float[9];
50 
51     /**
52      * @param targetView The view in the surface that acts as synchronization anchor.
53      */
SyncRtSurfaceTransactionApplier(View targetView)54     public SyncRtSurfaceTransactionApplier(View targetView) {
55         mTargetViewRootImpl = targetView != null ? targetView.getViewRootImpl() : null;
56     }
57 
58     /**
59      * Schedules applying surface parameters on the next frame.
60      *
61      * @param params The surface parameters to apply.
62      */
scheduleApply(final SurfaceParams... params)63     public void scheduleApply(final SurfaceParams... params) {
64         if (mTargetViewRootImpl == null) {
65             return;
66         }
67         mTargetSc = mTargetViewRootImpl.getSurfaceControl();
68         final Transaction t = new Transaction();
69         applyParams(t, params);
70 
71         mTargetViewRootImpl.registerRtFrameCallback(frame -> {
72             if (mTargetSc != null && mTargetSc.isValid()) {
73                 applyTransaction(t, frame);
74             }
75             // The transaction was either dropped, successfully applied, or merged with a future
76             // transaction, so we can safely release its resources.
77             t.close();
78         });
79 
80         // Make sure a frame gets scheduled.
81         mTargetViewRootImpl.getView().invalidate();
82     }
83 
84     /**
85      * Applies surface parameters on the next frame.
86      * @param t transaction to apply all parameters in.
87      * @param frame frame to synchronize to. Set -1 when sync is not required.
88      * @param params The surface parameters to apply.
89      */
applyParams(Transaction t, final SurfaceParams... params)90      void applyParams(Transaction t, final SurfaceParams... params) {
91         for (int i = params.length - 1; i >= 0; i--) {
92             SurfaceParams surfaceParams = params[i];
93             SurfaceControl surface = surfaceParams.surface;
94             applyParams(t, surfaceParams, mTmpFloat9);
95         }
96     }
97 
applyTransaction(Transaction t, long frame)98     void applyTransaction(Transaction t, long frame) {
99         if (mTargetViewRootImpl != null) {
100             mTargetViewRootImpl.mergeWithNextTransaction(t, frame);
101         } else {
102             t.apply();
103         }
104     }
105 
106     @SuppressLint("MissingPermission")
applyParams(Transaction t, SurfaceParams params, float[] tmpFloat9)107     public static void applyParams(Transaction t, SurfaceParams params, float[] tmpFloat9) {
108         if ((params.flags & FLAG_TRANSACTION) != 0) {
109             t.merge(params.mergeTransaction);
110         }
111 
112         if ((params.flags & FLAG_MATRIX) != 0) {
113             t.setMatrix(params.surface, params.matrix, tmpFloat9);
114         }
115         if ((params.flags & FLAG_WINDOW_CROP) != 0) {
116             t.setWindowCrop(params.surface, params.windowCrop);
117         }
118         if ((params.flags & FLAG_ALPHA) != 0) {
119             t.setAlpha(params.surface, params.alpha);
120         }
121         if ((params.flags & FLAG_LAYER) != 0) {
122             t.setLayer(params.surface, params.layer);
123         }
124         if ((params.flags & FLAG_CORNER_RADIUS) != 0) {
125             t.setCornerRadius(params.surface, params.cornerRadius);
126         }
127         if ((params.flags & FLAG_BACKGROUND_BLUR_RADIUS) != 0) {
128             t.setBackgroundBlurRadius(params.surface, params.backgroundBlurRadius);
129         }
130         if ((params.flags & FLAG_VISIBILITY) != 0) {
131             if (params.visible) {
132                 t.show(params.surface);
133             } else {
134                 t.hide(params.surface);
135             }
136         }
137         if ((params.flags & FLAG_EARLY_WAKEUP_START) != 0) {
138             t.setEarlyWakeupStart();
139         }
140         if ((params.flags & FLAG_EARLY_WAKEUP_END) != 0) {
141             t.setEarlyWakeupEnd();
142         }
143         if ((params.flags & FLAG_OPAQUE) != 0) {
144             t.setOpaque(params.surface, params.opaque);
145         }
146     }
147 
148     /**
149      * Creates an instance of SyncRtSurfaceTransactionApplier, deferring until the target view is
150      * attached if necessary.
151      */
create(final View targetView, final Consumer<SyncRtSurfaceTransactionApplier> callback)152     public static void create(final View targetView,
153             final Consumer<SyncRtSurfaceTransactionApplier> callback) {
154         if (targetView == null) {
155             // No target view, no applier
156             callback.accept(null);
157         } else if (targetView.getViewRootImpl() != null) {
158             // Already attached, we're good to go
159             callback.accept(new SyncRtSurfaceTransactionApplier(targetView));
160         } else {
161             // Haven't been attached before we can get the view root
162             targetView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
163                 @Override
164                 public void onViewAttachedToWindow(View v) {
165                     targetView.removeOnAttachStateChangeListener(this);
166                     callback.accept(new SyncRtSurfaceTransactionApplier(targetView));
167                 }
168 
169                 @Override
170                 public void onViewDetachedFromWindow(View v) {
171                     // Do nothing
172                 }
173             });
174         }
175     }
176 
177     public static class SurfaceParams {
178 
179         public static class Builder {
180             final SurfaceControl surface;
181             int flags;
182             float alpha;
183             float cornerRadius;
184             int backgroundBlurRadius;
185             Matrix matrix;
186             Rect windowCrop;
187             int layer;
188             boolean visible;
189             boolean opaque;
190             Transaction mergeTransaction;
191 
192             /**
193              * @param surface The surface to modify.
194              */
Builder(SurfaceControl surface)195             public Builder(SurfaceControl surface) {
196                 this.surface = surface;
197             }
198 
199             /**
200              * @param alpha The alpha value to apply to the surface.
201              * @return this Builder
202              */
withAlpha(float alpha)203             public Builder withAlpha(float alpha) {
204                 this.alpha = alpha;
205                 flags |= FLAG_ALPHA;
206                 return this;
207             }
208 
209             /**
210              * @param matrix The matrix to apply to the surface.
211              * @return this Builder
212              */
withMatrix(Matrix matrix)213             public Builder withMatrix(Matrix matrix) {
214                 this.matrix = new Matrix(matrix);
215                 flags |= FLAG_MATRIX;
216                 return this;
217             }
218 
219             /**
220              * @param windowCrop The window crop to apply to the surface.
221              * @return this Builder
222              */
withWindowCrop(Rect windowCrop)223             public Builder withWindowCrop(Rect windowCrop) {
224                 this.windowCrop = new Rect(windowCrop);
225                 flags |= FLAG_WINDOW_CROP;
226                 return this;
227             }
228 
229             /**
230              * @param layer The layer to assign the surface.
231              * @return this Builder
232              */
withLayer(int layer)233             public Builder withLayer(int layer) {
234                 this.layer = layer;
235                 flags |= FLAG_LAYER;
236                 return this;
237             }
238 
239             /**
240              * @param radius the Radius for rounded corners to apply to the surface.
241              * @return this Builder
242              */
withCornerRadius(float radius)243             public Builder withCornerRadius(float radius) {
244                 this.cornerRadius = radius;
245                 flags |= FLAG_CORNER_RADIUS;
246                 return this;
247             }
248 
249             /**
250              * @param radius the Radius for blur to apply to the background surfaces.
251              * @return this Builder
252              */
withBackgroundBlur(int radius)253             public Builder withBackgroundBlur(int radius) {
254                 this.backgroundBlurRadius = radius;
255                 flags |= FLAG_BACKGROUND_BLUR_RADIUS;
256                 return this;
257             }
258 
259             /**
260              * @param visible The visibility to apply to the surface.
261              * @return this Builder
262              */
withVisibility(boolean visible)263             public Builder withVisibility(boolean visible) {
264                 this.visible = visible;
265                 flags |= FLAG_VISIBILITY;
266                 return this;
267             }
268 
269             /**
270              * @param mergeTransaction The transaction to apply to the surface. Note this is applied
271              *                         first before all the other properties.
272              * @return this Builder
273              */
withMergeTransaction(Transaction mergeTransaction)274             public Builder withMergeTransaction(Transaction mergeTransaction) {
275                 this.mergeTransaction = mergeTransaction;
276                 flags |= FLAG_TRANSACTION;
277                 return this;
278             }
279 
280             /**
281              * Provides a hint to SurfaceFlinger to change its offset so that SurfaceFlinger
282              * wakes up earlier to compose surfaces.
283              * @return this Builder
284              */
withEarlyWakeupStart()285             public Builder withEarlyWakeupStart() {
286                 flags |= FLAG_EARLY_WAKEUP_START;
287                 return this;
288             }
289 
290             /**
291              * Removes the early wake up hint set by earlyWakeupStart.
292              * @return this Builder
293              */
withEarlyWakeupEnd()294             public Builder withEarlyWakeupEnd() {
295                 flags |= FLAG_EARLY_WAKEUP_END;
296                 return this;
297             }
298 
299             /**
300              * @param opaque Indicates weather the surface must be considered opaque.
301              * @return this Builder
302              */
withOpaque(boolean opaque)303             public Builder withOpaque(boolean opaque) {
304                 this.opaque = opaque;
305                 flags |= FLAG_OPAQUE;
306                 return this;
307             }
308 
309             /**
310              * @return a new SurfaceParams instance
311              */
build()312             public SurfaceParams build() {
313                 return new SurfaceParams(surface, flags, alpha, matrix, windowCrop, layer,
314                         cornerRadius, backgroundBlurRadius, visible, mergeTransaction,
315                         opaque);
316             }
317         }
318 
SurfaceParams(SurfaceControl surface, int params, float alpha, Matrix matrix, Rect windowCrop, int layer, float cornerRadius, int backgroundBlurRadius, boolean visible, Transaction mergeTransaction, boolean opaque)319         private SurfaceParams(SurfaceControl surface, int params, float alpha, Matrix matrix,
320                 Rect windowCrop, int layer, float cornerRadius,
321                 int backgroundBlurRadius, boolean visible,
322                 Transaction mergeTransaction, boolean opaque) {
323             this.flags = params;
324             this.surface = surface;
325             this.alpha = alpha;
326             this.matrix = matrix;
327             this.windowCrop = windowCrop;
328             this.layer = layer;
329             this.cornerRadius = cornerRadius;
330             this.backgroundBlurRadius = backgroundBlurRadius;
331             this.visible = visible;
332             this.mergeTransaction = mergeTransaction;
333             this.opaque = opaque;
334         }
335 
336         private final int flags;
337 
338         @VisibleForTesting
339         public final SurfaceControl surface;
340 
341         @VisibleForTesting
342         public final float alpha;
343 
344         @VisibleForTesting
345         public final float cornerRadius;
346 
347         @VisibleForTesting
348         public final int backgroundBlurRadius;
349 
350         @VisibleForTesting
351         public final Matrix matrix;
352 
353         @VisibleForTesting
354         public final Rect windowCrop;
355 
356         @VisibleForTesting
357         public final int layer;
358 
359         public final boolean visible;
360 
361         public final Transaction mergeTransaction;
362         public final boolean opaque;
363     }
364 }
365