File: SyncRtSurfaceTransactionApplier.java

package info (click to toggle)
android-platform-frameworks-base 1%3A14~beta1-3
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 326,092 kB
  • sloc: java: 2,032,373; xml: 343,016; cpp: 304,181; python: 3,683; ansic: 2,090; sh: 1,871; makefile: 117; sed: 19
file content (316 lines) | stat: -rw-r--r-- 10,909 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.view;

import android.graphics.Matrix;
import android.graphics.Rect;
import android.view.SurfaceControl.Transaction;

import com.android.internal.annotations.VisibleForTesting;

import java.util.function.Consumer;

/**
 * Helper class to apply surface transactions in sync with RenderThread.
 * @hide
 */
public class SyncRtSurfaceTransactionApplier {

    public static final int FLAG_ALL = 0xffffffff;
    public static final int FLAG_ALPHA = 1;
    public static final int FLAG_MATRIX = 1 << 1;
    public static final int FLAG_WINDOW_CROP = 1 << 2;
    public static final int FLAG_LAYER = 1 << 3;
    public static final int FLAG_CORNER_RADIUS = 1 << 4;
    public static final int FLAG_BACKGROUND_BLUR_RADIUS = 1 << 5;
    public static final int FLAG_VISIBILITY = 1 << 6;
    public static final int FLAG_TRANSACTION = 1 << 7;

    private SurfaceControl mTargetSc;
    private final ViewRootImpl mTargetViewRootImpl;
    private final float[] mTmpFloat9 = new float[9];

    /**
     * @param targetView The view in the surface that acts as synchronization anchor.
     */
    public SyncRtSurfaceTransactionApplier(View targetView) {
        mTargetViewRootImpl = targetView != null ? targetView.getViewRootImpl() : null;
    }

    /**
     * Schedules applying surface parameters on the next frame.
     *
     * @param params The surface parameters to apply.
     */
    public void scheduleApply(final SurfaceParams... params) {
        if (mTargetViewRootImpl == null) {
            return;
        }
        mTargetSc = mTargetViewRootImpl.getSurfaceControl();
        final Transaction t = new Transaction();
        applyParams(t, params);

        mTargetViewRootImpl.registerRtFrameCallback(frame -> {
            if (mTargetSc != null && mTargetSc.isValid()) {
                applyTransaction(t, frame);
            }
            // The transaction was either dropped, successfully applied, or merged with a future
            // transaction, so we can safely release its resources.
            t.close();
        });

        // Make sure a frame gets scheduled.
        mTargetViewRootImpl.getView().invalidate();
    }

    /**
     * Applies surface parameters on the next frame.
     * @param t transaction to apply all parameters in.
     * @param frame frame to synchronize to. Set -1 when sync is not required.
     * @param params The surface parameters to apply.
     */
     void applyParams(Transaction t, final SurfaceParams... params) {
        for (int i = params.length - 1; i >= 0; i--) {
            SurfaceParams surfaceParams = params[i];
            SurfaceControl surface = surfaceParams.surface;
            applyParams(t, surfaceParams, mTmpFloat9);
        }
    }

    void applyTransaction(Transaction t, long frame) {
        if (mTargetViewRootImpl != null) {
            mTargetViewRootImpl.mergeWithNextTransaction(t, frame);
        } else {
            t.apply();
        }
    }

    public static void applyParams(Transaction t, SurfaceParams params, float[] tmpFloat9) {
        if ((params.flags & FLAG_TRANSACTION) != 0) {
            t.merge(params.mergeTransaction);
        }

        if ((params.flags & FLAG_MATRIX) != 0) {
            t.setMatrix(params.surface, params.matrix, tmpFloat9);
        }
        if ((params.flags & FLAG_WINDOW_CROP) != 0) {
            t.setWindowCrop(params.surface, params.windowCrop);
        }
        if ((params.flags & FLAG_ALPHA) != 0) {
            t.setAlpha(params.surface, params.alpha);
        }
        if ((params.flags & FLAG_LAYER) != 0) {
            t.setLayer(params.surface, params.layer);
        }
        if ((params.flags & FLAG_CORNER_RADIUS) != 0) {
            t.setCornerRadius(params.surface, params.cornerRadius);
        }
        if ((params.flags & FLAG_BACKGROUND_BLUR_RADIUS) != 0) {
            t.setBackgroundBlurRadius(params.surface, params.backgroundBlurRadius);
        }
        if ((params.flags & FLAG_VISIBILITY) != 0) {
            if (params.visible) {
                t.show(params.surface);
            } else {
                t.hide(params.surface);
            }
        }
    }

    /**
     * Creates an instance of SyncRtSurfaceTransactionApplier, deferring until the target view is
     * attached if necessary.
     */
    public static void create(final View targetView,
            final Consumer<SyncRtSurfaceTransactionApplier> callback) {
        if (targetView == null) {
            // No target view, no applier
            callback.accept(null);
        } else if (targetView.getViewRootImpl() != null) {
            // Already attached, we're good to go
            callback.accept(new SyncRtSurfaceTransactionApplier(targetView));
        } else {
            // Haven't been attached before we can get the view root
            targetView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
                @Override
                public void onViewAttachedToWindow(View v) {
                    targetView.removeOnAttachStateChangeListener(this);
                    callback.accept(new SyncRtSurfaceTransactionApplier(targetView));
                }

                @Override
                public void onViewDetachedFromWindow(View v) {
                    // Do nothing
                }
            });
        }
    }

    public static class SurfaceParams {

        public static class Builder {
            final SurfaceControl surface;
            int flags;
            float alpha;
            float cornerRadius;
            int backgroundBlurRadius;
            Matrix matrix;
            Rect windowCrop;
            int layer;
            boolean visible;
            Transaction mergeTransaction;

            /**
             * @param surface The surface to modify.
             */
            public Builder(SurfaceControl surface) {
                this.surface = surface;
            }

            /**
             * @param alpha The alpha value to apply to the surface.
             * @return this Builder
             */
            public Builder withAlpha(float alpha) {
                this.alpha = alpha;
                flags |= FLAG_ALPHA;
                return this;
            }

            /**
             * @param matrix The matrix to apply to the surface.
             * @return this Builder
             */
            public Builder withMatrix(Matrix matrix) {
                this.matrix = new Matrix(matrix);
                flags |= FLAG_MATRIX;
                return this;
            }

            /**
             * @param windowCrop The window crop to apply to the surface.
             * @return this Builder
             */
            public Builder withWindowCrop(Rect windowCrop) {
                this.windowCrop = new Rect(windowCrop);
                flags |= FLAG_WINDOW_CROP;
                return this;
            }

            /**
             * @param layer The layer to assign the surface.
             * @return this Builder
             */
            public Builder withLayer(int layer) {
                this.layer = layer;
                flags |= FLAG_LAYER;
                return this;
            }

            /**
             * @param radius the Radius for rounded corners to apply to the surface.
             * @return this Builder
             */
            public Builder withCornerRadius(float radius) {
                this.cornerRadius = radius;
                flags |= FLAG_CORNER_RADIUS;
                return this;
            }

            /**
             * @param radius the Radius for blur to apply to the background surfaces.
             * @return this Builder
             */
            public Builder withBackgroundBlur(int radius) {
                this.backgroundBlurRadius = radius;
                flags |= FLAG_BACKGROUND_BLUR_RADIUS;
                return this;
            }

            /**
             * @param visible The visibility to apply to the surface.
             * @return this Builder
             */
            public Builder withVisibility(boolean visible) {
                this.visible = visible;
                flags |= FLAG_VISIBILITY;
                return this;
            }

            /**
             * @param mergeTransaction The transaction to apply to the surface. Note this is applied
             *                         first before all the other properties.
             * @return this Builder
             */
            public Builder withMergeTransaction(Transaction mergeTransaction) {
                this.mergeTransaction = mergeTransaction;
                flags |= FLAG_TRANSACTION;
                return this;
            }

            /**
             * @return a new SurfaceParams instance
             */
            public SurfaceParams build() {
                return new SurfaceParams(surface, flags, alpha, matrix, windowCrop, layer,
                        cornerRadius, backgroundBlurRadius, visible, mergeTransaction);
            }
        }

        private SurfaceParams(SurfaceControl surface, int params, float alpha, Matrix matrix,
                Rect windowCrop, int layer, float cornerRadius,
                int backgroundBlurRadius, boolean visible, Transaction mergeTransaction) {
            this.flags = params;
            this.surface = surface;
            this.alpha = alpha;
            this.matrix = matrix;
            this.windowCrop = windowCrop;
            this.layer = layer;
            this.cornerRadius = cornerRadius;
            this.backgroundBlurRadius = backgroundBlurRadius;
            this.visible = visible;
            this.mergeTransaction = mergeTransaction;
        }

        private final int flags;

        @VisibleForTesting
        public final SurfaceControl surface;

        @VisibleForTesting
        public final float alpha;

        @VisibleForTesting
        public final float cornerRadius;

        @VisibleForTesting
        public final int backgroundBlurRadius;

        @VisibleForTesting
        public final Matrix matrix;

        @VisibleForTesting
        public final Rect windowCrop;

        @VisibleForTesting
        public final int layer;

        public final boolean visible;

        public final Transaction mergeTransaction;
    }
}