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 com.android.systemui.shared.system; 18 19 import android.graphics.HardwareRenderer; 20 import android.graphics.Matrix; 21 import android.graphics.Rect; 22 import android.os.Handler; 23 import android.os.Handler.Callback; 24 import android.os.Message; 25 import android.os.Trace; 26 import android.view.SurfaceControl; 27 import android.view.SurfaceControl.Transaction; 28 import android.view.View; 29 import android.view.ViewRootImpl; 30 31 import java.util.function.Consumer; 32 33 /** 34 * Helper class to apply surface transactions in sync with RenderThread. 35 * 36 * NOTE: This is a modification of {@link android.view.SyncRtSurfaceTransactionApplier}, we can't 37 * currently reference that class from the shared lib as it is hidden. 38 */ 39 public class SyncRtSurfaceTransactionApplierCompat { 40 41 public static final int FLAG_ALL = 0xffffffff; 42 public static final int FLAG_ALPHA = 1; 43 public static final int FLAG_MATRIX = 1 << 1; 44 public static final int FLAG_WINDOW_CROP = 1 << 2; 45 public static final int FLAG_LAYER = 1 << 3; 46 public static final int FLAG_CORNER_RADIUS = 1 << 4; 47 public static final int FLAG_BACKGROUND_BLUR_RADIUS = 1 << 5; 48 public static final int FLAG_VISIBILITY = 1 << 6; 49 public static final int FLAG_RELATIVE_LAYER = 1 << 7; 50 public static final int FLAG_SHADOW_RADIUS = 1 << 8; 51 52 private static final int MSG_UPDATE_SEQUENCE_NUMBER = 0; 53 54 private final SurfaceControl mBarrierSurfaceControl; 55 private final ViewRootImpl mTargetViewRootImpl; 56 private final Handler mApplyHandler; 57 58 private int mSequenceNumber = 0; 59 private int mPendingSequenceNumber = 0; 60 private Runnable mAfterApplyCallback; 61 62 /** 63 * @param targetView The view in the surface that acts as synchronization anchor. 64 */ SyncRtSurfaceTransactionApplierCompat(View targetView)65 public SyncRtSurfaceTransactionApplierCompat(View targetView) { 66 mTargetViewRootImpl = targetView != null ? targetView.getViewRootImpl() : null; 67 mBarrierSurfaceControl = mTargetViewRootImpl != null 68 ? mTargetViewRootImpl.getSurfaceControl() : null; 69 70 mApplyHandler = new Handler(new Callback() { 71 @Override 72 public boolean handleMessage(Message msg) { 73 if (msg.what == MSG_UPDATE_SEQUENCE_NUMBER) { 74 onApplyMessage(msg.arg1); 75 return true; 76 } 77 return false; 78 } 79 }); 80 } 81 onApplyMessage(int seqNo)82 private void onApplyMessage(int seqNo) { 83 mSequenceNumber = seqNo; 84 if (mSequenceNumber == mPendingSequenceNumber && mAfterApplyCallback != null) { 85 Runnable r = mAfterApplyCallback; 86 mAfterApplyCallback = null; 87 r.run(); 88 } 89 } 90 91 /** 92 * Schedules applying surface parameters on the next frame. 93 * 94 * @param params The surface parameters to apply. DO NOT MODIFY the list after passing into 95 * this method to avoid synchronization issues. 96 */ scheduleApply(final SyncRtSurfaceTransactionApplierCompat.SurfaceParams... params)97 public void scheduleApply(final SyncRtSurfaceTransactionApplierCompat.SurfaceParams... params) { 98 if (mTargetViewRootImpl == null || mTargetViewRootImpl.getView() == null) { 99 return; 100 } 101 102 mPendingSequenceNumber++; 103 final int toApplySeqNo = mPendingSequenceNumber; 104 mTargetViewRootImpl.registerRtFrameCallback(new HardwareRenderer.FrameDrawingCallback() { 105 @Override 106 public void onFrameDraw(long frame) { 107 if (mBarrierSurfaceControl == null || !mBarrierSurfaceControl.isValid()) { 108 Message.obtain(mApplyHandler, MSG_UPDATE_SEQUENCE_NUMBER, toApplySeqNo, 0) 109 .sendToTarget(); 110 return; 111 } 112 Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Sync transaction frameNumber=" + frame); 113 Transaction t = new Transaction(); 114 for (int i = params.length - 1; i >= 0; i--) { 115 SyncRtSurfaceTransactionApplierCompat.SurfaceParams surfaceParams = 116 params[i]; 117 surfaceParams.applyTo(t); 118 } 119 if (mTargetViewRootImpl != null) { 120 mTargetViewRootImpl.mergeWithNextTransaction(t, frame); 121 } else { 122 t.apply(); 123 } 124 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 125 Message.obtain(mApplyHandler, MSG_UPDATE_SEQUENCE_NUMBER, toApplySeqNo, 0) 126 .sendToTarget(); 127 } 128 }); 129 130 // Make sure a frame gets scheduled. 131 mTargetViewRootImpl.getView().invalidate(); 132 } 133 134 /** 135 * Calls the runnable when any pending apply calls have completed 136 */ addAfterApplyCallback(final Runnable afterApplyCallback)137 public void addAfterApplyCallback(final Runnable afterApplyCallback) { 138 if (mSequenceNumber == mPendingSequenceNumber) { 139 afterApplyCallback.run(); 140 } else { 141 if (mAfterApplyCallback == null) { 142 mAfterApplyCallback = afterApplyCallback; 143 } else { 144 final Runnable oldCallback = mAfterApplyCallback; 145 mAfterApplyCallback = new Runnable() { 146 @Override 147 public void run() { 148 afterApplyCallback.run(); 149 oldCallback.run(); 150 } 151 }; 152 } 153 } 154 } 155 applyParams(TransactionCompat t, SyncRtSurfaceTransactionApplierCompat.SurfaceParams params)156 public static void applyParams(TransactionCompat t, 157 SyncRtSurfaceTransactionApplierCompat.SurfaceParams params) { 158 params.applyTo(t.mTransaction); 159 } 160 161 /** 162 * Creates an instance of SyncRtSurfaceTransactionApplier, deferring until the target view is 163 * attached if necessary. 164 */ create(final View targetView, final Consumer<SyncRtSurfaceTransactionApplierCompat> callback)165 public static void create(final View targetView, 166 final Consumer<SyncRtSurfaceTransactionApplierCompat> callback) { 167 if (targetView == null) { 168 // No target view, no applier 169 callback.accept(null); 170 } else if (targetView.getViewRootImpl() != null) { 171 // Already attached, we're good to go 172 callback.accept(new SyncRtSurfaceTransactionApplierCompat(targetView)); 173 } else { 174 // Haven't been attached before we can get the view root 175 targetView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { 176 @Override 177 public void onViewAttachedToWindow(View v) { 178 targetView.removeOnAttachStateChangeListener(this); 179 callback.accept(new SyncRtSurfaceTransactionApplierCompat(targetView)); 180 } 181 182 @Override 183 public void onViewDetachedFromWindow(View v) { 184 // Do nothing 185 } 186 }); 187 } 188 } 189 190 public static class SurfaceParams { 191 public static class Builder { 192 final SurfaceControl surface; 193 int flags; 194 float alpha; 195 float cornerRadius; 196 int backgroundBlurRadius; 197 Matrix matrix; 198 Rect windowCrop; 199 int layer; 200 SurfaceControl relativeTo; 201 int relativeLayer; 202 boolean visible; 203 float shadowRadius; 204 205 /** 206 * @param surface The surface to modify. 207 */ Builder(SurfaceControlCompat surface)208 public Builder(SurfaceControlCompat surface) { 209 this(surface.mSurfaceControl); 210 } 211 212 /** 213 * @param surface The surface to modify. 214 */ Builder(SurfaceControl surface)215 public Builder(SurfaceControl surface) { 216 this.surface = surface; 217 } 218 219 /** 220 * @param alpha The alpha value to apply to the surface. 221 * @return this Builder 222 */ withAlpha(float alpha)223 public Builder withAlpha(float alpha) { 224 this.alpha = alpha; 225 flags |= FLAG_ALPHA; 226 return this; 227 } 228 229 /** 230 * @param matrix The matrix to apply to the surface. 231 * @return this Builder 232 */ withMatrix(Matrix matrix)233 public Builder withMatrix(Matrix matrix) { 234 this.matrix = new Matrix(matrix); 235 flags |= FLAG_MATRIX; 236 return this; 237 } 238 239 /** 240 * @param windowCrop The window crop to apply to the surface. 241 * @return this Builder 242 */ withWindowCrop(Rect windowCrop)243 public Builder withWindowCrop(Rect windowCrop) { 244 this.windowCrop = new Rect(windowCrop); 245 flags |= FLAG_WINDOW_CROP; 246 return this; 247 } 248 249 /** 250 * @param layer The layer to assign the surface. 251 * @return this Builder 252 */ withLayer(int layer)253 public Builder withLayer(int layer) { 254 this.layer = layer; 255 flags |= FLAG_LAYER; 256 return this; 257 } 258 259 /** 260 * @param relativeTo The surface that's set relative layer to. 261 * @param relativeLayer The relative layer. 262 * @return this Builder 263 */ withRelativeLayerTo(SurfaceControl relativeTo, int relativeLayer)264 public Builder withRelativeLayerTo(SurfaceControl relativeTo, int relativeLayer) { 265 this.relativeTo = relativeTo; 266 this.relativeLayer = relativeLayer; 267 flags |= FLAG_RELATIVE_LAYER; 268 return this; 269 } 270 271 /** 272 * @param radius the Radius for rounded corners to apply to the surface. 273 * @return this Builder 274 */ withCornerRadius(float radius)275 public Builder withCornerRadius(float radius) { 276 this.cornerRadius = radius; 277 flags |= FLAG_CORNER_RADIUS; 278 return this; 279 } 280 281 /** 282 * @param radius the Radius for the shadows to apply to the surface. 283 * @return this Builder 284 */ withShadowRadius(float radius)285 public Builder withShadowRadius(float radius) { 286 this.shadowRadius = radius; 287 flags |= FLAG_SHADOW_RADIUS; 288 return this; 289 } 290 291 /** 292 * @param radius the Radius for blur to apply to the background surfaces. 293 * @return this Builder 294 */ withBackgroundBlur(int radius)295 public Builder withBackgroundBlur(int radius) { 296 this.backgroundBlurRadius = radius; 297 flags |= FLAG_BACKGROUND_BLUR_RADIUS; 298 return this; 299 } 300 301 /** 302 * @param visible The visibility to apply to the surface. 303 * @return this Builder 304 */ withVisibility(boolean visible)305 public Builder withVisibility(boolean visible) { 306 this.visible = visible; 307 flags |= FLAG_VISIBILITY; 308 return this; 309 } 310 311 /** 312 * @return a new SurfaceParams instance 313 */ build()314 public SurfaceParams build() { 315 return new SurfaceParams(surface, flags, alpha, matrix, windowCrop, layer, 316 relativeTo, relativeLayer, cornerRadius, backgroundBlurRadius, visible, 317 shadowRadius); 318 } 319 } 320 SurfaceParams(SurfaceControl surface, int flags, float alpha, Matrix matrix, Rect windowCrop, int layer, SurfaceControl relativeTo, int relativeLayer, float cornerRadius, int backgroundBlurRadius, boolean visible, float shadowRadius)321 private SurfaceParams(SurfaceControl surface, int flags, float alpha, Matrix matrix, 322 Rect windowCrop, int layer, SurfaceControl relativeTo, int relativeLayer, 323 float cornerRadius, int backgroundBlurRadius, boolean visible, float shadowRadius) { 324 this.flags = flags; 325 this.surface = surface; 326 this.alpha = alpha; 327 this.matrix = matrix; 328 this.windowCrop = windowCrop; 329 this.layer = layer; 330 this.relativeTo = relativeTo; 331 this.relativeLayer = relativeLayer; 332 this.cornerRadius = cornerRadius; 333 this.backgroundBlurRadius = backgroundBlurRadius; 334 this.visible = visible; 335 this.shadowRadius = shadowRadius; 336 } 337 338 private final int flags; 339 private final float[] mTmpValues = new float[9]; 340 341 public final SurfaceControl surface; 342 public final float alpha; 343 public final float cornerRadius; 344 public final int backgroundBlurRadius; 345 public final Matrix matrix; 346 public final Rect windowCrop; 347 public final int layer; 348 public final SurfaceControl relativeTo; 349 public final int relativeLayer; 350 public final boolean visible; 351 public final float shadowRadius; 352 applyTo(SurfaceControl.Transaction t)353 public void applyTo(SurfaceControl.Transaction t) { 354 if ((flags & FLAG_MATRIX) != 0) { 355 t.setMatrix(surface, matrix, mTmpValues); 356 } 357 if ((flags & FLAG_WINDOW_CROP) != 0) { 358 t.setWindowCrop(surface, windowCrop); 359 } 360 if ((flags & FLAG_ALPHA) != 0) { 361 t.setAlpha(surface, alpha); 362 } 363 if ((flags & FLAG_LAYER) != 0) { 364 t.setLayer(surface, layer); 365 } 366 if ((flags & FLAG_CORNER_RADIUS) != 0) { 367 t.setCornerRadius(surface, cornerRadius); 368 } 369 if ((flags & FLAG_BACKGROUND_BLUR_RADIUS) != 0) { 370 t.setBackgroundBlurRadius(surface, backgroundBlurRadius); 371 } 372 if ((flags & FLAG_VISIBILITY) != 0) { 373 if (visible) { 374 t.show(surface); 375 } else { 376 t.hide(surface); 377 } 378 } 379 if ((flags & FLAG_RELATIVE_LAYER) != 0) { 380 t.setRelativeLayer(surface, relativeTo, relativeLayer); 381 } 382 if ((flags & FLAG_SHADOW_RADIUS) != 0) { 383 t.setShadowRadius(surface, shadowRadius); 384 } 385 } 386 } 387 } 388