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     private final Surface mTargetSurface;
34     private final ViewRootImpl mTargetViewRootImpl;
35     private final float[] mTmpFloat9 = new float[9];
36 
37     /**
38      * @param targetView The view in the surface that acts as synchronization anchor.
39      */
SyncRtSurfaceTransactionApplier(View targetView)40     public SyncRtSurfaceTransactionApplier(View targetView) {
41         mTargetViewRootImpl = targetView != null ? targetView.getViewRootImpl() : null;
42         mTargetSurface = mTargetViewRootImpl != null ? mTargetViewRootImpl.mSurface : null;
43     }
44 
45     /**
46      * Schedules applying surface parameters on the next frame.
47      *
48      * @param params The surface parameters to apply. DO NOT MODIFY the list after passing into
49      *               this method to avoid synchronization issues.
50      */
scheduleApply(final SurfaceParams... params)51     public void scheduleApply(final SurfaceParams... params) {
52         if (mTargetViewRootImpl == null) {
53             return;
54         }
55         mTargetViewRootImpl.registerRtFrameCallback(frame -> {
56             if (mTargetSurface == null || !mTargetSurface.isValid()) {
57                 return;
58             }
59             Transaction t = new Transaction();
60             for (int i = params.length - 1; i >= 0; i--) {
61                 SurfaceParams surfaceParams = params[i];
62                 SurfaceControl surface = surfaceParams.surface;
63                 t.deferTransactionUntilSurface(surface, mTargetSurface, frame);
64                 applyParams(t, surfaceParams, mTmpFloat9);
65             }
66             t.setEarlyWakeup();
67             t.apply();
68         });
69 
70         // Make sure a frame gets scheduled.
71         mTargetViewRootImpl.getView().invalidate();
72     }
73 
applyParams(Transaction t, SurfaceParams params, float[] tmpFloat9)74     public static void applyParams(Transaction t, SurfaceParams params, float[] tmpFloat9) {
75         t.setMatrix(params.surface, params.matrix, tmpFloat9);
76         t.setWindowCrop(params.surface, params.windowCrop);
77         t.setAlpha(params.surface, params.alpha);
78         t.setLayer(params.surface, params.layer);
79         t.setCornerRadius(params.surface, params.cornerRadius);
80         if (params.visible) {
81             t.show(params.surface);
82         } else {
83             t.hide(params.surface);
84         }
85     }
86 
87     /**
88      * Creates an instance of SyncRtSurfaceTransactionApplier, deferring until the target view is
89      * attached if necessary.
90      */
create(final View targetView, final Consumer<SyncRtSurfaceTransactionApplier> callback)91     public static void create(final View targetView,
92             final Consumer<SyncRtSurfaceTransactionApplier> callback) {
93         if (targetView == null) {
94             // No target view, no applier
95             callback.accept(null);
96         } else if (targetView.getViewRootImpl() != null) {
97             // Already attached, we're good to go
98             callback.accept(new SyncRtSurfaceTransactionApplier(targetView));
99         } else {
100             // Haven't been attached before we can get the view root
101             targetView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
102                 @Override
103                 public void onViewAttachedToWindow(View v) {
104                     targetView.removeOnAttachStateChangeListener(this);
105                     callback.accept(new SyncRtSurfaceTransactionApplier(targetView));
106                 }
107 
108                 @Override
109                 public void onViewDetachedFromWindow(View v) {
110                     // Do nothing
111                 }
112             });
113         }
114     }
115 
116     public static class SurfaceParams {
117 
118         /**
119          * Constructs surface parameters to be applied when the current view state gets pushed to
120          * RenderThread.
121          *
122          * @param surface The surface to modify.
123          * @param alpha Alpha to apply.
124          * @param matrix Matrix to apply.
125          * @param windowCrop Crop to apply.
126          */
SurfaceParams(SurfaceControl surface, float alpha, Matrix matrix, Rect windowCrop, int layer, float cornerRadius, boolean visible)127         public SurfaceParams(SurfaceControl surface, float alpha, Matrix matrix,
128                 Rect windowCrop, int layer, float cornerRadius, boolean visible) {
129             this.surface = surface;
130             this.alpha = alpha;
131             this.matrix = new Matrix(matrix);
132             this.windowCrop = new Rect(windowCrop);
133             this.layer = layer;
134             this.cornerRadius = cornerRadius;
135             this.visible = visible;
136         }
137 
138         @VisibleForTesting
139         public final SurfaceControl surface;
140 
141         @VisibleForTesting
142         public final float alpha;
143 
144         @VisibleForTesting
145         final float cornerRadius;
146 
147         @VisibleForTesting
148         public final Matrix matrix;
149 
150         @VisibleForTesting
151         public final Rect windowCrop;
152 
153         @VisibleForTesting
154         public final int layer;
155 
156         public final boolean visible;
157     }
158 }
159