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