blob: b2e208a5e71181fe655bf353c0a45156a65b74bd [file] [log] [blame]
Winson Chunge2d72172018-01-25 17:46:20 +00001/*
2 * Copyright (C) 2017 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
Jorim Jaggi54cff642018-03-15 15:51:32 +010019import static android.app.ActivityManagerInternal.APP_TRANSITION_RECENTS_ANIM;
Jorim Jaggi54cff642018-03-15 15:51:32 +010020import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
Winson Chunge2d72172018-01-25 17:46:20 +000021import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
Winson Chung3e2980e2018-03-29 17:28:57 -070022import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
Winson Chunge2d72172018-01-25 17:46:20 +000023import static android.view.RemoteAnimationTarget.MODE_CLOSING;
Winson Chunga89ffed2018-01-25 17:46:11 +000024import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
Winson Chunge2d72172018-01-25 17:46:20 +000025import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
Yi Jin6c6e9ca2018-03-20 16:53:35 -070026import static com.android.server.wm.AnimationAdapterProto.REMOTE;
Winson Chungc6c3f852018-04-09 15:41:03 -070027import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET;
28import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RECENTS_ANIMATIONS;
29import static com.android.server.wm.WindowManagerService.H.NOTIFY_APP_TRANSITION_STARTING;
Winson Chunge2d72172018-01-25 17:46:20 +000030
Winson Chung6a38fca2018-03-28 17:57:09 -070031import android.annotation.IntDef;
Winson Chunge2d72172018-01-25 17:46:20 +000032import android.app.ActivityManager.TaskSnapshot;
33import android.app.WindowConfiguration;
Winson Chunge2d72172018-01-25 17:46:20 +000034import android.graphics.Point;
35import android.graphics.Rect;
36import android.os.Binder;
Adrian Roos842e7882018-03-26 17:34:06 +020037import android.os.IBinder.DeathRecipient;
Winson Chunge2d72172018-01-25 17:46:20 +000038import android.os.RemoteException;
39import android.os.SystemClock;
Winson Chung23aa7b12018-02-01 11:41:43 -080040import android.util.ArraySet;
Winson Chungc6c3f852018-04-09 15:41:03 -070041import android.util.Slog;
Vadim Tryshev593e9562018-03-08 17:15:45 -080042import android.util.SparseBooleanArray;
Jorim Jaggi54cff642018-03-15 15:51:32 +010043import android.util.SparseIntArray;
Winson Chungc6c3f852018-04-09 15:41:03 -070044import android.util.proto.ProtoOutputStream;
Winson Chunge2d72172018-01-25 17:46:20 +000045import android.view.IRecentsAnimationController;
46import android.view.IRecentsAnimationRunner;
47import android.view.RemoteAnimationTarget;
48import android.view.SurfaceControl;
49import android.view.SurfaceControl.Transaction;
Winson Chungda876c92018-04-05 18:31:06 -070050import com.android.internal.annotations.VisibleForTesting;
Jorim Jaggif75d1612018-02-27 15:05:21 +010051import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
Jorim Jaggi817ebdd2018-03-26 15:46:01 +020052import com.android.server.wm.utils.InsetUtils;
Winson Chungc6c3f852018-04-09 15:41:03 -070053import com.google.android.collect.Sets;
Winson Chunge2d72172018-01-25 17:46:20 +000054import java.io.PrintWriter;
55import java.util.ArrayList;
Winson Chungc6c3f852018-04-09 15:41:03 -070056
Winson Chunge2d72172018-01-25 17:46:20 +000057/**
58 * Controls a single instance of the remote driven recents animation. In particular, this allows
59 * the calling SystemUI to animate the visible task windows as a part of the transition. The remote
60 * runner is provided an animation controller which allows it to take screenshots and to notify
61 * window manager when the animation is completed. In addition, window manager may also notify the
62 * app if it requires the animation to be canceled at any time (ie. due to timeout, etc.)
63 */
Adrian Roos842e7882018-03-26 17:34:06 +020064public class RecentsAnimationController implements DeathRecipient {
Winson Chungc6c3f852018-04-09 15:41:03 -070065 private static final String TAG = RecentsAnimationController.class.getSimpleName();
Adrian Roos842e7882018-03-26 17:34:06 +020066 private static final long FAILSAFE_DELAY = 1000;
Winson Chunge2d72172018-01-25 17:46:20 +000067
Winson Chung3e2980e2018-03-29 17:28:57 -070068 public static final int REORDER_KEEP_IN_PLACE = 0;
69 public static final int REORDER_MOVE_TO_TOP = 1;
70 public static final int REORDER_MOVE_TO_ORIGINAL_POSITION = 2;
Winson Chung6a38fca2018-03-28 17:57:09 -070071
72 @IntDef(prefix = { "REORDER_MODE_" }, value = {
Winson Chung3e2980e2018-03-29 17:28:57 -070073 REORDER_KEEP_IN_PLACE,
74 REORDER_MOVE_TO_TOP,
75 REORDER_MOVE_TO_ORIGINAL_POSITION
Winson Chung6a38fca2018-03-28 17:57:09 -070076 })
77 public @interface ReorderMode {}
78
Winson Chunge2d72172018-01-25 17:46:20 +000079 private final WindowManagerService mService;
80 private final IRecentsAnimationRunner mRunner;
81 private final RecentsAnimationCallbacks mCallbacks;
82 private final ArrayList<TaskAnimationAdapter> mPendingAnimations = new ArrayList<>();
Winson Chungddf62972018-02-12 11:10:04 -080083 private final int mDisplayId;
Winson Chung6a38fca2018-03-28 17:57:09 -070084 private final Runnable mFailsafeRunnable = () -> {
Winson Chungc6c3f852018-04-09 15:41:03 -070085 cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "failSafeRunnable");
Winson Chung6a38fca2018-03-28 17:57:09 -070086 };
Winson Chunge2d72172018-01-25 17:46:20 +000087
88 // The recents component app token that is shown behind the visibile tasks
Winson Chung3e2980e2018-03-29 17:28:57 -070089 private AppWindowToken mTargetAppToken;
Winson Chung584d6522018-02-07 23:57:38 +000090 private Rect mMinimizedHomeBounds = new Rect();
Winson Chunge2d72172018-01-25 17:46:20 +000091
92 // We start the RecentsAnimationController in a pending-start state since we need to wait for
93 // the wallpaper/activity to draw before we can give control to the handler to start animating
94 // the visible task surfaces
95 private boolean mPendingStart = true;
96
97 // Set when the animation has been canceled
Winson Chungf557c3b2018-03-16 10:55:20 -070098 private boolean mCanceled;
Winson Chunge2d72172018-01-25 17:46:20 +000099
100 // Whether or not the input consumer is enabled. The input consumer must be both registered and
101 // enabled for it to start intercepting touch events.
102 private boolean mInputConsumerEnabled;
103
Winson Chungf557c3b2018-03-16 10:55:20 -0700104 // Whether or not the recents animation should cause the primary split-screen stack to be
105 // minimized
106 private boolean mSplitScreenMinimized;
107
Winson Chunga89ffed2018-01-25 17:46:11 +0000108 private Rect mTmpRect = new Rect();
109
Winson Chunge2d72172018-01-25 17:46:20 +0000110 public interface RecentsAnimationCallbacks {
Winson Chung6a38fca2018-03-28 17:57:09 -0700111 void onAnimationFinished(@ReorderMode int reorderMode);
Winson Chunge2d72172018-01-25 17:46:20 +0000112 }
113
114 private final IRecentsAnimationController mController =
115 new IRecentsAnimationController.Stub() {
116
117 @Override
118 public TaskSnapshot screenshotTask(int taskId) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700119 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "screenshotTask(" + taskId + "):"
120 + " mCanceled=" + mCanceled);
Winson Chungf557c3b2018-03-16 10:55:20 -0700121 final long token = Binder.clearCallingIdentity();
Winson Chunge2d72172018-01-25 17:46:20 +0000122 try {
123 synchronized (mService.getWindowManagerLock()) {
124 if (mCanceled) {
125 return null;
126 }
127 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
128 final TaskAnimationAdapter adapter = mPendingAnimations.get(i);
129 final Task task = adapter.mTask;
130 if (task.mTaskId == taskId) {
Winson Chung23aa7b12018-02-01 11:41:43 -0800131 final TaskSnapshotController snapshotController =
132 mService.mTaskSnapshotController;
133 final ArraySet<Task> tasks = Sets.newArraySet(task);
134 snapshotController.snapshotTasks(tasks);
135 snapshotController.addSkipClosingAppSnapshotTasks(tasks);
136 return snapshotController.getSnapshot(taskId, 0 /* userId */,
137 false /* restoreFromDisk */, false /* reducedResolution */);
Winson Chunge2d72172018-01-25 17:46:20 +0000138 }
139 }
140 return null;
141 }
142 } finally {
143 Binder.restoreCallingIdentity(token);
144 }
145 }
146
147 @Override
148 public void finish(boolean moveHomeToTop) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700149 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "finish(" + moveHomeToTop + "):"
150 + " mCanceled=" + mCanceled);
Winson Chungf557c3b2018-03-16 10:55:20 -0700151 final long token = Binder.clearCallingIdentity();
Winson Chunge2d72172018-01-25 17:46:20 +0000152 try {
153 synchronized (mService.getWindowManagerLock()) {
154 if (mCanceled) {
155 return;
156 }
157 }
158
159 // Note, the callback will handle its own synchronization, do not lock on WM lock
160 // prior to calling the callback
Winson Chung6a38fca2018-03-28 17:57:09 -0700161 mCallbacks.onAnimationFinished(moveHomeToTop
Winson Chung3e2980e2018-03-29 17:28:57 -0700162 ? REORDER_MOVE_TO_TOP
163 : REORDER_MOVE_TO_ORIGINAL_POSITION);
Winson Chunge2d72172018-01-25 17:46:20 +0000164 } finally {
165 Binder.restoreCallingIdentity(token);
166 }
167 }
168
169 @Override
Jorim Jaggi50bf59c2018-03-09 17:29:48 +0100170 public void setAnimationTargetsBehindSystemBars(boolean behindSystemBars)
171 throws RemoteException {
Winson Chungf557c3b2018-03-16 10:55:20 -0700172 final long token = Binder.clearCallingIdentity();
Jorim Jaggi50bf59c2018-03-09 17:29:48 +0100173 try {
174 synchronized (mService.getWindowManagerLock()) {
175 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
176 mPendingAnimations.get(i).mTask.setCanAffectSystemUiFlags(behindSystemBars);
177 }
178 mService.mWindowPlacerLocked.requestTraversal();
179 }
180 } finally {
181 Binder.restoreCallingIdentity(token);
182 }
183 }
184
185 @Override
Winson Chunge2d72172018-01-25 17:46:20 +0000186 public void setInputConsumerEnabled(boolean enabled) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700187 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "setInputConsumerEnabled(" + enabled + "):"
188 + " mCanceled=" + mCanceled);
Winson Chungf557c3b2018-03-16 10:55:20 -0700189 final long token = Binder.clearCallingIdentity();
Winson Chunge2d72172018-01-25 17:46:20 +0000190 try {
191 synchronized (mService.getWindowManagerLock()) {
192 if (mCanceled) {
193 return;
194 }
195
196 mInputConsumerEnabled = enabled;
197 mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
198 mService.scheduleAnimationLocked();
199 }
200 } finally {
201 Binder.restoreCallingIdentity(token);
202 }
203 }
Winson Chungf557c3b2018-03-16 10:55:20 -0700204
205 @Override
206 public void setSplitScreenMinimized(boolean minimized) {
207 final long token = Binder.clearCallingIdentity();
208 try {
209 synchronized (mService.getWindowManagerLock()) {
210 if (mCanceled) {
211 return;
212 }
213
214 mSplitScreenMinimized = minimized;
215 mService.checkSplitScreenMinimizedChanged(true /* animate */);
216 }
217 } finally {
218 Binder.restoreCallingIdentity(token);
219 }
220 }
Winson Chunge2d72172018-01-25 17:46:20 +0000221 };
222
223 /**
Winson Chunge2d72172018-01-25 17:46:20 +0000224 * @param remoteAnimationRunner The remote runner which should be notified when the animation is
225 * ready to start or has been canceled
226 * @param callbacks Callbacks to be made when the animation finishes
Winson Chunge2d72172018-01-25 17:46:20 +0000227 */
228 RecentsAnimationController(WindowManagerService service,
229 IRecentsAnimationRunner remoteAnimationRunner, RecentsAnimationCallbacks callbacks,
230 int displayId) {
231 mService = service;
232 mRunner = remoteAnimationRunner;
233 mCallbacks = callbacks;
Winson Chungddf62972018-02-12 11:10:04 -0800234 mDisplayId = displayId;
235 }
Winson Chunge2d72172018-01-25 17:46:20 +0000236
Winson Chungddf62972018-02-12 11:10:04 -0800237 /**
238 * Initializes the recents animation controller. This is a separate call from the constructor
239 * because it may call cancelAnimation() which needs to properly clean up the controller
240 * in the window manager.
241 */
Winson Chung3e2980e2018-03-29 17:28:57 -0700242 public void initialize(int targetActivityType, SparseBooleanArray recentTaskIds) {
Winson Chunge2d72172018-01-25 17:46:20 +0000243 // Make leashes for each of the visible tasks and add it to the recents animation to be
244 // started
Winson Chungddf62972018-02-12 11:10:04 -0800245 final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId);
246 final ArrayList<Task> visibleTasks = dc.getVisibleTasks();
Winson Chunge2d72172018-01-25 17:46:20 +0000247 final int taskCount = visibleTasks.size();
248 for (int i = 0; i < taskCount; i++) {
249 final Task task = visibleTasks.get(i);
250 final WindowConfiguration config = task.getWindowConfiguration();
251 if (config.tasksAreFloating()
252 || config.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
Winson Chung3e2980e2018-03-29 17:28:57 -0700253 || config.getActivityType() == targetActivityType) {
Winson Chunge2d72172018-01-25 17:46:20 +0000254 continue;
255 }
Vadim Tryshev593e9562018-03-08 17:15:45 -0800256 addAnimation(task, !recentTaskIds.get(task.mTaskId));
Winson Chunge2d72172018-01-25 17:46:20 +0000257 }
258
Winson Chungddf62972018-02-12 11:10:04 -0800259 // Skip the animation if there is nothing to animate
260 if (mPendingAnimations.isEmpty()) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700261 cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "initialize-noVisibleTasks");
Winson Chungddf62972018-02-12 11:10:04 -0800262 return;
263 }
264
Adrian Roos842e7882018-03-26 17:34:06 +0200265 try {
266 mRunner.asBinder().linkToDeath(this, 0);
267 } catch (RemoteException e) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700268 cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "initialize-failedToLinkToDeath");
Adrian Roos842e7882018-03-26 17:34:06 +0200269 return;
270 }
271
Winson Chung3e2980e2018-03-29 17:28:57 -0700272 // Adjust the wallpaper visibility for the showing target activity
273 final AppWindowToken recentsComponentAppToken = dc.getStack(WINDOWING_MODE_UNDEFINED,
274 targetActivityType).getTopChild().getTopFullscreenAppToken();
Winson Chunge2d72172018-01-25 17:46:20 +0000275 if (recentsComponentAppToken != null) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700276 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "setHomeApp("
277 + recentsComponentAppToken.getName() + ")");
Winson Chung3e2980e2018-03-29 17:28:57 -0700278 mTargetAppToken = recentsComponentAppToken;
Winson Chunge2d72172018-01-25 17:46:20 +0000279 if (recentsComponentAppToken.windowsCanBeWallpaperTarget()) {
280 dc.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
281 dc.setLayoutNeeded();
282 }
283 }
284
Winson Chung584d6522018-02-07 23:57:38 +0000285 // Save the minimized home height
286 dc.getDockedDividerController().getHomeStackBoundsInDockedMode(mMinimizedHomeBounds);
287
Winson Chunge2d72172018-01-25 17:46:20 +0000288 mService.mWindowPlacerLocked.performSurfacePlacement();
289 }
290
Winson Chungda876c92018-04-05 18:31:06 -0700291 @VisibleForTesting
292 AnimationAdapter addAnimation(Task task, boolean isRecentTaskInvisible) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700293 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "addAnimation(" + task.getName() + ")");
Winson Chungda876c92018-04-05 18:31:06 -0700294 // TODO: Refactor this to use the task's animator
Winson Chunge2d72172018-01-25 17:46:20 +0000295 final SurfaceAnimator anim = new SurfaceAnimator(task, null /* animationFinishedCallback */,
Chavi Weingartenb736e322018-02-23 00:27:54 +0000296 mService);
Vadim Tryshev593e9562018-03-08 17:15:45 -0800297 final TaskAnimationAdapter taskAdapter = new TaskAnimationAdapter(task,
298 isRecentTaskInvisible);
Winson Chunge2d72172018-01-25 17:46:20 +0000299 anim.startAnimation(task.getPendingTransaction(), taskAdapter, false /* hidden */);
300 task.commitPendingTransaction();
301 mPendingAnimations.add(taskAdapter);
Winson Chungda876c92018-04-05 18:31:06 -0700302 return taskAdapter;
303 }
304
305 @VisibleForTesting
306 void removeAnimation(TaskAnimationAdapter taskAdapter) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700307 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "removeAnimation("
308 + taskAdapter.mTask.mTaskId + ")");
Winson Chungda876c92018-04-05 18:31:06 -0700309 taskAdapter.mTask.setCanAffectSystemUiFlags(true);
310 taskAdapter.mCapturedFinishCallback.onAnimationFinished(taskAdapter);
311 mPendingAnimations.remove(taskAdapter);
Winson Chunge2d72172018-01-25 17:46:20 +0000312 }
313
314 void startAnimation() {
Winson Chungc6c3f852018-04-09 15:41:03 -0700315 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "startAnimation(): mPendingStart=" + mPendingStart
Winson Chungddf62972018-02-12 11:10:04 -0800316 + " mCanceled=" + mCanceled);
317 if (!mPendingStart || mCanceled) {
318 // Skip starting if we've already started or canceled the animation
Winson Chunge2d72172018-01-25 17:46:20 +0000319 return;
320 }
321 try {
Winson Chung2dc37362018-03-12 17:57:06 -0700322 final ArrayList<RemoteAnimationTarget> appAnimations = new ArrayList<>();
Winson Chunge2d72172018-01-25 17:46:20 +0000323 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
Winson Chungda876c92018-04-05 18:31:06 -0700324 final TaskAnimationAdapter taskAdapter = mPendingAnimations.get(i);
325 final RemoteAnimationTarget target = taskAdapter.createRemoteAnimationApp();
Winson Chung2dc37362018-03-12 17:57:06 -0700326 if (target != null) {
327 appAnimations.add(target);
Winson Chungda876c92018-04-05 18:31:06 -0700328 } else {
329 removeAnimation(taskAdapter);
Winson Chung2dc37362018-03-12 17:57:06 -0700330 }
Winson Chunge2d72172018-01-25 17:46:20 +0000331 }
Winson Chungda876c92018-04-05 18:31:06 -0700332
333 // Skip the animation if there is nothing to animate
334 if (appAnimations.isEmpty()) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700335 cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "startAnimation-noAppWindows");
Winson Chungda876c92018-04-05 18:31:06 -0700336 return;
337 }
338
Winson Chung2dc37362018-03-12 17:57:06 -0700339 final RemoteAnimationTarget[] appTargets = appAnimations.toArray(
340 new RemoteAnimationTarget[appAnimations.size()]);
Winson Chunge2d72172018-01-25 17:46:20 +0000341 mPendingStart = false;
Winson Chung584d6522018-02-07 23:57:38 +0000342
Winson Chung3e2980e2018-03-29 17:28:57 -0700343 final Rect minimizedHomeBounds = mTargetAppToken != null
344 && mTargetAppToken.inSplitScreenSecondaryWindowingMode()
345 ? mMinimizedHomeBounds
346 : null;
347 final Rect contentInsets = mTargetAppToken != null
348 && mTargetAppToken.findMainWindow() != null
349 ? mTargetAppToken.findMainWindow().mContentInsets
350 : null;
Winson Chung2dc37362018-03-12 17:57:06 -0700351 mRunner.onAnimationStart_New(mController, appTargets, contentInsets,
Winson Chung584d6522018-02-07 23:57:38 +0000352 minimizedHomeBounds);
Winson Chungc6c3f852018-04-09 15:41:03 -0700353 if (DEBUG_RECENTS_ANIMATIONS) {
354 Slog.d(TAG, "startAnimation(): Notify animation start:");
355 for (int i = 0; i < mPendingAnimations.size(); i++) {
356 final Task task = mPendingAnimations.get(i).mTask;
357 Slog.d(TAG, "\t" + task.mTaskId);
358 }
359 }
Winson Chunge2d72172018-01-25 17:46:20 +0000360 } catch (RemoteException e) {
361 Slog.e(TAG, "Failed to start recents animation", e);
362 }
Jorim Jaggi54cff642018-03-15 15:51:32 +0100363 final SparseIntArray reasons = new SparseIntArray();
364 reasons.put(WINDOWING_MODE_FULLSCREEN, APP_TRANSITION_RECENTS_ANIM);
365 mService.mH.obtainMessage(NOTIFY_APP_TRANSITION_STARTING,
366 reasons).sendToTarget();
Winson Chunge2d72172018-01-25 17:46:20 +0000367 }
368
Winson Chungc6c3f852018-04-09 15:41:03 -0700369 void cancelAnimation(@ReorderMode int reorderMode, String reason) {
370 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "cancelAnimation()");
Winson Chung65fc89a2018-02-28 08:32:12 -0800371 synchronized (mService.getWindowManagerLock()) {
372 if (mCanceled) {
373 // We've already canceled the animation
374 return;
375 }
Adrian Roos842e7882018-03-26 17:34:06 +0200376 mService.mH.removeCallbacks(mFailsafeRunnable);
Winson Chung65fc89a2018-02-28 08:32:12 -0800377 mCanceled = true;
378 try {
379 mRunner.onAnimationCanceled();
380 } catch (RemoteException e) {
381 Slog.e(TAG, "Failed to cancel recents animation", e);
382 }
Winson Chunge2d72172018-01-25 17:46:20 +0000383 }
Winson Chungf557c3b2018-03-16 10:55:20 -0700384
Winson Chunge2d72172018-01-25 17:46:20 +0000385 // Clean up and return to the previous app
Winson Chung65fc89a2018-02-28 08:32:12 -0800386 // Don't hold the WM lock here as it calls back to AM/RecentsAnimation
Winson Chung6a38fca2018-03-28 17:57:09 -0700387 mCallbacks.onAnimationFinished(reorderMode);
Winson Chunge2d72172018-01-25 17:46:20 +0000388 }
389
Winson Chung6a38fca2018-03-28 17:57:09 -0700390 void cleanupAnimation(@ReorderMode int reorderMode) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700391 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG,
392 "cleanupAnimation(): Notify animation finished mPendingAnimations="
393 + mPendingAnimations.size() + " reorderMode=" + reorderMode);
Winson Chunge2d72172018-01-25 17:46:20 +0000394 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
Winson Chungda876c92018-04-05 18:31:06 -0700395 final TaskAnimationAdapter taskAdapter = mPendingAnimations.get(i);
Winson Chung3e2980e2018-03-29 17:28:57 -0700396 if (reorderMode == REORDER_MOVE_TO_TOP || reorderMode == REORDER_KEEP_IN_PLACE) {
Winson Chungda876c92018-04-05 18:31:06 -0700397 taskAdapter.mTask.dontAnimateDimExit();
chaviw87ca63a2018-03-26 14:06:17 -0700398 }
Winson Chungda876c92018-04-05 18:31:06 -0700399 removeAnimation(taskAdapter);
Winson Chunge2d72172018-01-25 17:46:20 +0000400 }
Winson Chunge2d72172018-01-25 17:46:20 +0000401
Adrian Roos842e7882018-03-26 17:34:06 +0200402 mRunner.asBinder().unlinkToDeath(this, 0);
Winson Chungf557c3b2018-03-16 10:55:20 -0700403 // Clear associated input consumers
Winson Chunge2d72172018-01-25 17:46:20 +0000404 mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
Winson Chunga89ffed2018-01-25 17:46:11 +0000405 mService.destroyInputConsumer(INPUT_CONSUMER_RECENTS_ANIMATION);
Winson Chunge2d72172018-01-25 17:46:20 +0000406 }
407
Adrian Roos842e7882018-03-26 17:34:06 +0200408 void scheduleFailsafe() {
409 mService.mH.postDelayed(mFailsafeRunnable, FAILSAFE_DELAY);
410 }
411
412 @Override
413 public void binderDied() {
Winson Chungc6c3f852018-04-09 15:41:03 -0700414 cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "binderDied");
Adrian Roos842e7882018-03-26 17:34:06 +0200415 }
416
Winson Chunge2d72172018-01-25 17:46:20 +0000417 void checkAnimationReady(WallpaperController wallpaperController) {
418 if (mPendingStart) {
Winson Chung3e2980e2018-03-29 17:28:57 -0700419 final boolean wallpaperReady = !isTargetOverWallpaper()
Winson Chunge2d72172018-01-25 17:46:20 +0000420 || (wallpaperController.getWallpaperTarget() != null
421 && wallpaperController.wallpaperTransitionReady());
422 if (wallpaperReady) {
423 mService.getRecentsAnimationController().startAnimation();
424 }
425 }
426 }
427
Winson Chungf557c3b2018-03-16 10:55:20 -0700428 boolean isSplitScreenMinimized() {
429 return mSplitScreenMinimized;
430 }
431
Winson Chunge2d72172018-01-25 17:46:20 +0000432 boolean isWallpaperVisible(WindowState w) {
Winson Chung3e2980e2018-03-29 17:28:57 -0700433 return w != null && w.mAppToken != null && mTargetAppToken == w.mAppToken
434 && isTargetOverWallpaper();
Winson Chunge2d72172018-01-25 17:46:20 +0000435 }
436
Winson Chunga89ffed2018-01-25 17:46:11 +0000437 boolean hasInputConsumerForApp(AppWindowToken appToken) {
438 return mInputConsumerEnabled && isAnimatingApp(appToken);
439 }
440
441 boolean updateInputConsumerForApp(InputConsumerImpl recentsAnimationInputConsumer,
442 boolean hasFocus) {
Winson Chung3e2980e2018-03-29 17:28:57 -0700443 // Update the input consumer touchable region to match the target app main window
444 final WindowState targetAppMainWindow = mTargetAppToken != null
445 ? mTargetAppToken.findMainWindow()
Winson Chunga89ffed2018-01-25 17:46:11 +0000446 : null;
Winson Chung3e2980e2018-03-29 17:28:57 -0700447 if (targetAppMainWindow != null) {
448 targetAppMainWindow.getBounds(mTmpRect);
Winson Chunga89ffed2018-01-25 17:46:11 +0000449 recentsAnimationInputConsumer.mWindowHandle.hasFocus = hasFocus;
450 recentsAnimationInputConsumer.mWindowHandle.touchableRegion.set(mTmpRect);
451 return true;
452 }
453 return false;
454 }
455
Winson Chung3e2980e2018-03-29 17:28:57 -0700456 private boolean isTargetOverWallpaper() {
457 if (mTargetAppToken == null) {
Winson Chunge2d72172018-01-25 17:46:20 +0000458 return false;
459 }
Winson Chung3e2980e2018-03-29 17:28:57 -0700460 return mTargetAppToken.windowsCanBeWallpaperTarget();
Winson Chunge2d72172018-01-25 17:46:20 +0000461 }
462
Winson Chungd41f71d2018-03-16 15:26:07 -0700463 boolean isAnimatingTask(Task task) {
464 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
465 if (task == mPendingAnimations.get(i).mTask) {
466 return true;
467 }
468 }
469 return false;
470 }
471
Winson Chunga89ffed2018-01-25 17:46:11 +0000472 private boolean isAnimatingApp(AppWindowToken appToken) {
Winson Chunge2d72172018-01-25 17:46:20 +0000473 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
474 final Task task = mPendingAnimations.get(i).mTask;
475 for (int j = task.getChildCount() - 1; j >= 0; j--) {
476 final AppWindowToken app = task.getChildAt(j);
477 if (app == appToken) {
478 return true;
479 }
480 }
481 }
482 return false;
483 }
484
Winson Chungda876c92018-04-05 18:31:06 -0700485 @VisibleForTesting
486 class TaskAnimationAdapter implements AnimationAdapter {
Winson Chunge2d72172018-01-25 17:46:20 +0000487
Vadim Tryshev593e9562018-03-08 17:15:45 -0800488 private final Task mTask;
Winson Chunge2d72172018-01-25 17:46:20 +0000489 private SurfaceControl mCapturedLeash;
490 private OnAnimationFinishedCallback mCapturedFinishCallback;
Vadim Tryshev593e9562018-03-08 17:15:45 -0800491 private final boolean mIsRecentTaskInvisible;
Jorim Jaggif75d1612018-02-27 15:05:21 +0100492 private RemoteAnimationTarget mTarget;
Winson Chungd41f71d2018-03-16 15:26:07 -0700493 private final Point mPosition = new Point();
494 private final Rect mBounds = new Rect();
Winson Chunge2d72172018-01-25 17:46:20 +0000495
Vadim Tryshev593e9562018-03-08 17:15:45 -0800496 TaskAnimationAdapter(Task task, boolean isRecentTaskInvisible) {
Winson Chunge2d72172018-01-25 17:46:20 +0000497 mTask = task;
Vadim Tryshev593e9562018-03-08 17:15:45 -0800498 mIsRecentTaskInvisible = isRecentTaskInvisible;
Winson Chungd41f71d2018-03-16 15:26:07 -0700499 final WindowContainer container = mTask.getParent();
500 container.getRelativePosition(mPosition);
501 container.getBounds(mBounds);
Winson Chunge2d72172018-01-25 17:46:20 +0000502 }
503
504 RemoteAnimationTarget createRemoteAnimationApp() {
Winson Chung584d6522018-02-07 23:57:38 +0000505 final WindowState mainWindow = mTask.getTopVisibleAppMainWindow();
Winson Chung2dc37362018-03-12 17:57:06 -0700506 if (mainWindow == null) {
507 return null;
508 }
Jorim Jaggi817ebdd2018-03-26 15:46:01 +0200509 final Rect insets = new Rect(mainWindow.mContentInsets);
510 InsetUtils.addInsets(insets, mainWindow.mAppToken.getLetterboxInsets());
Jorim Jaggif75d1612018-02-27 15:05:21 +0100511 mTarget = new RemoteAnimationTarget(mTask.mTaskId, MODE_CLOSING, mCapturedLeash,
Winson Chung584d6522018-02-07 23:57:38 +0000512 !mTask.fillsParent(), mainWindow.mWinAnimator.mLastClipRect,
Winson Chungd41f71d2018-03-16 15:26:07 -0700513 insets, mTask.getPrefixOrderIndex(), mPosition, mBounds,
Vadim Tryshev593e9562018-03-08 17:15:45 -0800514 mTask.getWindowConfiguration(), mIsRecentTaskInvisible);
Jorim Jaggif75d1612018-02-27 15:05:21 +0100515 return mTarget;
Winson Chunge2d72172018-01-25 17:46:20 +0000516 }
517
518 @Override
519 public boolean getDetachWallpaper() {
520 return false;
521 }
522
523 @Override
Jorim Jaggi82c17862018-02-21 17:50:18 +0100524 public boolean getShowWallpaper() {
525 return false;
526 }
527
528 @Override
Winson Chunge2d72172018-01-25 17:46:20 +0000529 public int getBackgroundColor() {
530 return 0;
531 }
532
533 @Override
534 public void startAnimation(SurfaceControl animationLeash, Transaction t,
535 OnAnimationFinishedCallback finishCallback) {
Winson Chungd41f71d2018-03-16 15:26:07 -0700536 t.setPosition(animationLeash, mPosition.x, mPosition.y);
Winson Chunge2d72172018-01-25 17:46:20 +0000537 mCapturedLeash = animationLeash;
538 mCapturedFinishCallback = finishCallback;
539 }
540
541 @Override
542 public void onAnimationCancelled(SurfaceControl animationLeash) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700543 cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "taskAnimationAdapterCanceled");
Winson Chunge2d72172018-01-25 17:46:20 +0000544 }
545
546 @Override
547 public long getDurationHint() {
548 return 0;
549 }
550
551 @Override
552 public long getStatusBarTransitionsStartTime() {
553 return SystemClock.uptimeMillis();
554 }
Jorim Jaggif75d1612018-02-27 15:05:21 +0100555
556 @Override
557 public void dump(PrintWriter pw, String prefix) {
558 pw.print(prefix); pw.println("task=" + mTask);
559 if (mTarget != null) {
560 pw.print(prefix); pw.println("Target:");
561 mTarget.dump(pw, prefix + " ");
562 } else {
563 pw.print(prefix); pw.println("Target: null");
564 }
Winson Chungc6c3f852018-04-09 15:41:03 -0700565 pw.println("mIsRecentTaskInvisible=" + mIsRecentTaskInvisible);
566 pw.println("mPosition=" + mPosition);
567 pw.println("mBounds=" + mBounds);
568 pw.println("mIsRecentTaskInvisible=" + mIsRecentTaskInvisible);
Jorim Jaggif75d1612018-02-27 15:05:21 +0100569 }
570
571 @Override
572 public void writeToProto(ProtoOutputStream proto) {
573 final long token = proto.start(REMOTE);
574 if (mTarget != null) {
575 mTarget.writeToProto(proto, TARGET);
576 }
577 proto.end(token);
578 }
Winson Chunge2d72172018-01-25 17:46:20 +0000579 }
580
581 public void dump(PrintWriter pw, String prefix) {
582 final String innerPrefix = prefix + " ";
583 pw.print(prefix); pw.println(RecentsAnimationController.class.getSimpleName() + ":");
584 pw.print(innerPrefix); pw.println("mPendingStart=" + mPendingStart);
Winson Chungc6c3f852018-04-09 15:41:03 -0700585 pw.print(innerPrefix); pw.println("mCanceled=" + mCanceled);
586 pw.print(innerPrefix); pw.println("mInputConsumerEnabled=" + mInputConsumerEnabled);
587 pw.print(innerPrefix); pw.println("mSplitScreenMinimized=" + mSplitScreenMinimized);
Winson Chung3e2980e2018-03-29 17:28:57 -0700588 pw.print(innerPrefix); pw.println("mTargetAppToken=" + mTargetAppToken);
Winson Chungc6c3f852018-04-09 15:41:03 -0700589 pw.print(innerPrefix); pw.println("isTargetOverWallpaper=" + isTargetOverWallpaper());
Winson Chunge2d72172018-01-25 17:46:20 +0000590 }
591}