1 /* 2 * Copyright (C) 2020 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 package com.android.quickstep.util; 17 18 import static com.android.systemui.shared.system.TransactionCompat.deferTransactionUntil; 19 20 import android.annotation.TargetApi; 21 import android.os.Build; 22 import android.os.Handler; 23 import android.os.Message; 24 import android.view.SurfaceControl; 25 import android.view.SurfaceControl.Transaction; 26 import android.view.View; 27 28 import com.android.quickstep.RemoteAnimationTargets.ReleaseCheck; 29 import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams; 30 import com.android.systemui.shared.system.ViewRootImplCompat; 31 32 import java.util.function.Consumer; 33 34 35 /** 36 * Helper class to apply surface transactions in sync with RenderThread similar to 37 * android.view.SyncRtSurfaceTransactionApplier 38 * with some Launcher specific utility methods 39 */ 40 @TargetApi(Build.VERSION_CODES.R) 41 public class SurfaceTransactionApplier extends ReleaseCheck { 42 43 private static final int MSG_UPDATE_SEQUENCE_NUMBER = 0; 44 45 private final SurfaceControl mBarrierSurfaceControl; 46 private final ViewRootImplCompat mTargetViewRootImpl; 47 private final Handler mApplyHandler; 48 49 private int mLastSequenceNumber = 0; 50 51 /** 52 * @param targetView The view in the surface that acts as synchronization anchor. 53 */ SurfaceTransactionApplier(View targetView)54 public SurfaceTransactionApplier(View targetView) { 55 mTargetViewRootImpl = new ViewRootImplCompat(targetView); 56 mBarrierSurfaceControl = mTargetViewRootImpl.getRenderSurfaceControl(); 57 mApplyHandler = new Handler(this::onApplyMessage); 58 } 59 onApplyMessage(Message msg)60 protected boolean onApplyMessage(Message msg) { 61 if (msg.what == MSG_UPDATE_SEQUENCE_NUMBER) { 62 setCanRelease(msg.arg1 == mLastSequenceNumber); 63 return true; 64 } 65 return false; 66 } 67 68 /** 69 * Schedules applying surface parameters on the next frame. 70 * 71 * @param params The surface parameters to apply. DO NOT MODIFY the list after passing into 72 * this method to avoid synchronization issues. 73 */ scheduleApply(final SurfaceParams... params)74 public void scheduleApply(final SurfaceParams... params) { 75 View view = mTargetViewRootImpl.getView(); 76 if (view == null) { 77 return; 78 } 79 80 mLastSequenceNumber++; 81 final int toApplySeqNo = mLastSequenceNumber; 82 setCanRelease(false); 83 mTargetViewRootImpl.registerRtFrameCallback(frame -> { 84 if (mBarrierSurfaceControl == null || !mBarrierSurfaceControl.isValid()) { 85 Message.obtain(mApplyHandler, MSG_UPDATE_SEQUENCE_NUMBER, toApplySeqNo, 0) 86 .sendToTarget(); 87 return; 88 } 89 Transaction t = new Transaction(); 90 for (int i = params.length - 1; i >= 0; i--) { 91 SurfaceParams surfaceParams = params[i]; 92 if (surfaceParams.surface.isValid()) { 93 deferTransactionUntil(t, surfaceParams.surface, mBarrierSurfaceControl, frame); 94 surfaceParams.applyTo(t); 95 } 96 } 97 t.apply(); 98 Message.obtain(mApplyHandler, MSG_UPDATE_SEQUENCE_NUMBER, toApplySeqNo, 0) 99 .sendToTarget(); 100 }); 101 102 // Make sure a frame gets scheduled. 103 view.invalidate(); 104 } 105 106 /** 107 * Creates an instance of SyncRtSurfaceTransactionApplier, deferring until the target view is 108 * attached if necessary. 109 */ create( final View targetView, final Consumer<SurfaceTransactionApplier> callback)110 public static void create( 111 final View targetView, final Consumer<SurfaceTransactionApplier> callback) { 112 if (targetView == null) { 113 // No target view, no applier 114 callback.accept(null); 115 } else if (new ViewRootImplCompat(targetView).isValid()) { 116 // Already attached, we're good to go 117 callback.accept(new SurfaceTransactionApplier(targetView)); 118 } else { 119 // Haven't been attached before we can get the view root 120 targetView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { 121 @Override 122 public void onViewAttachedToWindow(View v) { 123 targetView.removeOnAttachStateChangeListener(this); 124 callback.accept(new SurfaceTransactionApplier(targetView)); 125 } 126 127 @Override 128 public void onViewDetachedFromWindow(View v) { 129 // Do nothing 130 } 131 }); 132 } 133 } 134 } 135