blob: ae0f412a99bbdaaacc91d829806a7082249294ed [file] [log] [blame]
Jorim Jaggi33a701a2017-12-01 14:58:18 +01001/*
2 * Copyright (C) 2018 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
17package com.android.server.wm;
18
19import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
20import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
21
22import android.graphics.Point;
23import android.graphics.Rect;
24import android.os.Handler;
25import android.os.RemoteException;
26import android.os.SystemClock;
27import android.util.Slog;
28import android.view.IRemoteAnimationFinishedCallback;
29import android.view.IRemoteAnimationFinishedCallback.Stub;
30import android.view.RemoteAnimationAdapter;
31import android.view.RemoteAnimationTarget;
32import android.view.SurfaceControl;
33import android.view.SurfaceControl.Transaction;
34
35import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
36
37import java.util.ArrayList;
38
39/**
40 * Helper class to run app animations in a remote process.
41 */
42class RemoteAnimationController {
43 private static final String TAG = TAG_WITH_CLASS_NAME ? "RemoteAnimationController" : TAG_WM;
44 private static final long TIMEOUT_MS = 2000;
45
46 private final WindowManagerService mService;
47 private final RemoteAnimationAdapter mRemoteAnimationAdapter;
48 private final ArrayList<RemoteAnimationAdapterWrapper> mPendingAnimations = new ArrayList<>();
49 private final Rect mTmpRect = new Rect();
50 private final Handler mHandler;
51
52 private final IRemoteAnimationFinishedCallback mFinishedCallback = new Stub() {
53 @Override
54 public void onAnimationFinished() throws RemoteException {
55 RemoteAnimationController.this.onAnimationFinished();
56 }
57 };
58
59 private final Runnable mTimeoutRunnable = () -> {
60 onAnimationFinished();
61 invokeAnimationCancelled();
62 };
63
64 RemoteAnimationController(WindowManagerService service,
65 RemoteAnimationAdapter remoteAnimationAdapter, Handler handler) {
66 mService = service;
67 mRemoteAnimationAdapter = remoteAnimationAdapter;
68 mHandler = handler;
69 }
70
71 /**
72 * Creates an animation for each individual {@link AppWindowToken}.
73 *
74 * @param appWindowToken The app to animate.
75 * @param position The position app bounds, in screen coordinates.
76 * @param stackBounds The stack bounds of the app.
77 * @return The adapter to be run on the app.
78 */
79 AnimationAdapter createAnimationAdapter(AppWindowToken appWindowToken, Point position,
80 Rect stackBounds) {
81 final RemoteAnimationAdapterWrapper adapter = new RemoteAnimationAdapterWrapper(
82 appWindowToken, position, stackBounds);
83 mPendingAnimations.add(adapter);
84 return adapter;
85 }
86
87 /**
88 * Called when the transition is ready to be started, and all leashes have been set up.
89 */
90 void goodToGo() {
Jorim Jaggi93f9fe32018-01-25 15:06:13 +010091 if (mPendingAnimations.isEmpty()) {
92 onAnimationFinished();
93 return;
94 }
Jorim Jaggia19d7812018-02-01 15:03:59 +010095
96 // Scale the timeout with the animator scale the controlling app is using.
97 mHandler.postDelayed(mTimeoutRunnable,
98 (long) (TIMEOUT_MS * mService.getCurrentAnimatorScale()));
Chavi Weingarten16d0d072018-02-12 23:50:28 +000099
100 final RemoteAnimationTarget[] animations = createAnimations();
101 mService.mAnimator.addAfterPrepareSurfacesRunnable(() -> {
102 try {
103 mRemoteAnimationAdapter.getRunner().onAnimationStart(animations,
104 mFinishedCallback);
105 } catch (RemoteException e) {
106 Slog.e(TAG, "Failed to start remote animation", e);
107 onAnimationFinished();
108 }
109 });
Jorim Jaggi33a701a2017-12-01 14:58:18 +0100110 }
111
112 private RemoteAnimationTarget[] createAnimations() {
Jorim Jaggi17770212018-01-22 20:01:21 +0100113 final ArrayList<RemoteAnimationTarget> targets = new ArrayList<>();
Jorim Jaggi33a701a2017-12-01 14:58:18 +0100114 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
Jorim Jaggi17770212018-01-22 20:01:21 +0100115 final RemoteAnimationTarget target =
116 mPendingAnimations.get(i).createRemoteAppAnimation();
117 if (target != null) {
118 targets.add(target);
119 }
Jorim Jaggi33a701a2017-12-01 14:58:18 +0100120 }
Jorim Jaggi17770212018-01-22 20:01:21 +0100121 return targets.toArray(new RemoteAnimationTarget[targets.size()]);
Jorim Jaggi33a701a2017-12-01 14:58:18 +0100122 }
123
124 private void onAnimationFinished() {
125 mHandler.removeCallbacks(mTimeoutRunnable);
126 synchronized (mService.mWindowMap) {
127 mService.openSurfaceTransaction();
128 try {
129 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
130 final RemoteAnimationAdapterWrapper adapter = mPendingAnimations.get(i);
131 adapter.mCapturedFinishCallback.onAnimationFinished(adapter);
132 }
133 } finally {
134 mService.closeSurfaceTransaction("RemoteAnimationController#finished");
135 }
136 }
137 }
138
139 private void invokeAnimationCancelled() {
140 try {
141 mRemoteAnimationAdapter.getRunner().onAnimationCancelled();
142 } catch (RemoteException e) {
143 Slog.e(TAG, "Failed to notify cancel", e);
144 }
145 }
146
147 private class RemoteAnimationAdapterWrapper implements AnimationAdapter {
148
149 private final AppWindowToken mAppWindowToken;
150 private SurfaceControl mCapturedLeash;
151 private OnAnimationFinishedCallback mCapturedFinishCallback;
152 private final Point mPosition = new Point();
153 private final Rect mStackBounds = new Rect();
154
155 RemoteAnimationAdapterWrapper(AppWindowToken appWindowToken, Point position,
156 Rect stackBounds) {
157 mAppWindowToken = appWindowToken;
158 mPosition.set(position.x, position.y);
159 mStackBounds.set(stackBounds);
160 }
161
162 RemoteAnimationTarget createRemoteAppAnimation() {
Jorim Jaggi17770212018-01-22 20:01:21 +0100163 final Task task = mAppWindowToken.getTask();
164 final WindowState mainWindow = mAppWindowToken.findMainWindow();
165 if (task == null) {
166 return null;
167 }
168 if (mainWindow == null) {
169 return null;
170 }
171 return new RemoteAnimationTarget(task.mTaskId, getMode(),
Jorim Jaggi33a701a2017-12-01 14:58:18 +0100172 mCapturedLeash, !mAppWindowToken.fillsParent(),
Winson Chung584d6522018-02-07 23:57:38 +0000173 mainWindow.mWinAnimator.mLastClipRect, mainWindow.mContentInsets,
Winson Chunge2d72172018-01-25 17:46:20 +0000174 mAppWindowToken.getPrefixOrderIndex(), mPosition, mStackBounds,
175 task.getWindowConfiguration());
Jorim Jaggi33a701a2017-12-01 14:58:18 +0100176 }
177
178 private int getMode() {
179 if (mService.mOpeningApps.contains(mAppWindowToken)) {
180 return RemoteAnimationTarget.MODE_OPENING;
181 } else {
182 return RemoteAnimationTarget.MODE_CLOSING;
183 }
184 }
185
186 @Override
187 public boolean getDetachWallpaper() {
188 return false;
189 }
190
191 @Override
192 public int getBackgroundColor() {
193 return 0;
194 }
195
196 @Override
197 public void startAnimation(SurfaceControl animationLeash, Transaction t,
198 OnAnimationFinishedCallback finishCallback) {
199
200 // Restore z-layering, position and stack crop until client has a chance to modify it.
201 t.setLayer(animationLeash, mAppWindowToken.getPrefixOrderIndex());
202 t.setPosition(animationLeash, mPosition.x, mPosition.y);
203 mTmpRect.set(mStackBounds);
204 mTmpRect.offsetTo(0, 0);
205 t.setWindowCrop(animationLeash, mTmpRect);
206 mCapturedLeash = animationLeash;
207 mCapturedFinishCallback = finishCallback;
208 }
209
210 @Override
211 public void onAnimationCancelled(SurfaceControl animationLeash) {
212 mPendingAnimations.remove(this);
213 if (mPendingAnimations.isEmpty()) {
214 mHandler.removeCallbacks(mTimeoutRunnable);
215 invokeAnimationCancelled();
216 }
217 }
218
219 @Override
220 public long getDurationHint() {
221 return mRemoteAnimationAdapter.getDuration();
222 }
223
224 @Override
225 public long getStatusBarTransitionsStartTime() {
226 return SystemClock.uptimeMillis()
227 + mRemoteAnimationAdapter.getStatusBarTransitionDelay();
228 }
229 }
230}