• 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.ViewRootImpl;
26 
27 import com.android.quickstep.RemoteAnimationTargets.ReleaseCheck;
28 
29 import java.util.function.Consumer;
30 
31 
32 /**
33  * Helper class to apply surface transactions in sync with RenderThread similar to
34  *   android.view.SyncRtSurfaceTransactionApplier
35  * with some Launcher specific utility methods
36  */
37 @TargetApi(Build.VERSION_CODES.R)
38 public class SurfaceTransactionApplier extends ReleaseCheck {
39 
40     private static final int MSG_UPDATE_SEQUENCE_NUMBER = 0;
41 
42     private final SurfaceControl mBarrierSurfaceControl;
43     private final ViewRootImpl mTargetViewRootImpl;
44     private final Handler mApplyHandler;
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         mTargetViewRootImpl = targetView.getViewRootImpl();
53         mBarrierSurfaceControl = mTargetViewRootImpl.getSurfaceControl();
54         mApplyHandler = new Handler(this::onApplyMessage);
55         setCanRelease(true);
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(SurfaceTransaction params)72     public void scheduleApply(SurfaceTransaction params) {
73         View view = mTargetViewRootImpl.getView();
74         if (view == null) {
75             return;
76         }
77         Transaction t = params.getTransaction();
78 
79         mLastSequenceNumber++;
80         final int toApplySeqNo = mLastSequenceNumber;
81         setCanRelease(false);
82         mTargetViewRootImpl.registerRtFrameCallback(frame -> {
83             if (mBarrierSurfaceControl == null || !mBarrierSurfaceControl.isValid()) {
84                 Message.obtain(mApplyHandler, MSG_UPDATE_SEQUENCE_NUMBER, toApplySeqNo, 0)
85                         .sendToTarget();
86                 return;
87             }
88             mTargetViewRootImpl.mergeWithNextTransaction(t, frame);
89             Message.obtain(mApplyHandler, MSG_UPDATE_SEQUENCE_NUMBER, toApplySeqNo, 0)
90                     .sendToTarget();
91         });
92 
93         // Make sure a frame gets scheduled.
94         view.invalidate();
95     }
96 
97     /**
98      * Creates an instance of SurfaceTransactionApplier, deferring until the target view is
99      * attached if necessary.
100      */
create( final View targetView, final Consumer<SurfaceTransactionApplier> callback)101     public static void create(
102             final View targetView, final Consumer<SurfaceTransactionApplier> callback) {
103         if (targetView == null) {
104             // No target view, no applier
105             callback.accept(null);
106         } else if (targetView.isAttachedToWindow()) {
107             // Already attached, we're good to go
108             callback.accept(new SurfaceTransactionApplier(targetView));
109         } else {
110             // Haven't been attached before we can get the view root
111             targetView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
112                 @Override
113                 public void onViewAttachedToWindow(View v) {
114                     targetView.removeOnAttachStateChangeListener(this);
115                     callback.accept(new SurfaceTransactionApplier(targetView));
116                 }
117 
118                 @Override
119                 public void onViewDetachedFromWindow(View v) {
120                     // Do nothing
121                 }
122             });
123         }
124     }
125 }
126