• 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 import android.view.View.OnAttachStateChangeListener;
26 import android.view.ViewRootImpl;
27 
28 import com.android.quickstep.RemoteAnimationTargets.ReleaseCheck;
29 
30 /**
31  * Helper class to apply surface transactions in sync with RenderThread similar to
32  *   android.view.SyncRtSurfaceTransactionApplier
33  * with some Launcher specific utility methods
34  */
35 @TargetApi(Build.VERSION_CODES.R)
36 public class SurfaceTransactionApplier extends ReleaseCheck {
37 
38     private static final int MSG_UPDATE_SEQUENCE_NUMBER = 0;
39 
40     private final Handler mApplyHandler;
41 
42     private boolean mInitialized;
43     private SurfaceControl mBarrierSurfaceControl;
44     private ViewRootImpl mTargetViewRootImpl;
45 
46     private int mLastSequenceNumber = 0;
47 
48     /**
49      * @param targetView The view in the surface that acts as synchronization anchor.
50      */
SurfaceTransactionApplier(View targetView)51     public SurfaceTransactionApplier(View targetView) {
52         if (targetView.isAttachedToWindow()) {
53             initialize(targetView);
54         } else {
55             mInitialized = false;
56             targetView.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
57                 @Override
58                 public void onViewAttachedToWindow(View v) {
59                     if (!mInitialized) {
60                         targetView.removeOnAttachStateChangeListener(this);
61                         initialize(targetView);
62                     }
63                 }
64 
65                 @Override
66                 public void onViewDetachedFromWindow(View v) {
67                     // Do nothing
68                 }
69             });
70         }
71         mApplyHandler = new Handler(this::onApplyMessage);
72         setCanRelease(true);
73     }
74 
initialize(View view)75     private void initialize(View view) {
76         mTargetViewRootImpl = view.getViewRootImpl();
77         mBarrierSurfaceControl = mTargetViewRootImpl.getSurfaceControl();
78         mInitialized = true;
79     }
80 
onApplyMessage(Message msg)81     protected boolean onApplyMessage(Message msg) {
82         if (msg.what == MSG_UPDATE_SEQUENCE_NUMBER) {
83             setCanRelease(msg.arg1 == mLastSequenceNumber);
84             return true;
85         }
86         return false;
87     }
88 
89     /**
90      * Schedules applying surface parameters on the next frame.
91      *
92      * @param params The surface parameters to apply. DO NOT MODIFY the list after passing into
93      *               this method to avoid synchronization issues.
94      */
scheduleApply(SurfaceTransaction params)95     public void scheduleApply(SurfaceTransaction params) {
96         if (!mInitialized) {
97             params.getTransaction().apply();
98             return;
99         }
100         View view = mTargetViewRootImpl.getView();
101         if (view == null) {
102             return;
103         }
104         Transaction t = params.getTransaction();
105 
106         mLastSequenceNumber++;
107         final int toApplySeqNo = mLastSequenceNumber;
108         setCanRelease(false);
109         mTargetViewRootImpl.registerRtFrameCallback(frame -> {
110             if (mBarrierSurfaceControl == null || !mBarrierSurfaceControl.isValid()) {
111                 Message.obtain(mApplyHandler, MSG_UPDATE_SEQUENCE_NUMBER, toApplySeqNo, 0)
112                         .sendToTarget();
113                 return;
114             }
115             mTargetViewRootImpl.mergeWithNextTransaction(t, frame);
116             Message.obtain(mApplyHandler, MSG_UPDATE_SEQUENCE_NUMBER, toApplySeqNo, 0)
117                     .sendToTarget();
118         });
119 
120         // Make sure a frame gets scheduled.
121         view.invalidate();
122     }
123 }
124