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 
17 package android.view;
18 
19 import static android.view.InsetsController.DEBUG;
20 import static android.view.SyncRtSurfaceTransactionApplier.applyParams;
21 
22 import android.annotation.Nullable;
23 import android.annotation.UiThread;
24 import android.content.res.CompatibilityInfo;
25 import android.graphics.Rect;
26 import android.os.Handler;
27 import android.os.Trace;
28 import android.util.Log;
29 import android.util.SparseArray;
30 import android.util.proto.ProtoOutputStream;
31 import android.view.InsetsController.AnimationType;
32 import android.view.InsetsController.LayoutInsetsDuringAnimation;
33 import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
34 import android.view.WindowInsets.Type.InsetsType;
35 import android.view.WindowInsetsAnimation.Bounds;
36 import android.view.animation.Interpolator;
37 
38 /**
39  * Insets animation runner that uses {@link InsetsAnimationThread} to run the animation off from the
40  * main thread.
41  *
42  * @hide
43  */
44 public class InsetsAnimationThreadControlRunner implements InsetsAnimationControlRunner {
45 
46     private static final String TAG = "InsetsAnimThreadRunner";
47     private final InsetsAnimationControlImpl mControl;
48     private final InsetsAnimationControlCallbacks mOuterCallbacks;
49     private final Handler mMainThreadHandler;
50     private final InsetsAnimationControlCallbacks mCallbacks =
51             new InsetsAnimationControlCallbacks() {
52 
53         private final float[] mTmpFloat9 = new float[9];
54 
55         @Override
56         @UiThread
57         public <T extends InsetsAnimationControlRunner & InternalInsetsAnimationController>
58         void startAnimation(T runner, WindowInsetsAnimationControlListener listener, int types,
59                 WindowInsetsAnimation animation, Bounds bounds) {
60             // Animation will be started in constructor already.
61         }
62 
63         @Override
64         public void scheduleApplyChangeInsets(InsetsAnimationControlRunner runner) {
65             synchronized (mControl) {
66                 // This reads the surface position on the animation thread, but the surface position
67                 // would be updated on the UI thread, so we need this critical section.
68                 // See: updateSurfacePosition.
69                 mControl.applyChangeInsets(null /* outState */);
70             }
71         }
72 
73         @Override
74         public void notifyFinished(InsetsAnimationControlRunner runner, boolean shown) {
75             Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW,
76                     "InsetsAsyncAnimation: " + WindowInsets.Type.toString(runner.getTypes()),
77                     runner.getTypes());
78             releaseControls(mControl.getControls());
79             mMainThreadHandler.post(() ->
80                     mOuterCallbacks.notifyFinished(InsetsAnimationThreadControlRunner.this, shown));
81         }
82 
83         @Override
84         public void applySurfaceParams(SurfaceParams... params) {
85             if (DEBUG) Log.d(TAG, "applySurfaceParams");
86             SurfaceControl.Transaction t = new SurfaceControl.Transaction();
87             for (int i = params.length - 1; i >= 0; i--) {
88                 SyncRtSurfaceTransactionApplier.SurfaceParams surfaceParams = params[i];
89                 applyParams(t, surfaceParams, mTmpFloat9);
90             }
91             t.setFrameTimelineVsync(Choreographer.getSfInstance().getVsyncId());
92             t.apply();
93             t.close();
94         }
95 
96         @Override
97         public void releaseSurfaceControlFromRt(SurfaceControl sc) {
98             if (DEBUG) Log.d(TAG, "releaseSurfaceControlFromRt");
99             // Since we don't push the SurfaceParams to the RT we can release directly
100             sc.release();
101         }
102 
103         @Override
104         public void reportPerceptible(int types, boolean perceptible) {
105             mMainThreadHandler.post(() -> mOuterCallbacks.reportPerceptible(types, perceptible));
106         }
107     };
108 
109     @UiThread
InsetsAnimationThreadControlRunner(SparseArray<InsetsSourceControl> controls, @Nullable Rect frame, InsetsState state, WindowInsetsAnimationControlListener listener, @InsetsType int types, InsetsAnimationControlCallbacks controller, long durationMs, Interpolator interpolator, @AnimationType int animationType, @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation, CompatibilityInfo.Translator translator, Handler mainThreadHandler)110     public InsetsAnimationThreadControlRunner(SparseArray<InsetsSourceControl> controls,
111             @Nullable Rect frame, InsetsState state, WindowInsetsAnimationControlListener listener,
112             @InsetsType int types, InsetsAnimationControlCallbacks controller, long durationMs,
113             Interpolator interpolator, @AnimationType int animationType,
114             @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation,
115             CompatibilityInfo.Translator translator, Handler mainThreadHandler) {
116         mMainThreadHandler = mainThreadHandler;
117         mOuterCallbacks = controller;
118         mControl = new InsetsAnimationControlImpl(controls, frame, state, listener, types,
119                 mCallbacks, durationMs, interpolator, animationType, layoutInsetsDuringAnimation,
120                 translator);
121         InsetsAnimationThread.getHandler().post(() -> {
122             if (mControl.isCancelled()) {
123                 return;
124             }
125             Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW,
126                     "InsetsAsyncAnimation: " + WindowInsets.Type.toString(types), types);
127             listener.onReady(mControl, types);
128         });
129     }
130 
releaseControls(SparseArray<InsetsSourceControl> controls)131     private void releaseControls(SparseArray<InsetsSourceControl> controls) {
132         for (int i = controls.size() - 1; i >= 0; i--) {
133             controls.valueAt(i).release(SurfaceControl::release);
134         }
135     }
136 
137     @Override
138     @UiThread
dumpDebug(ProtoOutputStream proto, long fieldId)139     public void dumpDebug(ProtoOutputStream proto, long fieldId) {
140         mControl.dumpDebug(proto, fieldId);
141     }
142 
143     @Override
144     @UiThread
getTypes()145     public int getTypes() {
146         return mControl.getTypes();
147     }
148 
149     @Override
150     @UiThread
getControllingTypes()151     public int getControllingTypes() {
152         return mControl.getControllingTypes();
153     }
154 
155     @Override
156     @UiThread
notifyControlRevoked(@nsetsType int types)157     public void notifyControlRevoked(@InsetsType int types) {
158         mControl.notifyControlRevoked(types);
159     }
160 
161     @Override
162     @UiThread
updateSurfacePosition(SparseArray<InsetsSourceControl> controls)163     public void updateSurfacePosition(SparseArray<InsetsSourceControl> controls) {
164         synchronized (mControl) {
165             // This is called from the UI thread, however, the surface position will be used on the
166             // animation thread, so we need this critical section. See: scheduleApplyChangeInsets.
167             mControl.updateSurfacePosition(controls);
168         }
169     }
170 
171     @Override
172     @UiThread
cancel()173     public void cancel() {
174         InsetsAnimationThread.getHandler().post(mControl::cancel);
175     }
176 
177     @Override
178     @UiThread
getAnimation()179     public WindowInsetsAnimation getAnimation() {
180         return mControl.getAnimation();
181     }
182 
183     @Override
getAnimationType()184     public int getAnimationType() {
185         return mControl.getAnimationType();
186     }
187 }
188