blob: 1ee642a58e8391b9e7aa6ff89444e413097f0f6e [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
Adrian Roos653c6c12018-04-09 14:12:46 -0700108 private final Rect mTmpRect = new Rect();
109
110 private boolean mLinkedToDeathOfRunner;
Winson Chunga89ffed2018-01-25 17:46:11 +0000111
Winson Chunge2d72172018-01-25 17:46:20 +0000112 public interface RecentsAnimationCallbacks {
Winson Chung6a38fca2018-03-28 17:57:09 -0700113 void onAnimationFinished(@ReorderMode int reorderMode);
Winson Chunge2d72172018-01-25 17:46:20 +0000114 }
115
116 private final IRecentsAnimationController mController =
117 new IRecentsAnimationController.Stub() {
118
119 @Override
120 public TaskSnapshot screenshotTask(int taskId) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700121 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "screenshotTask(" + taskId + "):"
122 + " mCanceled=" + mCanceled);
Winson Chungf557c3b2018-03-16 10:55:20 -0700123 final long token = Binder.clearCallingIdentity();
Winson Chunge2d72172018-01-25 17:46:20 +0000124 try {
125 synchronized (mService.getWindowManagerLock()) {
126 if (mCanceled) {
127 return null;
128 }
129 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
130 final TaskAnimationAdapter adapter = mPendingAnimations.get(i);
131 final Task task = adapter.mTask;
132 if (task.mTaskId == taskId) {
Winson Chung23aa7b12018-02-01 11:41:43 -0800133 final TaskSnapshotController snapshotController =
134 mService.mTaskSnapshotController;
135 final ArraySet<Task> tasks = Sets.newArraySet(task);
136 snapshotController.snapshotTasks(tasks);
137 snapshotController.addSkipClosingAppSnapshotTasks(tasks);
138 return snapshotController.getSnapshot(taskId, 0 /* userId */,
139 false /* restoreFromDisk */, false /* reducedResolution */);
Winson Chunge2d72172018-01-25 17:46:20 +0000140 }
141 }
142 return null;
143 }
144 } finally {
145 Binder.restoreCallingIdentity(token);
146 }
147 }
148
149 @Override
150 public void finish(boolean moveHomeToTop) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700151 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "finish(" + moveHomeToTop + "):"
152 + " mCanceled=" + mCanceled);
Winson Chungf557c3b2018-03-16 10:55:20 -0700153 final long token = Binder.clearCallingIdentity();
Winson Chunge2d72172018-01-25 17:46:20 +0000154 try {
155 synchronized (mService.getWindowManagerLock()) {
156 if (mCanceled) {
157 return;
158 }
159 }
160
161 // Note, the callback will handle its own synchronization, do not lock on WM lock
162 // prior to calling the callback
Winson Chung6a38fca2018-03-28 17:57:09 -0700163 mCallbacks.onAnimationFinished(moveHomeToTop
Winson Chung3e2980e2018-03-29 17:28:57 -0700164 ? REORDER_MOVE_TO_TOP
165 : REORDER_MOVE_TO_ORIGINAL_POSITION);
Winson Chunge2d72172018-01-25 17:46:20 +0000166 } finally {
167 Binder.restoreCallingIdentity(token);
168 }
169 }
170
171 @Override
Jorim Jaggi50bf59c2018-03-09 17:29:48 +0100172 public void setAnimationTargetsBehindSystemBars(boolean behindSystemBars)
173 throws RemoteException {
Winson Chungf557c3b2018-03-16 10:55:20 -0700174 final long token = Binder.clearCallingIdentity();
Jorim Jaggi50bf59c2018-03-09 17:29:48 +0100175 try {
176 synchronized (mService.getWindowManagerLock()) {
177 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
178 mPendingAnimations.get(i).mTask.setCanAffectSystemUiFlags(behindSystemBars);
179 }
180 mService.mWindowPlacerLocked.requestTraversal();
181 }
182 } finally {
183 Binder.restoreCallingIdentity(token);
184 }
185 }
186
187 @Override
Winson Chunge2d72172018-01-25 17:46:20 +0000188 public void setInputConsumerEnabled(boolean enabled) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700189 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "setInputConsumerEnabled(" + enabled + "):"
190 + " mCanceled=" + mCanceled);
Winson Chungf557c3b2018-03-16 10:55:20 -0700191 final long token = Binder.clearCallingIdentity();
Winson Chunge2d72172018-01-25 17:46:20 +0000192 try {
193 synchronized (mService.getWindowManagerLock()) {
194 if (mCanceled) {
195 return;
196 }
197
198 mInputConsumerEnabled = enabled;
199 mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
200 mService.scheduleAnimationLocked();
201 }
202 } finally {
203 Binder.restoreCallingIdentity(token);
204 }
205 }
Winson Chungf557c3b2018-03-16 10:55:20 -0700206
207 @Override
208 public void setSplitScreenMinimized(boolean minimized) {
209 final long token = Binder.clearCallingIdentity();
210 try {
211 synchronized (mService.getWindowManagerLock()) {
212 if (mCanceled) {
213 return;
214 }
215
216 mSplitScreenMinimized = minimized;
217 mService.checkSplitScreenMinimizedChanged(true /* animate */);
218 }
219 } finally {
220 Binder.restoreCallingIdentity(token);
221 }
222 }
Winson Chunge2d72172018-01-25 17:46:20 +0000223 };
224
225 /**
Winson Chunge2d72172018-01-25 17:46:20 +0000226 * @param remoteAnimationRunner The remote runner which should be notified when the animation is
227 * ready to start or has been canceled
228 * @param callbacks Callbacks to be made when the animation finishes
Winson Chunge2d72172018-01-25 17:46:20 +0000229 */
230 RecentsAnimationController(WindowManagerService service,
231 IRecentsAnimationRunner remoteAnimationRunner, RecentsAnimationCallbacks callbacks,
232 int displayId) {
233 mService = service;
234 mRunner = remoteAnimationRunner;
235 mCallbacks = callbacks;
Winson Chungddf62972018-02-12 11:10:04 -0800236 mDisplayId = displayId;
237 }
Winson Chunge2d72172018-01-25 17:46:20 +0000238
Winson Chungddf62972018-02-12 11:10:04 -0800239 /**
240 * Initializes the recents animation controller. This is a separate call from the constructor
241 * because it may call cancelAnimation() which needs to properly clean up the controller
242 * in the window manager.
243 */
Winson Chung3e2980e2018-03-29 17:28:57 -0700244 public void initialize(int targetActivityType, SparseBooleanArray recentTaskIds) {
Winson Chunge2d72172018-01-25 17:46:20 +0000245 // Make leashes for each of the visible tasks and add it to the recents animation to be
246 // started
Winson Chungddf62972018-02-12 11:10:04 -0800247 final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId);
248 final ArrayList<Task> visibleTasks = dc.getVisibleTasks();
Winson Chunge2d72172018-01-25 17:46:20 +0000249 final int taskCount = visibleTasks.size();
250 for (int i = 0; i < taskCount; i++) {
251 final Task task = visibleTasks.get(i);
252 final WindowConfiguration config = task.getWindowConfiguration();
253 if (config.tasksAreFloating()
254 || config.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
Winson Chung3e2980e2018-03-29 17:28:57 -0700255 || config.getActivityType() == targetActivityType) {
Winson Chunge2d72172018-01-25 17:46:20 +0000256 continue;
257 }
Vadim Tryshev593e9562018-03-08 17:15:45 -0800258 addAnimation(task, !recentTaskIds.get(task.mTaskId));
Winson Chunge2d72172018-01-25 17:46:20 +0000259 }
260
Winson Chungddf62972018-02-12 11:10:04 -0800261 // Skip the animation if there is nothing to animate
262 if (mPendingAnimations.isEmpty()) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700263 cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "initialize-noVisibleTasks");
Winson Chungddf62972018-02-12 11:10:04 -0800264 return;
265 }
266
Adrian Roos842e7882018-03-26 17:34:06 +0200267 try {
Adrian Roos653c6c12018-04-09 14:12:46 -0700268 linkToDeathOfRunner();
Adrian Roos842e7882018-03-26 17:34:06 +0200269 } catch (RemoteException e) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700270 cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "initialize-failedToLinkToDeath");
Adrian Roos842e7882018-03-26 17:34:06 +0200271 return;
272 }
273
Winson Chung3e2980e2018-03-29 17:28:57 -0700274 // Adjust the wallpaper visibility for the showing target activity
275 final AppWindowToken recentsComponentAppToken = dc.getStack(WINDOWING_MODE_UNDEFINED,
276 targetActivityType).getTopChild().getTopFullscreenAppToken();
Winson Chunge2d72172018-01-25 17:46:20 +0000277 if (recentsComponentAppToken != null) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700278 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "setHomeApp("
279 + recentsComponentAppToken.getName() + ")");
Winson Chung3e2980e2018-03-29 17:28:57 -0700280 mTargetAppToken = recentsComponentAppToken;
Winson Chunge2d72172018-01-25 17:46:20 +0000281 if (recentsComponentAppToken.windowsCanBeWallpaperTarget()) {
282 dc.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
283 dc.setLayoutNeeded();
284 }
285 }
286
Winson Chung584d6522018-02-07 23:57:38 +0000287 // Save the minimized home height
288 dc.getDockedDividerController().getHomeStackBoundsInDockedMode(mMinimizedHomeBounds);
289
Winson Chunge2d72172018-01-25 17:46:20 +0000290 mService.mWindowPlacerLocked.performSurfacePlacement();
291 }
292
Winson Chungda876c92018-04-05 18:31:06 -0700293 @VisibleForTesting
294 AnimationAdapter addAnimation(Task task, boolean isRecentTaskInvisible) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700295 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "addAnimation(" + task.getName() + ")");
Winson Chungda876c92018-04-05 18:31:06 -0700296 // TODO: Refactor this to use the task's animator
Winson Chunge2d72172018-01-25 17:46:20 +0000297 final SurfaceAnimator anim = new SurfaceAnimator(task, null /* animationFinishedCallback */,
Chavi Weingartenb736e322018-02-23 00:27:54 +0000298 mService);
Vadim Tryshev593e9562018-03-08 17:15:45 -0800299 final TaskAnimationAdapter taskAdapter = new TaskAnimationAdapter(task,
300 isRecentTaskInvisible);
Winson Chunge2d72172018-01-25 17:46:20 +0000301 anim.startAnimation(task.getPendingTransaction(), taskAdapter, false /* hidden */);
302 task.commitPendingTransaction();
303 mPendingAnimations.add(taskAdapter);
Winson Chungda876c92018-04-05 18:31:06 -0700304 return taskAdapter;
305 }
306
307 @VisibleForTesting
308 void removeAnimation(TaskAnimationAdapter taskAdapter) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700309 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "removeAnimation("
310 + taskAdapter.mTask.mTaskId + ")");
Winson Chungda876c92018-04-05 18:31:06 -0700311 taskAdapter.mTask.setCanAffectSystemUiFlags(true);
312 taskAdapter.mCapturedFinishCallback.onAnimationFinished(taskAdapter);
313 mPendingAnimations.remove(taskAdapter);
Winson Chunge2d72172018-01-25 17:46:20 +0000314 }
315
316 void startAnimation() {
Winson Chungc6c3f852018-04-09 15:41:03 -0700317 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "startAnimation(): mPendingStart=" + mPendingStart
Winson Chungddf62972018-02-12 11:10:04 -0800318 + " mCanceled=" + mCanceled);
319 if (!mPendingStart || mCanceled) {
320 // Skip starting if we've already started or canceled the animation
Winson Chunge2d72172018-01-25 17:46:20 +0000321 return;
322 }
323 try {
Winson Chung2dc37362018-03-12 17:57:06 -0700324 final ArrayList<RemoteAnimationTarget> appAnimations = new ArrayList<>();
Winson Chunge2d72172018-01-25 17:46:20 +0000325 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
Winson Chungda876c92018-04-05 18:31:06 -0700326 final TaskAnimationAdapter taskAdapter = mPendingAnimations.get(i);
327 final RemoteAnimationTarget target = taskAdapter.createRemoteAnimationApp();
Winson Chung2dc37362018-03-12 17:57:06 -0700328 if (target != null) {
329 appAnimations.add(target);
Winson Chungda876c92018-04-05 18:31:06 -0700330 } else {
331 removeAnimation(taskAdapter);
Winson Chung2dc37362018-03-12 17:57:06 -0700332 }
Winson Chunge2d72172018-01-25 17:46:20 +0000333 }
Winson Chungda876c92018-04-05 18:31:06 -0700334
335 // Skip the animation if there is nothing to animate
336 if (appAnimations.isEmpty()) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700337 cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "startAnimation-noAppWindows");
Winson Chungda876c92018-04-05 18:31:06 -0700338 return;
339 }
340
Winson Chung2dc37362018-03-12 17:57:06 -0700341 final RemoteAnimationTarget[] appTargets = appAnimations.toArray(
342 new RemoteAnimationTarget[appAnimations.size()]);
Winson Chunge2d72172018-01-25 17:46:20 +0000343 mPendingStart = false;
Winson Chung584d6522018-02-07 23:57:38 +0000344
Winson Chung3e2980e2018-03-29 17:28:57 -0700345 final Rect minimizedHomeBounds = mTargetAppToken != null
346 && mTargetAppToken.inSplitScreenSecondaryWindowingMode()
347 ? mMinimizedHomeBounds
348 : null;
349 final Rect contentInsets = mTargetAppToken != null
350 && mTargetAppToken.findMainWindow() != null
351 ? mTargetAppToken.findMainWindow().mContentInsets
352 : null;
Winson Chung2dc37362018-03-12 17:57:06 -0700353 mRunner.onAnimationStart_New(mController, appTargets, contentInsets,
Winson Chung584d6522018-02-07 23:57:38 +0000354 minimizedHomeBounds);
Winson Chungc6c3f852018-04-09 15:41:03 -0700355 if (DEBUG_RECENTS_ANIMATIONS) {
356 Slog.d(TAG, "startAnimation(): Notify animation start:");
357 for (int i = 0; i < mPendingAnimations.size(); i++) {
358 final Task task = mPendingAnimations.get(i).mTask;
359 Slog.d(TAG, "\t" + task.mTaskId);
360 }
361 }
Winson Chunge2d72172018-01-25 17:46:20 +0000362 } catch (RemoteException e) {
363 Slog.e(TAG, "Failed to start recents animation", e);
364 }
Jorim Jaggi54cff642018-03-15 15:51:32 +0100365 final SparseIntArray reasons = new SparseIntArray();
366 reasons.put(WINDOWING_MODE_FULLSCREEN, APP_TRANSITION_RECENTS_ANIM);
367 mService.mH.obtainMessage(NOTIFY_APP_TRANSITION_STARTING,
368 reasons).sendToTarget();
Winson Chunge2d72172018-01-25 17:46:20 +0000369 }
370
Winson Chungc6c3f852018-04-09 15:41:03 -0700371 void cancelAnimation(@ReorderMode int reorderMode, String reason) {
372 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "cancelAnimation()");
Winson Chung65fc89a2018-02-28 08:32:12 -0800373 synchronized (mService.getWindowManagerLock()) {
374 if (mCanceled) {
375 // We've already canceled the animation
376 return;
377 }
Adrian Roos842e7882018-03-26 17:34:06 +0200378 mService.mH.removeCallbacks(mFailsafeRunnable);
Winson Chung65fc89a2018-02-28 08:32:12 -0800379 mCanceled = true;
380 try {
381 mRunner.onAnimationCanceled();
382 } catch (RemoteException e) {
383 Slog.e(TAG, "Failed to cancel recents animation", e);
384 }
Winson Chunge2d72172018-01-25 17:46:20 +0000385 }
Winson Chungf557c3b2018-03-16 10:55:20 -0700386
Winson Chunge2d72172018-01-25 17:46:20 +0000387 // Clean up and return to the previous app
Winson Chung65fc89a2018-02-28 08:32:12 -0800388 // Don't hold the WM lock here as it calls back to AM/RecentsAnimation
Winson Chung6a38fca2018-03-28 17:57:09 -0700389 mCallbacks.onAnimationFinished(reorderMode);
Winson Chunge2d72172018-01-25 17:46:20 +0000390 }
391
Winson Chung6a38fca2018-03-28 17:57:09 -0700392 void cleanupAnimation(@ReorderMode int reorderMode) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700393 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG,
394 "cleanupAnimation(): Notify animation finished mPendingAnimations="
395 + mPendingAnimations.size() + " reorderMode=" + reorderMode);
Winson Chunge2d72172018-01-25 17:46:20 +0000396 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
Winson Chungda876c92018-04-05 18:31:06 -0700397 final TaskAnimationAdapter taskAdapter = mPendingAnimations.get(i);
Winson Chung3e2980e2018-03-29 17:28:57 -0700398 if (reorderMode == REORDER_MOVE_TO_TOP || reorderMode == REORDER_KEEP_IN_PLACE) {
Winson Chungda876c92018-04-05 18:31:06 -0700399 taskAdapter.mTask.dontAnimateDimExit();
chaviw87ca63a2018-03-26 14:06:17 -0700400 }
Winson Chungda876c92018-04-05 18:31:06 -0700401 removeAnimation(taskAdapter);
Winson Chunge2d72172018-01-25 17:46:20 +0000402 }
Winson Chunge2d72172018-01-25 17:46:20 +0000403
Adrian Roos653c6c12018-04-09 14:12:46 -0700404 unlinkToDeathOfRunner();
Winson Chungf557c3b2018-03-16 10:55:20 -0700405 // Clear associated input consumers
Winson Chunge2d72172018-01-25 17:46:20 +0000406 mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
Winson Chunga89ffed2018-01-25 17:46:11 +0000407 mService.destroyInputConsumer(INPUT_CONSUMER_RECENTS_ANIMATION);
Winson Chunge2d72172018-01-25 17:46:20 +0000408 }
409
Adrian Roos842e7882018-03-26 17:34:06 +0200410 void scheduleFailsafe() {
411 mService.mH.postDelayed(mFailsafeRunnable, FAILSAFE_DELAY);
412 }
413
Adrian Roos653c6c12018-04-09 14:12:46 -0700414 private void linkToDeathOfRunner() throws RemoteException {
415 if (!mLinkedToDeathOfRunner) {
416 mRunner.asBinder().linkToDeath(this, 0);
417 mLinkedToDeathOfRunner = true;
418 }
419 }
420
421 private void unlinkToDeathOfRunner() {
422 if (mLinkedToDeathOfRunner) {
423 mRunner.asBinder().unlinkToDeath(this, 0);
424 mLinkedToDeathOfRunner = false;
425 }
426 }
427
Adrian Roos842e7882018-03-26 17:34:06 +0200428 @Override
429 public void binderDied() {
Winson Chungc6c3f852018-04-09 15:41:03 -0700430 cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "binderDied");
Adrian Roos842e7882018-03-26 17:34:06 +0200431 }
432
Winson Chunge2d72172018-01-25 17:46:20 +0000433 void checkAnimationReady(WallpaperController wallpaperController) {
434 if (mPendingStart) {
Winson Chung3e2980e2018-03-29 17:28:57 -0700435 final boolean wallpaperReady = !isTargetOverWallpaper()
Winson Chunge2d72172018-01-25 17:46:20 +0000436 || (wallpaperController.getWallpaperTarget() != null
437 && wallpaperController.wallpaperTransitionReady());
438 if (wallpaperReady) {
439 mService.getRecentsAnimationController().startAnimation();
440 }
441 }
442 }
443
Winson Chungf557c3b2018-03-16 10:55:20 -0700444 boolean isSplitScreenMinimized() {
445 return mSplitScreenMinimized;
446 }
447
Winson Chunge2d72172018-01-25 17:46:20 +0000448 boolean isWallpaperVisible(WindowState w) {
Winson Chung3e2980e2018-03-29 17:28:57 -0700449 return w != null && w.mAppToken != null && mTargetAppToken == w.mAppToken
450 && isTargetOverWallpaper();
Winson Chunge2d72172018-01-25 17:46:20 +0000451 }
452
Winson Chunga89ffed2018-01-25 17:46:11 +0000453 boolean hasInputConsumerForApp(AppWindowToken appToken) {
454 return mInputConsumerEnabled && isAnimatingApp(appToken);
455 }
456
457 boolean updateInputConsumerForApp(InputConsumerImpl recentsAnimationInputConsumer,
458 boolean hasFocus) {
Winson Chung3e2980e2018-03-29 17:28:57 -0700459 // Update the input consumer touchable region to match the target app main window
460 final WindowState targetAppMainWindow = mTargetAppToken != null
461 ? mTargetAppToken.findMainWindow()
Winson Chunga89ffed2018-01-25 17:46:11 +0000462 : null;
Winson Chung3e2980e2018-03-29 17:28:57 -0700463 if (targetAppMainWindow != null) {
464 targetAppMainWindow.getBounds(mTmpRect);
Winson Chunga89ffed2018-01-25 17:46:11 +0000465 recentsAnimationInputConsumer.mWindowHandle.hasFocus = hasFocus;
466 recentsAnimationInputConsumer.mWindowHandle.touchableRegion.set(mTmpRect);
467 return true;
468 }
469 return false;
470 }
471
Winson Chung3e2980e2018-03-29 17:28:57 -0700472 private boolean isTargetOverWallpaper() {
473 if (mTargetAppToken == null) {
Winson Chunge2d72172018-01-25 17:46:20 +0000474 return false;
475 }
Winson Chung3e2980e2018-03-29 17:28:57 -0700476 return mTargetAppToken.windowsCanBeWallpaperTarget();
Winson Chunge2d72172018-01-25 17:46:20 +0000477 }
478
Winson Chungd41f71d2018-03-16 15:26:07 -0700479 boolean isAnimatingTask(Task task) {
480 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
481 if (task == mPendingAnimations.get(i).mTask) {
482 return true;
483 }
484 }
485 return false;
486 }
487
Winson Chunga89ffed2018-01-25 17:46:11 +0000488 private boolean isAnimatingApp(AppWindowToken appToken) {
Winson Chunge2d72172018-01-25 17:46:20 +0000489 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
490 final Task task = mPendingAnimations.get(i).mTask;
491 for (int j = task.getChildCount() - 1; j >= 0; j--) {
492 final AppWindowToken app = task.getChildAt(j);
493 if (app == appToken) {
494 return true;
495 }
496 }
497 }
498 return false;
499 }
500
Winson Chungda876c92018-04-05 18:31:06 -0700501 @VisibleForTesting
502 class TaskAnimationAdapter implements AnimationAdapter {
Winson Chunge2d72172018-01-25 17:46:20 +0000503
Vadim Tryshev593e9562018-03-08 17:15:45 -0800504 private final Task mTask;
Winson Chunge2d72172018-01-25 17:46:20 +0000505 private SurfaceControl mCapturedLeash;
506 private OnAnimationFinishedCallback mCapturedFinishCallback;
Vadim Tryshev593e9562018-03-08 17:15:45 -0800507 private final boolean mIsRecentTaskInvisible;
Jorim Jaggif75d1612018-02-27 15:05:21 +0100508 private RemoteAnimationTarget mTarget;
Winson Chungd41f71d2018-03-16 15:26:07 -0700509 private final Point mPosition = new Point();
510 private final Rect mBounds = new Rect();
Winson Chunge2d72172018-01-25 17:46:20 +0000511
Vadim Tryshev593e9562018-03-08 17:15:45 -0800512 TaskAnimationAdapter(Task task, boolean isRecentTaskInvisible) {
Winson Chunge2d72172018-01-25 17:46:20 +0000513 mTask = task;
Vadim Tryshev593e9562018-03-08 17:15:45 -0800514 mIsRecentTaskInvisible = isRecentTaskInvisible;
Winson Chungd41f71d2018-03-16 15:26:07 -0700515 final WindowContainer container = mTask.getParent();
516 container.getRelativePosition(mPosition);
517 container.getBounds(mBounds);
Winson Chunge2d72172018-01-25 17:46:20 +0000518 }
519
520 RemoteAnimationTarget createRemoteAnimationApp() {
Winson Chung584d6522018-02-07 23:57:38 +0000521 final WindowState mainWindow = mTask.getTopVisibleAppMainWindow();
Winson Chung2dc37362018-03-12 17:57:06 -0700522 if (mainWindow == null) {
523 return null;
524 }
Jorim Jaggi817ebdd2018-03-26 15:46:01 +0200525 final Rect insets = new Rect(mainWindow.mContentInsets);
526 InsetUtils.addInsets(insets, mainWindow.mAppToken.getLetterboxInsets());
Jorim Jaggif75d1612018-02-27 15:05:21 +0100527 mTarget = new RemoteAnimationTarget(mTask.mTaskId, MODE_CLOSING, mCapturedLeash,
Winson Chung584d6522018-02-07 23:57:38 +0000528 !mTask.fillsParent(), mainWindow.mWinAnimator.mLastClipRect,
Winson Chungd41f71d2018-03-16 15:26:07 -0700529 insets, mTask.getPrefixOrderIndex(), mPosition, mBounds,
Vadim Tryshev593e9562018-03-08 17:15:45 -0800530 mTask.getWindowConfiguration(), mIsRecentTaskInvisible);
Jorim Jaggif75d1612018-02-27 15:05:21 +0100531 return mTarget;
Winson Chunge2d72172018-01-25 17:46:20 +0000532 }
533
534 @Override
535 public boolean getDetachWallpaper() {
536 return false;
537 }
538
539 @Override
Jorim Jaggi82c17862018-02-21 17:50:18 +0100540 public boolean getShowWallpaper() {
541 return false;
542 }
543
544 @Override
Winson Chunge2d72172018-01-25 17:46:20 +0000545 public int getBackgroundColor() {
546 return 0;
547 }
548
549 @Override
550 public void startAnimation(SurfaceControl animationLeash, Transaction t,
551 OnAnimationFinishedCallback finishCallback) {
Winson Chungd41f71d2018-03-16 15:26:07 -0700552 t.setPosition(animationLeash, mPosition.x, mPosition.y);
Winson Chunge2d72172018-01-25 17:46:20 +0000553 mCapturedLeash = animationLeash;
554 mCapturedFinishCallback = finishCallback;
555 }
556
557 @Override
558 public void onAnimationCancelled(SurfaceControl animationLeash) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700559 cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "taskAnimationAdapterCanceled");
Winson Chunge2d72172018-01-25 17:46:20 +0000560 }
561
562 @Override
563 public long getDurationHint() {
564 return 0;
565 }
566
567 @Override
568 public long getStatusBarTransitionsStartTime() {
569 return SystemClock.uptimeMillis();
570 }
Jorim Jaggif75d1612018-02-27 15:05:21 +0100571
572 @Override
573 public void dump(PrintWriter pw, String prefix) {
574 pw.print(prefix); pw.println("task=" + mTask);
575 if (mTarget != null) {
576 pw.print(prefix); pw.println("Target:");
577 mTarget.dump(pw, prefix + " ");
578 } else {
579 pw.print(prefix); pw.println("Target: null");
580 }
Winson Chungc6c3f852018-04-09 15:41:03 -0700581 pw.println("mIsRecentTaskInvisible=" + mIsRecentTaskInvisible);
582 pw.println("mPosition=" + mPosition);
583 pw.println("mBounds=" + mBounds);
584 pw.println("mIsRecentTaskInvisible=" + mIsRecentTaskInvisible);
Jorim Jaggif75d1612018-02-27 15:05:21 +0100585 }
586
587 @Override
588 public void writeToProto(ProtoOutputStream proto) {
589 final long token = proto.start(REMOTE);
590 if (mTarget != null) {
591 mTarget.writeToProto(proto, TARGET);
592 }
593 proto.end(token);
594 }
Winson Chunge2d72172018-01-25 17:46:20 +0000595 }
596
597 public void dump(PrintWriter pw, String prefix) {
598 final String innerPrefix = prefix + " ";
599 pw.print(prefix); pw.println(RecentsAnimationController.class.getSimpleName() + ":");
600 pw.print(innerPrefix); pw.println("mPendingStart=" + mPendingStart);
Winson Chungc6c3f852018-04-09 15:41:03 -0700601 pw.print(innerPrefix); pw.println("mCanceled=" + mCanceled);
602 pw.print(innerPrefix); pw.println("mInputConsumerEnabled=" + mInputConsumerEnabled);
603 pw.print(innerPrefix); pw.println("mSplitScreenMinimized=" + mSplitScreenMinimized);
Winson Chung3e2980e2018-03-29 17:28:57 -0700604 pw.print(innerPrefix); pw.println("mTargetAppToken=" + mTargetAppToken);
Winson Chungc6c3f852018-04-09 15:41:03 -0700605 pw.print(innerPrefix); pw.println("isTargetOverWallpaper=" + isTargetOverWallpaper());
Winson Chunge2d72172018-01-25 17:46:20 +0000606 }
607}