• 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.graphics.Matrix;
20 import android.graphics.Rect;
21 import android.view.SurfaceControl.Transaction;
22 
23 import com.android.internal.annotations.VisibleForTesting;
24 
25 import java.util.function.Consumer;
26 
27 /**
28  * Helper class to apply surface transactions in sync with RenderThread.
29  * @hide
30  */
31 public class SyncRtSurfaceTransactionApplier {
32 
33     public static final int FLAG_ALL = 0xffffffff;
34     public static final int FLAG_ALPHA = 1;
35     public static final int FLAG_MATRIX = 1 << 1;
36     public static final int FLAG_WINDOW_CROP = 1 << 2;
37     public static final int FLAG_LAYER = 1 << 3;
38     public static final int FLAG_CORNER_RADIUS = 1 << 4;
39     public static final int FLAG_BACKGROUND_BLUR_RADIUS = 1 << 5;
40     public static final int FLAG_VISIBILITY = 1 << 6;
41 
42     private SurfaceControl mTargetSc;
43     private final ViewRootImpl mTargetViewRootImpl;
44     private final float[] mTmpFloat9 = new float[9];
45 
46     /**
47      * @param targetView The view in the surface that acts as synchronization anchor.
48      */
SyncRtSurfaceTransactionApplier(View targetView)49     public SyncRtSurfaceTransactionApplier(View targetView) {
50         mTargetViewRootImpl = targetView != null ? targetView.getViewRootImpl() : null;
51     }
52 
53     /**
54      * Schedules applying surface parameters on the next frame.
55      *
56      * @param params The surface parameters to apply. DO NOT MODIFY the list after passing into
57      *               this method to avoid synchronization issues.
58      */
scheduleApply(final SurfaceParams... params)59     public void scheduleApply(final SurfaceParams... params) {
60         if (mTargetViewRootImpl == null) {
61             return;
62         }
63         mTargetSc = mTargetViewRootImpl.getRenderSurfaceControl();
64         mTargetViewRootImpl.registerRtFrameCallback(frame -> {
65             if (mTargetSc == null || !mTargetSc.isValid()) {
66                 return;
67             }
68             Transaction t = new Transaction();
69             applyParams(t, frame, params);
70         });
71 
72         // Make sure a frame gets scheduled.
73         mTargetViewRootImpl.getView().invalidate();
74     }
75 
76     /**
77      * Applies surface parameters on the next frame.
78      * @param t transaction to apply all parameters in.
79      * @param frame frame to synchronize to. Set -1 when sync is not required.
80      * @param params The surface parameters to apply. DO NOT MODIFY the list after passing into
81      *               this method to avoid synchronization issues.
82      */
applyParams(Transaction t, long frame, final SurfaceParams... params)83      void applyParams(Transaction t, long frame, final SurfaceParams... params) {
84         for (int i = params.length - 1; i >= 0; i--) {
85             SurfaceParams surfaceParams = params[i];
86             SurfaceControl surface = surfaceParams.surface;
87             if (frame > 0) {
88                 t.deferTransactionUntil(surface, mTargetSc, frame);
89             }
90             applyParams(t, surfaceParams, mTmpFloat9);
91         }
92         t.apply();
93     }
94 
applyParams(Transaction t, SurfaceParams params, float[] tmpFloat9)95     public static void applyParams(Transaction t, SurfaceParams params, float[] tmpFloat9) {
96         if ((params.flags & FLAG_MATRIX) != 0) {
97             t.setMatrix(params.surface, params.matrix, tmpFloat9);
98         }
99         if ((params.flags & FLAG_WINDOW_CROP) != 0) {
100             t.setWindowCrop(params.surface, params.windowCrop);
101         }
102         if ((params.flags & FLAG_ALPHA) != 0) {
103             t.setAlpha(params.surface, params.alpha);
104         }
105         if ((params.flags & FLAG_LAYER) != 0) {
106             t.setLayer(params.surface, params.layer);
107         }
108         if ((params.flags & FLAG_CORNER_RADIUS) != 0) {
109             t.setCornerRadius(params.surface, params.cornerRadius);
110         }
111         if ((params.flags & FLAG_BACKGROUND_BLUR_RADIUS) != 0) {
112             t.setBackgroundBlurRadius(params.surface, params.backgroundBlurRadius);
113         }
114         if ((params.flags & FLAG_VISIBILITY) != 0) {
115             if (params.visible) {
116                 t.show(params.surface);
117             } else {
118                 t.hide(params.surface);
119             }
120         }
121     }
122 
123     /**
124      * Creates an instance of SyncRtSurfaceTransactionApplier, deferring until the target view is
125      * attached if necessary.
126      */
create(final View targetView, final Consumer<SyncRtSurfaceTransactionApplier> callback)127     public static void create(final View targetView,
128             final Consumer<SyncRtSurfaceTransactionApplier> callback) {
129         if (targetView == null) {
130             // No target view, no applier
131             callback.accept(null);
132         } else if (targetView.getViewRootImpl() != null) {
133             // Already attached, we're good to go
134             callback.accept(new SyncRtSurfaceTransactionApplier(targetView));
135         } else {
136             // Haven't been attached before we can get the view root
137             targetView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
138                 @Override
139                 public void onViewAttachedToWindow(View v) {
140                     targetView.removeOnAttachStateChangeListener(this);
141                     callback.accept(new SyncRtSurfaceTransactionApplier(targetView));
142                 }
143 
144                 @Override
145                 public void onViewDetachedFromWindow(View v) {
146                     // Do nothing
147                 }
148             });
149         }
150     }
151 
152     public static class SurfaceParams {
153 
154         public static class Builder {
155             final SurfaceControl surface;
156             int flags;
157             float alpha;
158             float cornerRadius;
159             int backgroundBlurRadius;
160             Matrix matrix;
161             Rect windowCrop;
162             int layer;
163             boolean visible;
164 
165             /**
166              * @param surface The surface to modify.
167              */
Builder(SurfaceControl surface)168             public Builder(SurfaceControl surface) {
169                 this.surface = surface;
170             }
171 
172             /**
173              * @param alpha The alpha value to apply to the surface.
174              * @return this Builder
175              */
withAlpha(float alpha)176             public Builder withAlpha(float alpha) {
177                 this.alpha = alpha;
178                 flags |= FLAG_ALPHA;
179                 return this;
180             }
181 
182             /**
183              * @param matrix The matrix to apply to the surface.
184              * @return this Builder
185              */
withMatrix(Matrix matrix)186             public Builder withMatrix(Matrix matrix) {
187                 this.matrix = matrix;
188                 flags |= FLAG_MATRIX;
189                 return this;
190             }
191 
192             /**
193              * @param windowCrop The window crop to apply to the surface.
194              * @return this Builder
195              */
withWindowCrop(Rect windowCrop)196             public Builder withWindowCrop(Rect windowCrop) {
197                 this.windowCrop = windowCrop;
198                 flags |= FLAG_WINDOW_CROP;
199                 return this;
200             }
201 
202             /**
203              * @param layer The layer to assign the surface.
204              * @return this Builder
205              */
withLayer(int layer)206             public Builder withLayer(int layer) {
207                 this.layer = layer;
208                 flags |= FLAG_LAYER;
209                 return this;
210             }
211 
212             /**
213              * @param radius the Radius for rounded corners to apply to the surface.
214              * @return this Builder
215              */
withCornerRadius(float radius)216             public Builder withCornerRadius(float radius) {
217                 this.cornerRadius = radius;
218                 flags |= FLAG_CORNER_RADIUS;
219                 return this;
220             }
221 
222             /**
223              * @param radius the Radius for blur to apply to the background surfaces.
224              * @return this Builder
225              */
withBackgroundBlur(int radius)226             public Builder withBackgroundBlur(int radius) {
227                 this.backgroundBlurRadius = radius;
228                 flags |= FLAG_BACKGROUND_BLUR_RADIUS;
229                 return this;
230             }
231 
232             /**
233              * @param visible The visibility to apply to the surface.
234              * @return this Builder
235              */
withVisibility(boolean visible)236             public Builder withVisibility(boolean visible) {
237                 this.visible = visible;
238                 flags |= FLAG_VISIBILITY;
239                 return this;
240             }
241 
242             /**
243              * @return a new SurfaceParams instance
244              */
build()245             public SurfaceParams build() {
246                 return new SurfaceParams(surface, flags, alpha, matrix, windowCrop, layer,
247                         cornerRadius, backgroundBlurRadius, visible);
248             }
249         }
250 
SurfaceParams(SurfaceControl surface, int params, float alpha, Matrix matrix, Rect windowCrop, int layer, float cornerRadius, int backgroundBlurRadius, boolean visible)251         private SurfaceParams(SurfaceControl surface, int params, float alpha, Matrix matrix,
252                 Rect windowCrop, int layer, float cornerRadius, int backgroundBlurRadius,
253                 boolean visible) {
254             this.flags = params;
255             this.surface = surface;
256             this.alpha = alpha;
257             this.matrix = new Matrix(matrix);
258             this.windowCrop = new Rect(windowCrop);
259             this.layer = layer;
260             this.cornerRadius = cornerRadius;
261             this.backgroundBlurRadius = backgroundBlurRadius;
262             this.visible = visible;
263         }
264 
265         private final int flags;
266 
267         @VisibleForTesting
268         public final SurfaceControl surface;
269 
270         @VisibleForTesting
271         public final float alpha;
272 
273         @VisibleForTesting
274         public final float cornerRadius;
275 
276         @VisibleForTesting
277         public final int backgroundBlurRadius;
278 
279         @VisibleForTesting
280         public final Matrix matrix;
281 
282         @VisibleForTesting
283         public final Rect windowCrop;
284 
285         @VisibleForTesting
286         public final int layer;
287 
288         public final boolean visible;
289     }
290 }
291