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