blob: 985c77a81f7a7656a2ac03fcb68ec89c103c00f3 [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.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
Winson Chunge2d72172018-01-25 17:46:20 +000020import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
Winson Chung3e2980e2018-03-29 17:28:57 -070021import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
Winson Chunge2d72172018-01-25 17:46:20 +000022import static android.view.RemoteAnimationTarget.MODE_CLOSING;
Winson Chung732446a2018-09-19 13:15:17 -070023import static android.view.RemoteAnimationTarget.MODE_OPENING;
Evan Roskyc5abbd82018-10-05 16:02:19 -070024import static android.view.WindowManager.DOCKED_INVALID;
Winson Chunga89ffed2018-01-25 17:46:11 +000025import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
Jorim Jaggiceeb06d2019-06-11 16:19:36 +020026import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
Tracy Zhou8089ffa2019-07-30 17:30:43 -070027
Winson Chunge2d72172018-01-25 17:46:20 +000028import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -070029import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_RECENTS_ANIM;
Yi Jin6c6e9ca2018-03-20 16:53:35 -070030import static com.android.server.wm.AnimationAdapterProto.REMOTE;
Tracy Zhou9c675d42019-04-08 00:32:40 -070031import static com.android.server.wm.BoundsAnimationController.FADE_IN;
Winson Chungc6c3f852018-04-09 15:41:03 -070032import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET;
33import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RECENTS_ANIMATIONS;
lumark54284462019-03-05 20:44:27 +080034import static com.android.server.wm.WindowManagerInternal.AppTransitionListener;
Winson Chunge2d72172018-01-25 17:46:20 +000035
Winson Chung6a38fca2018-03-28 17:57:09 -070036import android.annotation.IntDef;
Winson Chunge2d72172018-01-25 17:46:20 +000037import android.app.ActivityManager.TaskSnapshot;
38import android.app.WindowConfiguration;
Winson Chunge2d72172018-01-25 17:46:20 +000039import android.graphics.Point;
40import android.graphics.Rect;
41import android.os.Binder;
Adrian Roos842e7882018-03-26 17:34:06 +020042import android.os.IBinder.DeathRecipient;
Winson Chunge2d72172018-01-25 17:46:20 +000043import android.os.RemoteException;
44import android.os.SystemClock;
Winson Chung23aa7b12018-02-01 11:41:43 -080045import android.util.ArraySet;
Winson Chungc6c3f852018-04-09 15:41:03 -070046import android.util.Slog;
Vadim Tryshev593e9562018-03-08 17:15:45 -080047import android.util.SparseBooleanArray;
Jorim Jaggi54cff642018-03-15 15:51:32 +010048import android.util.SparseIntArray;
Winson Chungc6c3f852018-04-09 15:41:03 -070049import android.util.proto.ProtoOutputStream;
Winson Chunge2d72172018-01-25 17:46:20 +000050import android.view.IRecentsAnimationController;
51import android.view.IRecentsAnimationRunner;
Evan Roskyc5abbd82018-10-05 16:02:19 -070052import android.view.InputWindowHandle;
Winson Chunge2d72172018-01-25 17:46:20 +000053import android.view.RemoteAnimationTarget;
54import android.view.SurfaceControl;
55import android.view.SurfaceControl.Transaction;
Evan Roskyc5abbd82018-10-05 16:02:19 -070056
Winson Chungda876c92018-04-05 18:31:06 -070057import com.android.internal.annotations.VisibleForTesting;
Winson Chunga840c322018-04-20 15:58:18 -070058import com.android.server.LocalServices;
Yohei Yukawac3de83e2018-08-28 16:09:34 -070059import com.android.server.inputmethod.InputMethodManagerInternal;
Winson Chung67e49362019-05-17 16:40:38 -070060import com.android.server.statusbar.StatusBarManagerInternal;
Jorim Jaggif75d1612018-02-27 15:05:21 +010061import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
Jorim Jaggi817ebdd2018-03-26 15:46:01 +020062import com.android.server.wm.utils.InsetUtils;
Evan Roskyc5abbd82018-10-05 16:02:19 -070063
Vadim Tryshev257f86b2018-08-23 16:45:02 -070064import com.google.android.collect.Sets;
Evan Roskyc5abbd82018-10-05 16:02:19 -070065
Winson Chunge2d72172018-01-25 17:46:20 +000066import java.io.PrintWriter;
67import java.util.ArrayList;
Winson Chungc6c3f852018-04-09 15:41:03 -070068
Winson Chunge2d72172018-01-25 17:46:20 +000069/**
70 * Controls a single instance of the remote driven recents animation. In particular, this allows
71 * the calling SystemUI to animate the visible task windows as a part of the transition. The remote
72 * runner is provided an animation controller which allows it to take screenshots and to notify
73 * window manager when the animation is completed. In addition, window manager may also notify the
74 * app if it requires the animation to be canceled at any time (ie. due to timeout, etc.)
75 */
Adrian Roos842e7882018-03-26 17:34:06 +020076public class RecentsAnimationController implements DeathRecipient {
Winson Chungc6c3f852018-04-09 15:41:03 -070077 private static final String TAG = RecentsAnimationController.class.getSimpleName();
Adrian Roos842e7882018-03-26 17:34:06 +020078 private static final long FAILSAFE_DELAY = 1000;
Winson Chunge2d72172018-01-25 17:46:20 +000079
Winson Chung3e2980e2018-03-29 17:28:57 -070080 public static final int REORDER_KEEP_IN_PLACE = 0;
81 public static final int REORDER_MOVE_TO_TOP = 1;
82 public static final int REORDER_MOVE_TO_ORIGINAL_POSITION = 2;
Winson Chung6a38fca2018-03-28 17:57:09 -070083
84 @IntDef(prefix = { "REORDER_MODE_" }, value = {
Winson Chung3e2980e2018-03-29 17:28:57 -070085 REORDER_KEEP_IN_PLACE,
86 REORDER_MOVE_TO_TOP,
87 REORDER_MOVE_TO_ORIGINAL_POSITION
Winson Chung6a38fca2018-03-28 17:57:09 -070088 })
89 public @interface ReorderMode {}
90
Winson Chunge2d72172018-01-25 17:46:20 +000091 private final WindowManagerService mService;
Winson Chung67e49362019-05-17 16:40:38 -070092 private final StatusBarManagerInternal mStatusBar;
Winson Chung5c91e8f2018-05-07 10:06:55 -070093 private IRecentsAnimationRunner mRunner;
Winson Chunge2d72172018-01-25 17:46:20 +000094 private final RecentsAnimationCallbacks mCallbacks;
95 private final ArrayList<TaskAnimationAdapter> mPendingAnimations = new ArrayList<>();
Winson Chungd5852192019-09-06 17:20:28 -070096 private final ArrayList<WallpaperAnimationAdapter> mPendingWallpaperAnimations =
97 new ArrayList<>();
Winson Chungddf62972018-02-12 11:10:04 -080098 private final int mDisplayId;
Winson Chung65c5f992018-04-20 14:58:57 -070099 private final Runnable mFailsafeRunnable = () ->
100 cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "failSafeRunnable");
Winson Chunge2d72172018-01-25 17:46:20 +0000101
102 // The recents component app token that is shown behind the visibile tasks
Winson Chung3e2980e2018-03-29 17:28:57 -0700103 private AppWindowToken mTargetAppToken;
Winson Chung7a545ae2019-07-16 14:52:13 -0700104 private DisplayContent mDisplayContent;
Winson Chung732446a2018-09-19 13:15:17 -0700105 private int mTargetActivityType;
Winson Chung584d6522018-02-07 23:57:38 +0000106 private Rect mMinimizedHomeBounds = new Rect();
Winson Chunge2d72172018-01-25 17:46:20 +0000107
108 // We start the RecentsAnimationController in a pending-start state since we need to wait for
109 // the wallpaper/activity to draw before we can give control to the handler to start animating
110 // the visible task surfaces
111 private boolean mPendingStart = true;
112
113 // Set when the animation has been canceled
Winson Chungf557c3b2018-03-16 10:55:20 -0700114 private boolean mCanceled;
Winson Chunge2d72172018-01-25 17:46:20 +0000115
116 // Whether or not the input consumer is enabled. The input consumer must be both registered and
117 // enabled for it to start intercepting touch events.
118 private boolean mInputConsumerEnabled;
119
Winson Chungf557c3b2018-03-16 10:55:20 -0700120 // Whether or not the recents animation should cause the primary split-screen stack to be
121 // minimized
122 private boolean mSplitScreenMinimized;
123
Adrian Roos653c6c12018-04-09 14:12:46 -0700124 private final Rect mTmpRect = new Rect();
125
126 private boolean mLinkedToDeathOfRunner;
Winson Chunga89ffed2018-01-25 17:46:11 +0000127
Winson Chung7a545ae2019-07-16 14:52:13 -0700128 // Whether to try to defer canceling from a stack order change until the next transition
129 private boolean mRequestDeferCancelUntilNextTransition;
130 // Whether to actually defer canceling until the next transition
lumark54284462019-03-05 20:44:27 +0800131 private boolean mCancelOnNextTransitionStart;
Winson Chung7a545ae2019-07-16 14:52:13 -0700132 // Whether to take a screenshot when handling a deferred cancel
133 private boolean mCancelDeferredWithScreenshot;
lumark54284462019-03-05 20:44:27 +0800134
135 /**
136 * Animates the screenshot of task that used to be controlled by RecentsAnimation.
Winson Chung7a545ae2019-07-16 14:52:13 -0700137 * @see {@link #setCancelOnNextTransitionStart}
lumark54284462019-03-05 20:44:27 +0800138 */
139 SurfaceAnimator mRecentScreenshotAnimator;
140
Winson Chung7a545ae2019-07-16 14:52:13 -0700141 /**
142 * An app transition listener to cancel the recents animation only after the app transition
143 * starts or is canceled.
144 */
lumark54284462019-03-05 20:44:27 +0800145 final AppTransitionListener mAppTransitionListener = new AppTransitionListener() {
146 @Override
147 public int onAppTransitionStartingLocked(int transit, long duration,
148 long statusBarAnimationStartTime, long statusBarAnimationDuration) {
Winson Chung7a545ae2019-07-16 14:52:13 -0700149 continueDeferredCancel();
lumark54284462019-03-05 20:44:27 +0800150 return 0;
151 }
Winson Chung7a545ae2019-07-16 14:52:13 -0700152
153 @Override
154 public void onAppTransitionCancelledLocked(int transit) {
155 continueDeferredCancel();
156 }
157
158 private void continueDeferredCancel() {
159 mDisplayContent.mAppTransition.unregisterListener(this);
160 if (mCanceled) {
161 return;
162 }
163
164 if (mCancelOnNextTransitionStart) {
165 mCancelOnNextTransitionStart = false;
166 cancelAnimationWithScreenshot(mCancelDeferredWithScreenshot);
167 }
168 }
lumark54284462019-03-05 20:44:27 +0800169 };
170
Winson Chunge2d72172018-01-25 17:46:20 +0000171 public interface RecentsAnimationCallbacks {
Tracy Zhou9c675d42019-04-08 00:32:40 -0700172 /** Callback when recents animation is finished. */
Wale Ogunwalea441b922019-06-27 19:21:44 -0700173 void onAnimationFinished(@ReorderMode int reorderMode, boolean sendUserLeaveHint);
Winson Chunge2d72172018-01-25 17:46:20 +0000174 }
175
176 private final IRecentsAnimationController mController =
177 new IRecentsAnimationController.Stub() {
178
179 @Override
180 public TaskSnapshot screenshotTask(int taskId) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700181 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "screenshotTask(" + taskId + "):"
182 + " mCanceled=" + mCanceled);
Winson Chungf557c3b2018-03-16 10:55:20 -0700183 final long token = Binder.clearCallingIdentity();
Winson Chunge2d72172018-01-25 17:46:20 +0000184 try {
185 synchronized (mService.getWindowManagerLock()) {
186 if (mCanceled) {
187 return null;
188 }
189 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
190 final TaskAnimationAdapter adapter = mPendingAnimations.get(i);
191 final Task task = adapter.mTask;
192 if (task.mTaskId == taskId) {
Winson Chung23aa7b12018-02-01 11:41:43 -0800193 final TaskSnapshotController snapshotController =
194 mService.mTaskSnapshotController;
195 final ArraySet<Task> tasks = Sets.newArraySet(task);
196 snapshotController.snapshotTasks(tasks);
197 snapshotController.addSkipClosingAppSnapshotTasks(tasks);
198 return snapshotController.getSnapshot(taskId, 0 /* userId */,
199 false /* restoreFromDisk */, false /* reducedResolution */);
Winson Chunge2d72172018-01-25 17:46:20 +0000200 }
201 }
202 return null;
203 }
204 } finally {
205 Binder.restoreCallingIdentity(token);
206 }
207 }
208
209 @Override
Tracy Zhou9c675d42019-04-08 00:32:40 -0700210 public void finish(boolean moveHomeToTop, boolean sendUserLeaveHint) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700211 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "finish(" + moveHomeToTop + "):"
212 + " mCanceled=" + mCanceled);
Winson Chungf557c3b2018-03-16 10:55:20 -0700213 final long token = Binder.clearCallingIdentity();
Winson Chunge2d72172018-01-25 17:46:20 +0000214 try {
215 synchronized (mService.getWindowManagerLock()) {
216 if (mCanceled) {
217 return;
218 }
219 }
220
221 // Note, the callback will handle its own synchronization, do not lock on WM lock
222 // prior to calling the callback
Winson Chung6a38fca2018-03-28 17:57:09 -0700223 mCallbacks.onAnimationFinished(moveHomeToTop
Winson Chung3e2980e2018-03-29 17:28:57 -0700224 ? REORDER_MOVE_TO_TOP
Wale Ogunwalea441b922019-06-27 19:21:44 -0700225 : REORDER_MOVE_TO_ORIGINAL_POSITION, sendUserLeaveHint);
Winson Chung7a545ae2019-07-16 14:52:13 -0700226 mDisplayContent.mBoundsAnimationController.setAnimationType(FADE_IN);
Winson Chunge2d72172018-01-25 17:46:20 +0000227 } finally {
228 Binder.restoreCallingIdentity(token);
229 }
230 }
231
232 @Override
Jorim Jaggi50bf59c2018-03-09 17:29:48 +0100233 public void setAnimationTargetsBehindSystemBars(boolean behindSystemBars)
234 throws RemoteException {
Winson Chungf557c3b2018-03-16 10:55:20 -0700235 final long token = Binder.clearCallingIdentity();
Jorim Jaggi50bf59c2018-03-09 17:29:48 +0100236 try {
237 synchronized (mService.getWindowManagerLock()) {
238 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
Winson Chungce48a252019-03-21 11:03:03 -0700239 final Task task = mPendingAnimations.get(i).mTask;
240 if (task.getActivityType() != mTargetActivityType) {
241 task.setCanAffectSystemUiFlags(behindSystemBars);
242 }
Jorim Jaggi50bf59c2018-03-09 17:29:48 +0100243 }
244 mService.mWindowPlacerLocked.requestTraversal();
245 }
246 } finally {
247 Binder.restoreCallingIdentity(token);
248 }
249 }
250
251 @Override
Winson Chunge2d72172018-01-25 17:46:20 +0000252 public void setInputConsumerEnabled(boolean enabled) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700253 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "setInputConsumerEnabled(" + enabled + "):"
254 + " mCanceled=" + mCanceled);
Winson Chungf557c3b2018-03-16 10:55:20 -0700255 final long token = Binder.clearCallingIdentity();
Winson Chunge2d72172018-01-25 17:46:20 +0000256 try {
257 synchronized (mService.getWindowManagerLock()) {
258 if (mCanceled) {
259 return;
260 }
261
262 mInputConsumerEnabled = enabled;
Winson Chung7a545ae2019-07-16 14:52:13 -0700263 final InputMonitor inputMonitor = mDisplayContent.getInputMonitor();
Arthur Hung95b38a92018-07-20 18:56:12 +0800264 inputMonitor.updateInputWindowsLw(true /*force*/);
Winson Chunge2d72172018-01-25 17:46:20 +0000265 mService.scheduleAnimationLocked();
266 }
267 } finally {
268 Binder.restoreCallingIdentity(token);
269 }
270 }
Winson Chungf557c3b2018-03-16 10:55:20 -0700271
272 @Override
273 public void setSplitScreenMinimized(boolean minimized) {
274 final long token = Binder.clearCallingIdentity();
275 try {
276 synchronized (mService.getWindowManagerLock()) {
277 if (mCanceled) {
278 return;
279 }
280
281 mSplitScreenMinimized = minimized;
282 mService.checkSplitScreenMinimizedChanged(true /* animate */);
283 }
284 } finally {
285 Binder.restoreCallingIdentity(token);
286 }
287 }
Winson Chunga840c322018-04-20 15:58:18 -0700288
289 @Override
290 public void hideCurrentInputMethod() {
291 final long token = Binder.clearCallingIdentity();
292 try {
293 final InputMethodManagerInternal inputMethodManagerInternal =
294 LocalServices.getService(InputMethodManagerInternal.class);
295 if (inputMethodManagerInternal != null) {
296 inputMethodManagerInternal.hideCurrentInputMethod();
297 }
298 } finally {
299 Binder.restoreCallingIdentity(token);
300 }
301 }
lumark54284462019-03-05 20:44:27 +0800302
303 @Override
Winson Chung7a545ae2019-07-16 14:52:13 -0700304 @Deprecated
lumark54284462019-03-05 20:44:27 +0800305 public void setCancelWithDeferredScreenshot(boolean screenshot) {
Winson Chung7a545ae2019-07-16 14:52:13 -0700306 synchronized (mService.mGlobalLock) {
307 setDeferredCancel(true /* deferred */, screenshot);
308 }
309 }
310
311 @Override
312 public void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot) {
313 synchronized (mService.mGlobalLock) {
314 setDeferredCancel(defer, screenshot);
lumark54284462019-03-05 20:44:27 +0800315 }
316 }
317
318 @Override
319 public void cleanupScreenshot() {
Winson Chung7a545ae2019-07-16 14:52:13 -0700320 synchronized (mService.mGlobalLock) {
lumark54284462019-03-05 20:44:27 +0800321 if (mRecentScreenshotAnimator != null) {
322 mRecentScreenshotAnimator.cancelAnimation();
323 mRecentScreenshotAnimator = null;
324 }
325 }
326 }
Winson Chunge2d72172018-01-25 17:46:20 +0000327 };
328
329 /**
Winson Chunge2d72172018-01-25 17:46:20 +0000330 * @param remoteAnimationRunner The remote runner which should be notified when the animation is
331 * ready to start or has been canceled
332 * @param callbacks Callbacks to be made when the animation finishes
Winson Chunge2d72172018-01-25 17:46:20 +0000333 */
334 RecentsAnimationController(WindowManagerService service,
335 IRecentsAnimationRunner remoteAnimationRunner, RecentsAnimationCallbacks callbacks,
336 int displayId) {
337 mService = service;
338 mRunner = remoteAnimationRunner;
339 mCallbacks = callbacks;
Winson Chungddf62972018-02-12 11:10:04 -0800340 mDisplayId = displayId;
Winson Chung67e49362019-05-17 16:40:38 -0700341 mStatusBar = LocalServices.getService(StatusBarManagerInternal.class);
Winson Chung7a545ae2019-07-16 14:52:13 -0700342 mDisplayContent = service.mRoot.getDisplayContent(displayId);
Winson Chung732446a2018-09-19 13:15:17 -0700343 }
344
Winson Chungddf62972018-02-12 11:10:04 -0800345 /**
346 * Initializes the recents animation controller. This is a separate call from the constructor
347 * because it may call cancelAnimation() which needs to properly clean up the controller
348 * in the window manager.
349 */
Winson Chung7a545ae2019-07-16 14:52:13 -0700350 public void initialize(int targetActivityType, SparseBooleanArray recentTaskIds) {
Winson Chung732446a2018-09-19 13:15:17 -0700351 mTargetActivityType = targetActivityType;
Winson Chung7a545ae2019-07-16 14:52:13 -0700352 mDisplayContent.mAppTransition.registerListenerLocked(mAppTransitionListener);
Winson Chung732446a2018-09-19 13:15:17 -0700353
354 // Make leashes for each of the visible/target tasks and add it to the recents animation to
355 // be started
Winson Chung7a545ae2019-07-16 14:52:13 -0700356 final ArrayList<Task> visibleTasks = mDisplayContent.getVisibleTasks();
357 final TaskStack targetStack = mDisplayContent.getStack(WINDOWING_MODE_UNDEFINED,
358 targetActivityType);
Winson Chung732446a2018-09-19 13:15:17 -0700359 if (targetStack != null) {
360 for (int i = targetStack.getChildCount() - 1; i >= 0; i--) {
361 final Task t = targetStack.getChildAt(i);
362 if (!visibleTasks.contains(t)) {
363 visibleTasks.add(t);
364 }
365 }
366 }
Winson Chunge2d72172018-01-25 17:46:20 +0000367 final int taskCount = visibleTasks.size();
368 for (int i = 0; i < taskCount; i++) {
369 final Task task = visibleTasks.get(i);
370 final WindowConfiguration config = task.getWindowConfiguration();
371 if (config.tasksAreFloating()
Winson Chung732446a2018-09-19 13:15:17 -0700372 || config.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
Winson Chunge2d72172018-01-25 17:46:20 +0000373 continue;
374 }
Vadim Tryshev593e9562018-03-08 17:15:45 -0800375 addAnimation(task, !recentTaskIds.get(task.mTaskId));
Winson Chunge2d72172018-01-25 17:46:20 +0000376 }
377
Winson Chungddf62972018-02-12 11:10:04 -0800378 // Skip the animation if there is nothing to animate
379 if (mPendingAnimations.isEmpty()) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700380 cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "initialize-noVisibleTasks");
Winson Chungddf62972018-02-12 11:10:04 -0800381 return;
382 }
383
Adrian Roos842e7882018-03-26 17:34:06 +0200384 try {
Adrian Roos653c6c12018-04-09 14:12:46 -0700385 linkToDeathOfRunner();
Adrian Roos842e7882018-03-26 17:34:06 +0200386 } catch (RemoteException e) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700387 cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "initialize-failedToLinkToDeath");
Adrian Roos842e7882018-03-26 17:34:06 +0200388 return;
389 }
390
Winson Chung3e2980e2018-03-29 17:28:57 -0700391 // Adjust the wallpaper visibility for the showing target activity
Winson Chung7a545ae2019-07-16 14:52:13 -0700392 final AppWindowToken recentsComponentAppToken =
393 targetStack.getTopChild().getTopFullscreenAppToken();
Winson Chunge2d72172018-01-25 17:46:20 +0000394 if (recentsComponentAppToken != null) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700395 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "setHomeApp("
396 + recentsComponentAppToken.getName() + ")");
Winson Chung3e2980e2018-03-29 17:28:57 -0700397 mTargetAppToken = recentsComponentAppToken;
Winson Chunge2d72172018-01-25 17:46:20 +0000398 if (recentsComponentAppToken.windowsCanBeWallpaperTarget()) {
Winson Chung7a545ae2019-07-16 14:52:13 -0700399 mDisplayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
400 mDisplayContent.setLayoutNeeded();
Winson Chunge2d72172018-01-25 17:46:20 +0000401 }
402 }
403
Winson Chung584d6522018-02-07 23:57:38 +0000404 // Save the minimized home height
Winson Chung7a545ae2019-07-16 14:52:13 -0700405 final TaskStack dockedStack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
406 mDisplayContent.getDockedDividerController().getHomeStackBoundsInDockedMode(
407 mDisplayContent.getConfiguration(),
Evan Roskyc5abbd82018-10-05 16:02:19 -0700408 dockedStack == null ? DOCKED_INVALID : dockedStack.getDockSide(),
409 mMinimizedHomeBounds);
Winson Chung584d6522018-02-07 23:57:38 +0000410
Winson Chunge2d72172018-01-25 17:46:20 +0000411 mService.mWindowPlacerLocked.performSurfacePlacement();
Winson Chung67e49362019-05-17 16:40:38 -0700412
413 // Notify that the animation has started
Winson Chung7a545ae2019-07-16 14:52:13 -0700414 if (mStatusBar != null) {
415 mStatusBar.onRecentsAnimationStateChanged(true /* running */);
416 }
Winson Chunge2d72172018-01-25 17:46:20 +0000417 }
418
Winson Chungda876c92018-04-05 18:31:06 -0700419 @VisibleForTesting
420 AnimationAdapter addAnimation(Task task, boolean isRecentTaskInvisible) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700421 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "addAnimation(" + task.getName() + ")");
Vadim Tryshev593e9562018-03-08 17:15:45 -0800422 final TaskAnimationAdapter taskAdapter = new TaskAnimationAdapter(task,
423 isRecentTaskInvisible);
Winson Chung5720d8e2018-08-03 15:50:00 -0700424 task.startAnimation(task.getPendingTransaction(), taskAdapter, false /* hidden */);
Winson Chunge2d72172018-01-25 17:46:20 +0000425 task.commitPendingTransaction();
426 mPendingAnimations.add(taskAdapter);
Winson Chungda876c92018-04-05 18:31:06 -0700427 return taskAdapter;
428 }
429
430 @VisibleForTesting
431 void removeAnimation(TaskAnimationAdapter taskAdapter) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700432 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "removeAnimation("
433 + taskAdapter.mTask.mTaskId + ")");
Winson Chungda876c92018-04-05 18:31:06 -0700434 taskAdapter.mTask.setCanAffectSystemUiFlags(true);
435 taskAdapter.mCapturedFinishCallback.onAnimationFinished(taskAdapter);
436 mPendingAnimations.remove(taskAdapter);
Winson Chunge2d72172018-01-25 17:46:20 +0000437 }
438
Winson Chungd5852192019-09-06 17:20:28 -0700439 @VisibleForTesting
440 void removeWallpaperAnimation(WallpaperAnimationAdapter wallpaperAdapter) {
441 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "removeWallpaperAnimation()");
442 wallpaperAdapter.getLeashFinishedCallback().onAnimationFinished(wallpaperAdapter);
443 mPendingWallpaperAnimations.remove(wallpaperAdapter);
444 }
445
Winson Chunge2d72172018-01-25 17:46:20 +0000446 void startAnimation() {
Winson Chungc6c3f852018-04-09 15:41:03 -0700447 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "startAnimation(): mPendingStart=" + mPendingStart
Winson Chungddf62972018-02-12 11:10:04 -0800448 + " mCanceled=" + mCanceled);
449 if (!mPendingStart || mCanceled) {
450 // Skip starting if we've already started or canceled the animation
Winson Chunge2d72172018-01-25 17:46:20 +0000451 return;
452 }
453 try {
Winson Chungd5852192019-09-06 17:20:28 -0700454 // Create the app targets
455 final RemoteAnimationTarget[] appTargets = createAppAnimations();
Winson Chungda876c92018-04-05 18:31:06 -0700456
457 // Skip the animation if there is nothing to animate
Winson Chungd5852192019-09-06 17:20:28 -0700458 if (appTargets.length == 0) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700459 cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "startAnimation-noAppWindows");
Winson Chungda876c92018-04-05 18:31:06 -0700460 return;
461 }
462
Winson Chungd5852192019-09-06 17:20:28 -0700463 // Create the wallpaper targets
464 final RemoteAnimationTarget[] wallpaperTargets = createWallpaperAnimations();
465
Winson Chunge2d72172018-01-25 17:46:20 +0000466 mPendingStart = false;
Winson Chung584d6522018-02-07 23:57:38 +0000467
Winson Chung9e8b0cb2018-08-03 16:23:52 -0700468 // Perform layout if it was scheduled before to make sure that we get correct content
469 // insets for the target app window after a rotation
Winson Chung7a545ae2019-07-16 14:52:13 -0700470 mDisplayContent.performLayout(false /* initial */, false /* updateInputWindows */);
Winson Chung9e8b0cb2018-08-03 16:23:52 -0700471
Winson Chung3e2980e2018-03-29 17:28:57 -0700472 final Rect minimizedHomeBounds = mTargetAppToken != null
473 && mTargetAppToken.inSplitScreenSecondaryWindowingMode()
474 ? mMinimizedHomeBounds
475 : null;
Vadim Tryshev257f86b2018-08-23 16:45:02 -0700476 final Rect contentInsets;
477 if (mTargetAppToken != null && mTargetAppToken.findMainWindow() != null) {
chaviw9c81e632018-07-31 11:17:52 -0700478 contentInsets = mTargetAppToken.findMainWindow().getContentInsets();
Vadim Tryshev257f86b2018-08-23 16:45:02 -0700479 } else {
480 // If the window for the activity had not yet been created, use the display insets.
481 mService.getStableInsets(mDisplayId, mTmpRect);
482 contentInsets = mTmpRect;
483 }
Winson Chungd5852192019-09-06 17:20:28 -0700484 mRunner.onAnimationStart(mController, appTargets, wallpaperTargets, contentInsets,
485 minimizedHomeBounds);
Winson Chungc6c3f852018-04-09 15:41:03 -0700486 if (DEBUG_RECENTS_ANIMATIONS) {
487 Slog.d(TAG, "startAnimation(): Notify animation start:");
488 for (int i = 0; i < mPendingAnimations.size(); i++) {
489 final Task task = mPendingAnimations.get(i).mTask;
490 Slog.d(TAG, "\t" + task.mTaskId);
491 }
492 }
Winson Chunge2d72172018-01-25 17:46:20 +0000493 } catch (RemoteException e) {
494 Slog.e(TAG, "Failed to start recents animation", e);
495 }
Jorim Jaggi54cff642018-03-15 15:51:32 +0100496 final SparseIntArray reasons = new SparseIntArray();
497 reasons.put(WINDOWING_MODE_FULLSCREEN, APP_TRANSITION_RECENTS_ANIM);
Yunfan Chencafc7062019-01-22 17:21:32 +0900498 mService.mAtmInternal.notifyAppTransitionStarting(reasons, SystemClock.uptimeMillis());
Winson Chunge2d72172018-01-25 17:46:20 +0000499 }
500
Winson Chungd5852192019-09-06 17:20:28 -0700501 private RemoteAnimationTarget[] createAppAnimations() {
502 final ArrayList<RemoteAnimationTarget> targets = new ArrayList<>();
503 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
504 final TaskAnimationAdapter taskAdapter = mPendingAnimations.get(i);
505 final RemoteAnimationTarget target = taskAdapter.createRemoteAnimationTarget();
506 if (target != null) {
507 targets.add(target);
508 } else {
509 removeAnimation(taskAdapter);
510 }
511 }
512 return targets.toArray(new RemoteAnimationTarget[targets.size()]);
513 }
514
515 private RemoteAnimationTarget[] createWallpaperAnimations() {
516 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "createWallpaperAnimations()");
517 return WallpaperAnimationAdapter.startWallpaperAnimations(mService, 0L, 0L,
518 adapter -> {
519 synchronized (mService.mGlobalLock) {
520 // If the wallpaper animation is canceled, continue with the recents
521 // animation
522 mPendingWallpaperAnimations.remove(adapter);
523 }
524 }, mPendingWallpaperAnimations);
525 }
526
Winson Chungc6c3f852018-04-09 15:41:03 -0700527 void cancelAnimation(@ReorderMode int reorderMode, String reason) {
Wale Ogunwalea441b922019-06-27 19:21:44 -0700528 cancelAnimation(reorderMode, false /*screenshot */, reason);
lumark54284462019-03-05 20:44:27 +0800529 }
530
Winson Chung7a545ae2019-07-16 14:52:13 -0700531 void cancelAnimationWithScreenshot(boolean screenshot) {
Wale Ogunwalea441b922019-06-27 19:21:44 -0700532 cancelAnimation(REORDER_KEEP_IN_PLACE, screenshot, "stackOrderChanged");
Winson Chung65c5f992018-04-20 14:58:57 -0700533 }
534
Wale Ogunwalea441b922019-06-27 19:21:44 -0700535 private void cancelAnimation(@ReorderMode int reorderMode, boolean screenshot, String reason) {
536 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "cancelAnimation(): reason=" + reason);
Winson Chung65fc89a2018-02-28 08:32:12 -0800537 synchronized (mService.getWindowManagerLock()) {
538 if (mCanceled) {
539 // We've already canceled the animation
540 return;
541 }
Adrian Roos842e7882018-03-26 17:34:06 +0200542 mService.mH.removeCallbacks(mFailsafeRunnable);
Winson Chung65fc89a2018-02-28 08:32:12 -0800543 mCanceled = true;
Winson Chung7a545ae2019-07-16 14:52:13 -0700544
545 if (screenshot) {
546 // Screen shot previous task when next task starts transition and notify the runner.
547 // We will actually finish the animation once the runner calls cleanUpScreenshot().
548 final Task task = mPendingAnimations.get(0).mTask;
Wale Ogunwalea441b922019-06-27 19:21:44 -0700549 final TaskSnapshot taskSnapshot = screenshotRecentTask(task, reorderMode);
Winson Chung7a545ae2019-07-16 14:52:13 -0700550 try {
Tracy Zhou8089ffa2019-07-30 17:30:43 -0700551 mRunner.onAnimationCanceled(taskSnapshot);
Winson Chung7a545ae2019-07-16 14:52:13 -0700552 } catch (RemoteException e) {
553 Slog.e(TAG, "Failed to cancel recents animation", e);
lumark54284462019-03-05 20:44:27 +0800554 }
Tracy Zhou8089ffa2019-07-30 17:30:43 -0700555 if (taskSnapshot == null) {
Wale Ogunwalea441b922019-06-27 19:21:44 -0700556 mCallbacks.onAnimationFinished(reorderMode, false /* sendUserLeaveHint */);
Tracy Zhou8089ffa2019-07-30 17:30:43 -0700557 }
Winson Chung7a545ae2019-07-16 14:52:13 -0700558 } else {
559 // Otherwise, notify the runner and clean up the animation immediately
560 // Note: In the fallback case, this can trigger multiple onAnimationCancel() calls
561 // to the runner if we this actually triggers cancel twice on the caller
562 try {
Tracy Zhou8089ffa2019-07-30 17:30:43 -0700563 mRunner.onAnimationCanceled(null /* taskSnapshot */);
Winson Chung7a545ae2019-07-16 14:52:13 -0700564 } catch (RemoteException e) {
565 Slog.e(TAG, "Failed to cancel recents animation", e);
566 }
Wale Ogunwalea441b922019-06-27 19:21:44 -0700567 mCallbacks.onAnimationFinished(reorderMode, false /* sendUserLeaveHint */);
Winson Chung65fc89a2018-02-28 08:32:12 -0800568 }
lumark54284462019-03-05 20:44:27 +0800569 }
570 }
571
572 /**
573 * Cancel recents animation when the next app transition starts.
574 * <p>
575 * When we cancel the recents animation due to a stack order change, we can't just cancel it
576 * immediately as it would lead to a flicker in Launcher if we just remove the task from the
577 * leash. Instead we screenshot the previous task and replace the child of the leash with the
578 * screenshot, so that Launcher can still control the leash lifecycle & make the next app
579 * transition animate smoothly without flickering.
580 */
Winson Chung7a545ae2019-07-16 14:52:13 -0700581 void setCancelOnNextTransitionStart() {
lumark54284462019-03-05 20:44:27 +0800582 mCancelOnNextTransitionStart = true;
583 }
584
Winson Chung7a545ae2019-07-16 14:52:13 -0700585 /**
586 * Requests that we attempt to defer the cancel until the next app transition if we are
587 * canceling from a stack order change. If {@param screenshot} is specified, then the system
588 * will replace the contents of the leash with a screenshot, which must be cleaned up when the
589 * runner calls cleanUpScreenshot().
590 */
591 void setDeferredCancel(boolean defer, boolean screenshot) {
592 mRequestDeferCancelUntilNextTransition = defer;
593 mCancelDeferredWithScreenshot = screenshot;
lumark54284462019-03-05 20:44:27 +0800594 }
595
Winson Chung7a545ae2019-07-16 14:52:13 -0700596 /**
597 * @return Whether we should defer the cancel from a stack order change until the next app
598 * transition.
599 */
600 boolean shouldDeferCancelUntilNextTransition() {
601 return mRequestDeferCancelUntilNextTransition;
lumark54284462019-03-05 20:44:27 +0800602 }
603
Winson Chung7a545ae2019-07-16 14:52:13 -0700604 /**
605 * @return Whether we should both defer the cancel from a stack order change until the next
606 * app transition, and also that the deferred cancel should replace the contents of the leash
607 * with a screenshot.
608 */
609 boolean shouldDeferCancelWithScreenshot() {
610 return mRequestDeferCancelUntilNextTransition && mCancelDeferredWithScreenshot;
lumark54284462019-03-05 20:44:27 +0800611 }
612
Wale Ogunwalea441b922019-06-27 19:21:44 -0700613 TaskSnapshot screenshotRecentTask(Task task, @ReorderMode int reorderMode) {
Tracy Zhou8089ffa2019-07-30 17:30:43 -0700614 final TaskSnapshotController snapshotController = mService.mTaskSnapshotController;
615 final ArraySet<Task> tasks = Sets.newArraySet(task);
616 snapshotController.snapshotTasks(tasks);
617 snapshotController.addSkipClosingAppSnapshotTasks(tasks);
618 final TaskSnapshot taskSnapshot = snapshotController.getSnapshot(task.mTaskId,
619 task.mUserId, false /* restoreFromDisk */, false /* reducedResolution */);
620 if (taskSnapshot == null) {
621 return null;
lumark54284462019-03-05 20:44:27 +0800622 }
Tracy Zhou8089ffa2019-07-30 17:30:43 -0700623
Vishnu Nair33197392019-08-30 10:29:37 -0700624 final TaskScreenshotAnimatable animatable = new TaskScreenshotAnimatable(mService.mSurfaceControlFactory, task,
Tracy Zhou8089ffa2019-07-30 17:30:43 -0700625 new SurfaceControl.ScreenshotGraphicBuffer(taskSnapshot.getSnapshot(),
626 taskSnapshot.getColorSpace(), false /* containsSecureLayers */));
627 mRecentScreenshotAnimator = new SurfaceAnimator(
628 animatable,
629 () -> {
630 if (DEBUG_RECENTS_ANIMATIONS) {
631 Slog.d(TAG, "mRecentScreenshotAnimator finish");
632 }
Wale Ogunwalea441b922019-06-27 19:21:44 -0700633 mCallbacks.onAnimationFinished(reorderMode, false /* sendUserLeaveHint */);
Tracy Zhou8089ffa2019-07-30 17:30:43 -0700634 }, mService);
635 mRecentScreenshotAnimator.transferAnimation(task.mSurfaceAnimator);
636 return taskSnapshot;
Winson Chunge2d72172018-01-25 17:46:20 +0000637 }
638
Winson Chung6a38fca2018-03-28 17:57:09 -0700639 void cleanupAnimation(@ReorderMode int reorderMode) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700640 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG,
641 "cleanupAnimation(): Notify animation finished mPendingAnimations="
642 + mPendingAnimations.size() + " reorderMode=" + reorderMode);
Winson Chunge2d72172018-01-25 17:46:20 +0000643 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
Winson Chungda876c92018-04-05 18:31:06 -0700644 final TaskAnimationAdapter taskAdapter = mPendingAnimations.get(i);
Winson Chung3e2980e2018-03-29 17:28:57 -0700645 if (reorderMode == REORDER_MOVE_TO_TOP || reorderMode == REORDER_KEEP_IN_PLACE) {
Winson Chungda876c92018-04-05 18:31:06 -0700646 taskAdapter.mTask.dontAnimateDimExit();
chaviw87ca63a2018-03-26 14:06:17 -0700647 }
Winson Chungda876c92018-04-05 18:31:06 -0700648 removeAnimation(taskAdapter);
Winson Chunge2d72172018-01-25 17:46:20 +0000649 }
Winson Chunge2d72172018-01-25 17:46:20 +0000650
Winson Chungd5852192019-09-06 17:20:28 -0700651 for (int i = mPendingWallpaperAnimations.size() - 1; i >= 0; i--) {
652 final WallpaperAnimationAdapter wallpaperAdapter = mPendingWallpaperAnimations.get(i);
653 removeWallpaperAnimation(wallpaperAdapter);
654 }
655
Winson Chung7906b3e2018-05-10 10:32:39 -0700656 // Clear any pending failsafe runnables
657 mService.mH.removeCallbacks(mFailsafeRunnable);
Winson Chung7a545ae2019-07-16 14:52:13 -0700658 mDisplayContent.mAppTransition.unregisterListener(mAppTransitionListener);
Winson Chung7906b3e2018-05-10 10:32:39 -0700659
Winson Chung5c91e8f2018-05-07 10:06:55 -0700660 // Clear references to the runner
Adrian Roos653c6c12018-04-09 14:12:46 -0700661 unlinkToDeathOfRunner();
Winson Chung5c91e8f2018-05-07 10:06:55 -0700662 mRunner = null;
Winson Chung7906b3e2018-05-10 10:32:39 -0700663 mCanceled = true;
Winson Chung5c91e8f2018-05-07 10:06:55 -0700664
lumark54284462019-03-05 20:44:27 +0800665 // Make sure previous animator has cleaned-up.
666 if (mRecentScreenshotAnimator != null) {
667 mRecentScreenshotAnimator.cancelAnimation();
668 mRecentScreenshotAnimator = null;
669 }
670
Winson Chungdb111ee2018-10-03 14:25:34 -0700671 // Update the input windows after the animation is complete
Winson Chung7a545ae2019-07-16 14:52:13 -0700672 final InputMonitor inputMonitor = mDisplayContent.getInputMonitor();
Arthur Hung95b38a92018-07-20 18:56:12 +0800673 inputMonitor.updateInputWindowsLw(true /*force*/);
Winson Chung0bb66cc2018-04-10 11:58:15 -0700674
675 // We have deferred all notifications to the target app as a part of the recents animation,
676 // so if we are actually transitioning there, notify again here
677 if (mTargetAppToken != null) {
678 if (reorderMode == REORDER_MOVE_TO_TOP || reorderMode == REORDER_KEEP_IN_PLACE) {
Winson Chung7a545ae2019-07-16 14:52:13 -0700679 mDisplayContent.mAppTransition.notifyAppTransitionFinishedLocked(
680 mTargetAppToken.token);
Winson Chung0bb66cc2018-04-10 11:58:15 -0700681 }
682 }
Winson Chung67e49362019-05-17 16:40:38 -0700683
684 // Notify that the animation has ended
Winson Chung7a545ae2019-07-16 14:52:13 -0700685 if (mStatusBar != null) {
686 mStatusBar.onRecentsAnimationStateChanged(false /* running */);
687 }
Winson Chunge2d72172018-01-25 17:46:20 +0000688 }
689
Adrian Roos842e7882018-03-26 17:34:06 +0200690 void scheduleFailsafe() {
691 mService.mH.postDelayed(mFailsafeRunnable, FAILSAFE_DELAY);
692 }
693
Adrian Roos653c6c12018-04-09 14:12:46 -0700694 private void linkToDeathOfRunner() throws RemoteException {
695 if (!mLinkedToDeathOfRunner) {
696 mRunner.asBinder().linkToDeath(this, 0);
697 mLinkedToDeathOfRunner = true;
698 }
699 }
700
701 private void unlinkToDeathOfRunner() {
702 if (mLinkedToDeathOfRunner) {
703 mRunner.asBinder().unlinkToDeath(this, 0);
704 mLinkedToDeathOfRunner = false;
705 }
706 }
707
Adrian Roos842e7882018-03-26 17:34:06 +0200708 @Override
709 public void binderDied() {
Winson Chungc6c3f852018-04-09 15:41:03 -0700710 cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "binderDied");
Winson Chungdb111ee2018-10-03 14:25:34 -0700711
Arthur Hung1b636fa2018-12-04 15:53:49 +0800712 synchronized (mService.getWindowManagerLock()) {
713 // Clear associated input consumers on runner death
Winson Chung7a545ae2019-07-16 14:52:13 -0700714 final InputMonitor inputMonitor = mDisplayContent.getInputMonitor();
Arthur Hung1b636fa2018-12-04 15:53:49 +0800715 inputMonitor.destroyInputConsumer(INPUT_CONSUMER_RECENTS_ANIMATION);
716 }
Adrian Roos842e7882018-03-26 17:34:06 +0200717 }
718
Winson Chunge2d72172018-01-25 17:46:20 +0000719 void checkAnimationReady(WallpaperController wallpaperController) {
720 if (mPendingStart) {
Winson Chung3e2980e2018-03-29 17:28:57 -0700721 final boolean wallpaperReady = !isTargetOverWallpaper()
Winson Chunge2d72172018-01-25 17:46:20 +0000722 || (wallpaperController.getWallpaperTarget() != null
723 && wallpaperController.wallpaperTransitionReady());
724 if (wallpaperReady) {
725 mService.getRecentsAnimationController().startAnimation();
726 }
727 }
728 }
729
Winson Chungf557c3b2018-03-16 10:55:20 -0700730 boolean isSplitScreenMinimized() {
731 return mSplitScreenMinimized;
732 }
733
Winson Chunge2d72172018-01-25 17:46:20 +0000734 boolean isWallpaperVisible(WindowState w) {
Jorim Jaggiceeb06d2019-06-11 16:19:36 +0200735 return w != null && w.mAttrs.type == TYPE_BASE_APPLICATION && w.mAppToken != null
736 && mTargetAppToken == w.mAppToken && isTargetOverWallpaper();
Winson Chunge2d72172018-01-25 17:46:20 +0000737 }
738
Winson Chungdb111ee2018-10-03 14:25:34 -0700739 /**
740 * @return Whether to use the input consumer to override app input to route home/recents.
741 */
742 boolean shouldApplyInputConsumer(AppWindowToken appToken) {
743 // Only apply the input consumer if it is enabled, it is not the target (home/recents)
744 // being revealed with the transition, and we are actively animating the app as a part of
745 // the animation
746 return mInputConsumerEnabled && mTargetAppToken != appToken && isAnimatingApp(appToken);
Winson Chunga89ffed2018-01-25 17:46:11 +0000747 }
748
Arthur Hung95b38a92018-07-20 18:56:12 +0800749 boolean updateInputConsumerForApp(InputWindowHandle inputWindowHandle,
Winson Chunga89ffed2018-01-25 17:46:11 +0000750 boolean hasFocus) {
Winson Chung3e2980e2018-03-29 17:28:57 -0700751 // Update the input consumer touchable region to match the target app main window
752 final WindowState targetAppMainWindow = mTargetAppToken != null
753 ? mTargetAppToken.findMainWindow()
Winson Chunga89ffed2018-01-25 17:46:11 +0000754 : null;
Winson Chung3e2980e2018-03-29 17:28:57 -0700755 if (targetAppMainWindow != null) {
756 targetAppMainWindow.getBounds(mTmpRect);
Arthur Hung95b38a92018-07-20 18:56:12 +0800757 inputWindowHandle.hasFocus = hasFocus;
758 inputWindowHandle.touchableRegion.set(mTmpRect);
Winson Chunga89ffed2018-01-25 17:46:11 +0000759 return true;
760 }
761 return false;
762 }
763
Winson Chung0bb66cc2018-04-10 11:58:15 -0700764 boolean isTargetApp(AppWindowToken token) {
765 return mTargetAppToken != null && token == mTargetAppToken;
766 }
767
Winson Chung3e2980e2018-03-29 17:28:57 -0700768 private boolean isTargetOverWallpaper() {
769 if (mTargetAppToken == null) {
Winson Chunge2d72172018-01-25 17:46:20 +0000770 return false;
771 }
Winson Chung3e2980e2018-03-29 17:28:57 -0700772 return mTargetAppToken.windowsCanBeWallpaperTarget();
Winson Chunge2d72172018-01-25 17:46:20 +0000773 }
774
Winson Chungd41f71d2018-03-16 15:26:07 -0700775 boolean isAnimatingTask(Task task) {
776 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
777 if (task == mPendingAnimations.get(i).mTask) {
778 return true;
779 }
780 }
781 return false;
782 }
783
Winson Chungd5852192019-09-06 17:20:28 -0700784 boolean isAnimatingWallpaper(WallpaperWindowToken token) {
785 for (int i = mPendingWallpaperAnimations.size() - 1; i >= 0; i--) {
786 if (token == mPendingWallpaperAnimations.get(i).getToken()) {
787 return true;
788 }
789 }
790 return false;
791 }
792
Winson Chunga89ffed2018-01-25 17:46:11 +0000793 private boolean isAnimatingApp(AppWindowToken appToken) {
Winson Chunge2d72172018-01-25 17:46:20 +0000794 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
795 final Task task = mPendingAnimations.get(i).mTask;
796 for (int j = task.getChildCount() - 1; j >= 0; j--) {
797 final AppWindowToken app = task.getChildAt(j);
798 if (app == appToken) {
799 return true;
800 }
801 }
802 }
803 return false;
804 }
805
Tracy Zhoud2d3e442019-09-04 13:26:32 -0700806 boolean shouldIgnoreForAccessibility(WindowState windowState) {
807 final Task task = windowState.getTask();
808 return task != null && isAnimatingTask(task) && !isTargetApp(windowState.mAppToken);
809 }
810
Winson Chungda876c92018-04-05 18:31:06 -0700811 @VisibleForTesting
812 class TaskAnimationAdapter implements AnimationAdapter {
Winson Chunge2d72172018-01-25 17:46:20 +0000813
Vadim Tryshev593e9562018-03-08 17:15:45 -0800814 private final Task mTask;
Winson Chunge2d72172018-01-25 17:46:20 +0000815 private SurfaceControl mCapturedLeash;
816 private OnAnimationFinishedCallback mCapturedFinishCallback;
Vadim Tryshev593e9562018-03-08 17:15:45 -0800817 private final boolean mIsRecentTaskInvisible;
Jorim Jaggif75d1612018-02-27 15:05:21 +0100818 private RemoteAnimationTarget mTarget;
Winson Chungd41f71d2018-03-16 15:26:07 -0700819 private final Point mPosition = new Point();
820 private final Rect mBounds = new Rect();
Winson Chunge2d72172018-01-25 17:46:20 +0000821
Vadim Tryshev593e9562018-03-08 17:15:45 -0800822 TaskAnimationAdapter(Task task, boolean isRecentTaskInvisible) {
Winson Chunge2d72172018-01-25 17:46:20 +0000823 mTask = task;
Vadim Tryshev593e9562018-03-08 17:15:45 -0800824 mIsRecentTaskInvisible = isRecentTaskInvisible;
Winson Chungd41f71d2018-03-16 15:26:07 -0700825 final WindowContainer container = mTask.getParent();
Evan Roskyed6767f2018-10-26 17:21:06 -0700826 container.getRelativeDisplayedPosition(mPosition);
827 mBounds.set(container.getDisplayedBounds());
Winson Chunge2d72172018-01-25 17:46:20 +0000828 }
829
Winson Chungd5852192019-09-06 17:20:28 -0700830 RemoteAnimationTarget createRemoteAnimationTarget() {
Winson Chung173020c2018-05-04 15:36:47 -0700831 final AppWindowToken topApp = mTask.getTopVisibleAppToken();
832 final WindowState mainWindow = topApp != null
833 ? topApp.findMainWindow()
834 : null;
Winson Chung2dc37362018-03-12 17:57:06 -0700835 if (mainWindow == null) {
836 return null;
837 }
chaviw9c81e632018-07-31 11:17:52 -0700838 final Rect insets = new Rect();
839 mainWindow.getContentInsets(insets);
Jorim Jaggi817ebdd2018-03-26 15:46:01 +0200840 InsetUtils.addInsets(insets, mainWindow.mAppToken.getLetterboxInsets());
Winson Chung732446a2018-09-19 13:15:17 -0700841 final int mode = topApp.getActivityType() == mTargetActivityType
842 ? MODE_OPENING
843 : MODE_CLOSING;
844 mTarget = new RemoteAnimationTarget(mTask.mTaskId, mode, mCapturedLeash,
Winson Chung173020c2018-05-04 15:36:47 -0700845 !topApp.fillsParent(), mainWindow.mWinAnimator.mLastClipRect,
Winson Chungd41f71d2018-03-16 15:26:07 -0700846 insets, mTask.getPrefixOrderIndex(), mPosition, mBounds,
Evan Rosky2289ba12018-11-19 18:28:18 -0800847 mTask.getWindowConfiguration(), mIsRecentTaskInvisible, null, null);
Jorim Jaggif75d1612018-02-27 15:05:21 +0100848 return mTarget;
Winson Chunge2d72172018-01-25 17:46:20 +0000849 }
850
851 @Override
Jorim Jaggi82c17862018-02-21 17:50:18 +0100852 public boolean getShowWallpaper() {
853 return false;
854 }
855
856 @Override
Winson Chunge2d72172018-01-25 17:46:20 +0000857 public int getBackgroundColor() {
858 return 0;
859 }
860
861 @Override
862 public void startAnimation(SurfaceControl animationLeash, Transaction t,
863 OnAnimationFinishedCallback finishCallback) {
Winson Chung65a05862018-04-12 17:14:50 -0700864 // Restore z-layering, position and stack crop until client has a chance to modify it.
865 t.setLayer(animationLeash, mTask.getPrefixOrderIndex());
Winson Chungd41f71d2018-03-16 15:26:07 -0700866 t.setPosition(animationLeash, mPosition.x, mPosition.y);
Winson Chung65a05862018-04-12 17:14:50 -0700867 mTmpRect.set(mBounds);
868 mTmpRect.offsetTo(0, 0);
869 t.setWindowCrop(animationLeash, mTmpRect);
Winson Chunge2d72172018-01-25 17:46:20 +0000870 mCapturedLeash = animationLeash;
871 mCapturedFinishCallback = finishCallback;
872 }
873
874 @Override
875 public void onAnimationCancelled(SurfaceControl animationLeash) {
Winson Chungd5852192019-09-06 17:20:28 -0700876 // Cancel the animation immediately if any single task animator is canceled
Winson Chungc6c3f852018-04-09 15:41:03 -0700877 cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "taskAnimationAdapterCanceled");
Winson Chunge2d72172018-01-25 17:46:20 +0000878 }
879
880 @Override
881 public long getDurationHint() {
882 return 0;
883 }
884
885 @Override
886 public long getStatusBarTransitionsStartTime() {
887 return SystemClock.uptimeMillis();
888 }
Jorim Jaggif75d1612018-02-27 15:05:21 +0100889
890 @Override
891 public void dump(PrintWriter pw, String prefix) {
892 pw.print(prefix); pw.println("task=" + mTask);
893 if (mTarget != null) {
894 pw.print(prefix); pw.println("Target:");
895 mTarget.dump(pw, prefix + " ");
896 } else {
897 pw.print(prefix); pw.println("Target: null");
898 }
Winson Chungc6c3f852018-04-09 15:41:03 -0700899 pw.println("mIsRecentTaskInvisible=" + mIsRecentTaskInvisible);
900 pw.println("mPosition=" + mPosition);
901 pw.println("mBounds=" + mBounds);
902 pw.println("mIsRecentTaskInvisible=" + mIsRecentTaskInvisible);
Jorim Jaggif75d1612018-02-27 15:05:21 +0100903 }
904
905 @Override
906 public void writeToProto(ProtoOutputStream proto) {
907 final long token = proto.start(REMOTE);
908 if (mTarget != null) {
909 mTarget.writeToProto(proto, TARGET);
910 }
911 proto.end(token);
912 }
Winson Chunge2d72172018-01-25 17:46:20 +0000913 }
914
915 public void dump(PrintWriter pw, String prefix) {
916 final String innerPrefix = prefix + " ";
917 pw.print(prefix); pw.println(RecentsAnimationController.class.getSimpleName() + ":");
918 pw.print(innerPrefix); pw.println("mPendingStart=" + mPendingStart);
Winson Chungdb111ee2018-10-03 14:25:34 -0700919 pw.print(innerPrefix); pw.println("mPendingAnimations=" + mPendingAnimations.size());
Winson Chungc6c3f852018-04-09 15:41:03 -0700920 pw.print(innerPrefix); pw.println("mCanceled=" + mCanceled);
921 pw.print(innerPrefix); pw.println("mInputConsumerEnabled=" + mInputConsumerEnabled);
922 pw.print(innerPrefix); pw.println("mSplitScreenMinimized=" + mSplitScreenMinimized);
Winson Chung3e2980e2018-03-29 17:28:57 -0700923 pw.print(innerPrefix); pw.println("mTargetAppToken=" + mTargetAppToken);
Winson Chungc6c3f852018-04-09 15:41:03 -0700924 pw.print(innerPrefix); pw.println("isTargetOverWallpaper=" + isTargetOverWallpaper());
Winson Chung7a545ae2019-07-16 14:52:13 -0700925 pw.print(innerPrefix); pw.println("mRequestDeferCancelUntilNextTransition="
926 + mRequestDeferCancelUntilNextTransition);
927 pw.print(innerPrefix); pw.println("mCancelOnNextTransitionStart="
928 + mCancelOnNextTransitionStart);
929 pw.print(innerPrefix); pw.println("mCancelDeferredWithScreenshot="
930 + mCancelDeferredWithScreenshot);
Winson Chunge2d72172018-01-25 17:46:20 +0000931 }
932}