blob: 9c97f3e5b503c45a9bd9cf9704a1e41d4a89536f [file] [log] [blame]
Jorim Jaggi64be98d2018-04-26 23:23:29 +02001/*
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
Jorim Jaggi5bb571d2018-11-06 14:42:04 +010014 * limitations under the License.
Jorim Jaggi64be98d2018-04-26 23:23:29 +020015 */
16
Jorim Jaggi5bb571d2018-11-06 14:42:04 +010017package android.view;
Jorim Jaggi64be98d2018-04-26 23:23:29 +020018
19import android.graphics.Matrix;
20import android.graphics.Rect;
Jorim Jaggicd560732018-05-29 16:29:24 +020021import android.view.SurfaceControl.Transaction;
Jorim Jaggi5bb571d2018-11-06 14:42:04 +010022
23import com.android.internal.annotations.VisibleForTesting;
Jorim Jaggi64be98d2018-04-26 23:23:29 +020024
Winson Chung71eda582018-12-11 12:54:36 -080025import java.util.function.Consumer;
26
Jorim Jaggi64be98d2018-04-26 23:23:29 +020027/**
28 * Helper class to apply surface transactions in sync with RenderThread.
Jorim Jaggi5bb571d2018-11-06 14:42:04 +010029 * @hide
Jorim Jaggi64be98d2018-04-26 23:23:29 +020030 */
31public class SyncRtSurfaceTransactionApplier {
32
Mark Renoufdf0f3bc2019-09-16 14:04:38 -040033 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;
Winson Chung7e895da2020-02-03 13:28:44 -080039 public static final int FLAG_BACKGROUND_BLUR_RADIUS = 1 << 5;
40 public static final int FLAG_VISIBILITY = 1 << 6;
Mark Renoufdf0f3bc2019-09-16 14:04:38 -040041
Robert Carrcef9a282020-01-14 09:08:05 -080042 private SurfaceControl mTargetSc;
Jorim Jaggi64be98d2018-04-26 23:23:29 +020043 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 */
49 public SyncRtSurfaceTransactionApplier(View targetView) {
50 mTargetViewRootImpl = targetView != null ? targetView.getViewRootImpl() : null;
Jorim Jaggi64be98d2018-04-26 23:23:29 +020051 }
52
53 /**
54 * Schedules applying surface parameters on the next frame.
55 *
Jorim Jaggi33a35ef2020-03-10 00:47:12 +010056 * @param earlyWakeup Whether to set {@link Transaction#setEarlyWakeup()} on transaction.
Jorim Jaggi64be98d2018-04-26 23:23:29 +020057 * @param params The surface parameters to apply. DO NOT MODIFY the list after passing into
58 * this method to avoid synchronization issues.
59 */
Jorim Jaggi33a35ef2020-03-10 00:47:12 +010060 public void scheduleApply(boolean earlyWakeup, final SurfaceParams... params) {
Jorim Jaggi2d39fb92018-05-16 14:37:02 -070061 if (mTargetViewRootImpl == null) {
62 return;
Jorim Jaggi64be98d2018-04-26 23:23:29 +020063 }
Robert Carrcef9a282020-01-14 09:08:05 -080064 mTargetSc = mTargetViewRootImpl.getRenderSurfaceControl();
Jorim Jaggi5bb571d2018-11-06 14:42:04 +010065 mTargetViewRootImpl.registerRtFrameCallback(frame -> {
Robert Carrcef9a282020-01-14 09:08:05 -080066 if (mTargetSc == null || !mTargetSc.isValid()) {
Jorim Jaggi5bb571d2018-11-06 14:42:04 +010067 return;
Sunny Goyalbba378e2018-08-22 12:50:26 -070068 }
Jorim Jaggi5bb571d2018-11-06 14:42:04 +010069 Transaction t = new Transaction();
Jorim Jaggi33a35ef2020-03-10 00:47:12 +010070 applyParams(t, frame, earlyWakeup, params);
Jorim Jaggi2d39fb92018-05-16 14:37:02 -070071 });
Jorim Jaggi42b04752018-05-18 18:23:08 +020072
73 // Make sure a frame gets scheduled.
74 mTargetViewRootImpl.getView().invalidate();
Jorim Jaggi64be98d2018-04-26 23:23:29 +020075 }
76
Tarandeep Singh7eb2bed2020-02-11 14:55:28 -080077 /**
78 * Applies surface parameters on the next frame.
79 * @param t transaction to apply all parameters in.
80 * @param frame frame to synchronize to. Set -1 when sync is not required.
Jorim Jaggi33a35ef2020-03-10 00:47:12 +010081 * @param earlyWakeup Whether to set {@link Transaction#setEarlyWakeup()} on transaction.
Tarandeep Singh7eb2bed2020-02-11 14:55:28 -080082 * @param params The surface parameters to apply. DO NOT MODIFY the list after passing into
83 * this method to avoid synchronization issues.
84 */
Jorim Jaggi33a35ef2020-03-10 00:47:12 +010085 void applyParams(Transaction t, long frame, boolean earlyWakeup,
86 final SurfaceParams... params) {
Tarandeep Singh7eb2bed2020-02-11 14:55:28 -080087 for (int i = params.length - 1; i >= 0; i--) {
88 SurfaceParams surfaceParams = params[i];
89 SurfaceControl surface = surfaceParams.surface;
90 if (frame > 0) {
91 t.deferTransactionUntil(surface, mTargetSc, frame);
92 }
93 applyParams(t, surfaceParams, mTmpFloat9);
94 }
Jorim Jaggi33a35ef2020-03-10 00:47:12 +010095 if (earlyWakeup) {
96 t.setEarlyWakeup();
97 }
Tarandeep Singh7eb2bed2020-02-11 14:55:28 -080098 t.apply();
99 }
100
Jorim Jaggi5bb571d2018-11-06 14:42:04 +0100101 public static void applyParams(Transaction t, SurfaceParams params, float[] tmpFloat9) {
Mark Renoufdf0f3bc2019-09-16 14:04:38 -0400102 if ((params.flags & FLAG_MATRIX) != 0) {
103 t.setMatrix(params.surface, params.matrix, tmpFloat9);
104 }
105 if ((params.flags & FLAG_WINDOW_CROP) != 0) {
106 t.setWindowCrop(params.surface, params.windowCrop);
107 }
108 if ((params.flags & FLAG_ALPHA) != 0) {
109 t.setAlpha(params.surface, params.alpha);
110 }
111 if ((params.flags & FLAG_LAYER) != 0) {
112 t.setLayer(params.surface, params.layer);
113 }
114 if ((params.flags & FLAG_CORNER_RADIUS) != 0) {
115 t.setCornerRadius(params.surface, params.cornerRadius);
116 }
Winson Chung7e895da2020-02-03 13:28:44 -0800117 if ((params.flags & FLAG_BACKGROUND_BLUR_RADIUS) != 0) {
118 t.setBackgroundBlurRadius(params.surface, params.backgroundBlurRadius);
119 }
Mark Renoufdf0f3bc2019-09-16 14:04:38 -0400120 if ((params.flags & FLAG_VISIBILITY) != 0) {
121 if (params.visible) {
122 t.show(params.surface);
123 } else {
124 t.hide(params.surface);
125 }
Jorim Jaggi67684882019-01-22 17:36:34 +0100126 }
Jorim Jaggicd560732018-05-29 16:29:24 +0200127 }
128
Winson Chung71eda582018-12-11 12:54:36 -0800129 /**
130 * Creates an instance of SyncRtSurfaceTransactionApplier, deferring until the target view is
131 * attached if necessary.
132 */
133 public static void create(final View targetView,
134 final Consumer<SyncRtSurfaceTransactionApplier> callback) {
135 if (targetView == null) {
136 // No target view, no applier
137 callback.accept(null);
138 } else if (targetView.getViewRootImpl() != null) {
139 // Already attached, we're good to go
140 callback.accept(new SyncRtSurfaceTransactionApplier(targetView));
141 } else {
142 // Haven't been attached before we can get the view root
143 targetView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
144 @Override
145 public void onViewAttachedToWindow(View v) {
146 targetView.removeOnAttachStateChangeListener(this);
147 callback.accept(new SyncRtSurfaceTransactionApplier(targetView));
148 }
149
150 @Override
151 public void onViewDetachedFromWindow(View v) {
152 // Do nothing
153 }
154 });
155 }
156 }
157
Jorim Jaggi64be98d2018-04-26 23:23:29 +0200158 public static class SurfaceParams {
159
Mark Renoufdf0f3bc2019-09-16 14:04:38 -0400160 public static class Builder {
161 final SurfaceControl surface;
162 int flags;
163 float alpha;
164 float cornerRadius;
Winson Chung7e895da2020-02-03 13:28:44 -0800165 int backgroundBlurRadius;
Mark Renoufdf0f3bc2019-09-16 14:04:38 -0400166 Matrix matrix;
167 Rect windowCrop;
168 int layer;
169 boolean visible;
170
171 /**
172 * @param surface The surface to modify.
173 */
174 public Builder(SurfaceControl surface) {
175 this.surface = surface;
176 }
177
178 /**
179 * @param alpha The alpha value to apply to the surface.
180 * @return this Builder
181 */
182 public Builder withAlpha(float alpha) {
183 this.alpha = alpha;
184 flags |= FLAG_ALPHA;
185 return this;
186 }
187
188 /**
189 * @param matrix The matrix to apply to the surface.
190 * @return this Builder
191 */
192 public Builder withMatrix(Matrix matrix) {
193 this.matrix = matrix;
194 flags |= FLAG_MATRIX;
195 return this;
196 }
197
198 /**
199 * @param windowCrop The window crop to apply to the surface.
200 * @return this Builder
201 */
202 public Builder withWindowCrop(Rect windowCrop) {
203 this.windowCrop = windowCrop;
204 flags |= FLAG_WINDOW_CROP;
205 return this;
206 }
207
208 /**
209 * @param layer The layer to assign the surface.
210 * @return this Builder
211 */
212 public Builder withLayer(int layer) {
213 this.layer = layer;
214 flags |= FLAG_LAYER;
215 return this;
216 }
217
218 /**
219 * @param radius the Radius for rounded corners to apply to the surface.
220 * @return this Builder
221 */
222 public Builder withCornerRadius(float radius) {
223 this.cornerRadius = radius;
224 flags |= FLAG_CORNER_RADIUS;
225 return this;
226 }
227
228 /**
Winson Chung7e895da2020-02-03 13:28:44 -0800229 * @param radius the Radius for blur to apply to the background surfaces.
230 * @return this Builder
231 */
232 public Builder withBackgroundBlur(int radius) {
233 this.backgroundBlurRadius = radius;
234 flags |= FLAG_BACKGROUND_BLUR_RADIUS;
235 return this;
236 }
237
238 /**
Mark Renoufdf0f3bc2019-09-16 14:04:38 -0400239 * @param visible The visibility to apply to the surface.
240 * @return this Builder
241 */
242 public Builder withVisibility(boolean visible) {
243 this.visible = visible;
244 flags |= FLAG_VISIBILITY;
245 return this;
246 }
247
248 /**
249 * @return a new SurfaceParams instance
250 */
251 public SurfaceParams build() {
252 return new SurfaceParams(surface, flags, alpha, matrix, windowCrop, layer,
Winson Chung7e895da2020-02-03 13:28:44 -0800253 cornerRadius, backgroundBlurRadius, visible);
Mark Renoufdf0f3bc2019-09-16 14:04:38 -0400254 }
255 }
256
257 private SurfaceParams(SurfaceControl surface, int params, float alpha, Matrix matrix,
Winson Chung7e895da2020-02-03 13:28:44 -0800258 Rect windowCrop, int layer, float cornerRadius, int backgroundBlurRadius,
259 boolean visible) {
Mark Renoufdf0f3bc2019-09-16 14:04:38 -0400260 this.flags = params;
Jorim Jaggi5bb571d2018-11-06 14:42:04 +0100261 this.surface = surface;
Jorim Jaggi64be98d2018-04-26 23:23:29 +0200262 this.alpha = alpha;
263 this.matrix = new Matrix(matrix);
264 this.windowCrop = new Rect(windowCrop);
265 this.layer = layer;
Lucas Dupin086c6fc2018-10-16 18:06:43 -0700266 this.cornerRadius = cornerRadius;
Winson Chung7e895da2020-02-03 13:28:44 -0800267 this.backgroundBlurRadius = backgroundBlurRadius;
Mark Renoufdf0f3bc2019-09-16 14:04:38 -0400268 this.visible = visible;
269 }
270
271 private final int flags;
272
Jorim Jaggi5bb571d2018-11-06 14:42:04 +0100273 @VisibleForTesting
274 public final SurfaceControl surface;
275
276 @VisibleForTesting
277 public final float alpha;
278
279 @VisibleForTesting
Winson Chung7e895da2020-02-03 13:28:44 -0800280 public final float cornerRadius;
281
282 @VisibleForTesting
283 public final int backgroundBlurRadius;
Jorim Jaggi5bb571d2018-11-06 14:42:04 +0100284
285 @VisibleForTesting
286 public final Matrix matrix;
287
288 @VisibleForTesting
289 public final Rect windowCrop;
290
291 @VisibleForTesting
292 public final int layer;
Jorim Jaggi67684882019-01-22 17:36:34 +0100293
294 public final boolean visible;
Jorim Jaggi64be98d2018-04-26 23:23:29 +0200295 }
296}