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