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