blob: 2ce10a74c949d22fff5812da23286524f5cff195 [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
Winson Chunge2d72172018-01-25 17:46:20 +000019import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
Winson Chung3e2980e2018-03-29 17:28:57 -070020import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
Winson Chunge2d72172018-01-25 17:46:20 +000021import static android.view.RemoteAnimationTarget.MODE_CLOSING;
Winson Chung732446a2018-09-19 13:15:17 -070022import static android.view.RemoteAnimationTarget.MODE_OPENING;
Winson Chunga89ffed2018-01-25 17:46:11 +000023import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
Jorim Jaggiceeb06d2019-06-11 16:19:36 +020024import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
Tracy Zhou8089ffa2019-07-30 17:30:43 -070025
Winson Chunge2d72172018-01-25 17:46:20 +000026import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
Wale Ogunwale9e4f3e02018-05-17 09:35:39 -070027import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_RECENTS_ANIM;
Yi Jin6c6e9ca2018-03-20 16:53:35 -070028import static com.android.server.wm.AnimationAdapterProto.REMOTE;
Adrian Roosb125e0b2019-10-02 14:55:14 +020029import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS;
Winson Chungc6c3f852018-04-09 15:41:03 -070030import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET;
Issei Suzuki8b995df2020-01-08 12:23:04 +010031import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
lumark54284462019-03-05 20:44:27 +080032import static com.android.server.wm.WindowManagerInternal.AppTransitionListener;
Winson Chunge2d72172018-01-25 17:46:20 +000033
Winson Chung6a38fca2018-03-28 17:57:09 -070034import android.annotation.IntDef;
Vadim Caen2a9ccc92020-01-29 12:21:41 +010035import android.annotation.NonNull;
Winson Chunge2d72172018-01-25 17:46:20 +000036import android.app.ActivityManager.TaskSnapshot;
37import android.app.WindowConfiguration;
Winson Chunge2d72172018-01-25 17:46:20 +000038import android.graphics.Point;
39import android.graphics.Rect;
40import android.os.Binder;
Adrian Roos842e7882018-03-26 17:34:06 +020041import android.os.IBinder.DeathRecipient;
Winson Chunge2d72172018-01-25 17:46:20 +000042import android.os.RemoteException;
43import android.os.SystemClock;
Riddle Hsufd66d4d2019-11-14 10:35:55 +080044import android.util.ArrayMap;
Winson Chung23aa7b12018-02-01 11:41:43 -080045import android.util.ArraySet;
lumark04bceb92020-03-07 00:03:33 +080046import android.util.IntArray;
Winson Chungc6c3f852018-04-09 15:41:03 -070047import android.util.Slog;
Vadim Tryshev593e9562018-03-08 17:15:45 -080048import android.util.SparseBooleanArray;
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;
lumarkd85e1582019-12-29 20:20:41 +080058import com.android.internal.inputmethod.SoftInputShowHideReason;
Wale Ogunwalea38654f2019-11-17 20:37:15 -080059import com.android.internal.util.function.pooled.PooledConsumer;
60import com.android.internal.util.function.pooled.PooledFunction;
61import com.android.internal.util.function.pooled.PooledLambda;
Winson Chunga840c322018-04-20 15:58:18 -070062import com.android.server.LocalServices;
Yohei Yukawac3de83e2018-08-28 16:09:34 -070063import com.android.server.inputmethod.InputMethodManagerInternal;
Adrian Roosb125e0b2019-10-02 14:55:14 +020064import com.android.server.protolog.common.ProtoLog;
Winson Chung67e49362019-05-17 16:40:38 -070065import com.android.server.statusbar.StatusBarManagerInternal;
Issei Suzuki8b995df2020-01-08 12:23:04 +010066import com.android.server.wm.SurfaceAnimator.AnimationType;
Jorim Jaggif75d1612018-02-27 15:05:21 +010067import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
Jorim Jaggi817ebdd2018-03-26 15:46:01 +020068import com.android.server.wm.utils.InsetUtils;
Evan Roskyc5abbd82018-10-05 16:02:19 -070069
Vadim Tryshev257f86b2018-08-23 16:45:02 -070070import com.google.android.collect.Sets;
Evan Roskyc5abbd82018-10-05 16:02:19 -070071
Winson Chunge2d72172018-01-25 17:46:20 +000072import java.io.PrintWriter;
73import java.util.ArrayList;
Adrian Roosb125e0b2019-10-02 14:55:14 +020074import java.util.stream.Collectors;
Winson Chungc6c3f852018-04-09 15:41:03 -070075
Winson Chunge2d72172018-01-25 17:46:20 +000076/**
77 * Controls a single instance of the remote driven recents animation. In particular, this allows
78 * the calling SystemUI to animate the visible task windows as a part of the transition. The remote
79 * runner is provided an animation controller which allows it to take screenshots and to notify
80 * window manager when the animation is completed. In addition, window manager may also notify the
81 * app if it requires the animation to be canceled at any time (ie. due to timeout, etc.)
82 */
Adrian Roos842e7882018-03-26 17:34:06 +020083public class RecentsAnimationController implements DeathRecipient {
Winson Chungc6c3f852018-04-09 15:41:03 -070084 private static final String TAG = RecentsAnimationController.class.getSimpleName();
Adrian Roos842e7882018-03-26 17:34:06 +020085 private static final long FAILSAFE_DELAY = 1000;
Winson Chunge2d72172018-01-25 17:46:20 +000086
Winson Chung3e2980e2018-03-29 17:28:57 -070087 public static final int REORDER_KEEP_IN_PLACE = 0;
88 public static final int REORDER_MOVE_TO_TOP = 1;
89 public static final int REORDER_MOVE_TO_ORIGINAL_POSITION = 2;
Winson Chung6a38fca2018-03-28 17:57:09 -070090
91 @IntDef(prefix = { "REORDER_MODE_" }, value = {
Winson Chung3e2980e2018-03-29 17:28:57 -070092 REORDER_KEEP_IN_PLACE,
93 REORDER_MOVE_TO_TOP,
94 REORDER_MOVE_TO_ORIGINAL_POSITION
Winson Chung6a38fca2018-03-28 17:57:09 -070095 })
96 public @interface ReorderMode {}
97
Winson Chunge2d72172018-01-25 17:46:20 +000098 private final WindowManagerService mService;
Winson Chung67e49362019-05-17 16:40:38 -070099 private final StatusBarManagerInternal mStatusBar;
Winson Chung5c91e8f2018-05-07 10:06:55 -0700100 private IRecentsAnimationRunner mRunner;
Winson Chunge2d72172018-01-25 17:46:20 +0000101 private final RecentsAnimationCallbacks mCallbacks;
102 private final ArrayList<TaskAnimationAdapter> mPendingAnimations = new ArrayList<>();
lumark04bceb92020-03-07 00:03:33 +0800103 private final IntArray mPendingNewTaskTargets = new IntArray(0);
104
Winson Chungd5852192019-09-06 17:20:28 -0700105 private final ArrayList<WallpaperAnimationAdapter> mPendingWallpaperAnimations =
106 new ArrayList<>();
Winson Chungddf62972018-02-12 11:10:04 -0800107 private final int mDisplayId;
Tracy Zhou9e0354f2019-10-03 18:05:03 -0700108 private boolean mWillFinishToHome = false;
109 private final Runnable mFailsafeRunnable = () -> cancelAnimation(
110 mWillFinishToHome ? REORDER_MOVE_TO_TOP : REORDER_MOVE_TO_ORIGINAL_POSITION,
111 "failSafeRunnable");
Winson Chunge2d72172018-01-25 17:46:20 +0000112
113 // The recents component app token that is shown behind the visibile tasks
Garfield Tane8d84ab2019-10-11 09:49:40 -0700114 private ActivityRecord mTargetActivityRecord;
Winson Chung7a545ae2019-07-16 14:52:13 -0700115 private DisplayContent mDisplayContent;
Winson Chung732446a2018-09-19 13:15:17 -0700116 private int mTargetActivityType;
Winson Chung584d6522018-02-07 23:57:38 +0000117 private Rect mMinimizedHomeBounds = new Rect();
Winson Chunge2d72172018-01-25 17:46:20 +0000118
119 // We start the RecentsAnimationController in a pending-start state since we need to wait for
120 // the wallpaper/activity to draw before we can give control to the handler to start animating
121 // the visible task surfaces
122 private boolean mPendingStart = true;
123
124 // Set when the animation has been canceled
Winson Chungf557c3b2018-03-16 10:55:20 -0700125 private boolean mCanceled;
Winson Chunge2d72172018-01-25 17:46:20 +0000126
127 // Whether or not the input consumer is enabled. The input consumer must be both registered and
128 // enabled for it to start intercepting touch events.
129 private boolean mInputConsumerEnabled;
130
Adrian Roos653c6c12018-04-09 14:12:46 -0700131 private final Rect mTmpRect = new Rect();
132
133 private boolean mLinkedToDeathOfRunner;
Winson Chunga89ffed2018-01-25 17:46:11 +0000134
Winson Chung7a545ae2019-07-16 14:52:13 -0700135 // Whether to try to defer canceling from a stack order change until the next transition
136 private boolean mRequestDeferCancelUntilNextTransition;
137 // Whether to actually defer canceling until the next transition
lumark54284462019-03-05 20:44:27 +0800138 private boolean mCancelOnNextTransitionStart;
Winson Chung7a545ae2019-07-16 14:52:13 -0700139 // Whether to take a screenshot when handling a deferred cancel
140 private boolean mCancelDeferredWithScreenshot;
lumark54284462019-03-05 20:44:27 +0800141
142 /**
143 * Animates the screenshot of task that used to be controlled by RecentsAnimation.
Winson Chung7a545ae2019-07-16 14:52:13 -0700144 * @see {@link #setCancelOnNextTransitionStart}
lumark54284462019-03-05 20:44:27 +0800145 */
146 SurfaceAnimator mRecentScreenshotAnimator;
147
Winson Chung7a545ae2019-07-16 14:52:13 -0700148 /**
149 * An app transition listener to cancel the recents animation only after the app transition
150 * starts or is canceled.
151 */
lumark54284462019-03-05 20:44:27 +0800152 final AppTransitionListener mAppTransitionListener = new AppTransitionListener() {
153 @Override
154 public int onAppTransitionStartingLocked(int transit, long duration,
155 long statusBarAnimationStartTime, long statusBarAnimationDuration) {
Winson Chung7a545ae2019-07-16 14:52:13 -0700156 continueDeferredCancel();
lumark54284462019-03-05 20:44:27 +0800157 return 0;
158 }
Winson Chung7a545ae2019-07-16 14:52:13 -0700159
160 @Override
161 public void onAppTransitionCancelledLocked(int transit) {
162 continueDeferredCancel();
163 }
164
165 private void continueDeferredCancel() {
166 mDisplayContent.mAppTransition.unregisterListener(this);
167 if (mCanceled) {
168 return;
169 }
170
171 if (mCancelOnNextTransitionStart) {
172 mCancelOnNextTransitionStart = false;
173 cancelAnimationWithScreenshot(mCancelDeferredWithScreenshot);
174 }
175 }
lumark54284462019-03-05 20:44:27 +0800176 };
177
Winson Chunge2d72172018-01-25 17:46:20 +0000178 public interface RecentsAnimationCallbacks {
Tracy Zhou9c675d42019-04-08 00:32:40 -0700179 /** Callback when recents animation is finished. */
Wale Ogunwalea441b922019-06-27 19:21:44 -0700180 void onAnimationFinished(@ReorderMode int reorderMode, boolean sendUserLeaveHint);
Winson Chunge2d72172018-01-25 17:46:20 +0000181 }
182
183 private final IRecentsAnimationController mController =
184 new IRecentsAnimationController.Stub() {
185
186 @Override
187 public TaskSnapshot screenshotTask(int taskId) {
Adrian Roosb125e0b2019-10-02 14:55:14 +0200188 ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
189 "screenshotTask(%d): mCanceled=%b", taskId, mCanceled);
Winson Chungf557c3b2018-03-16 10:55:20 -0700190 final long token = Binder.clearCallingIdentity();
Winson Chunge2d72172018-01-25 17:46:20 +0000191 try {
192 synchronized (mService.getWindowManagerLock()) {
193 if (mCanceled) {
194 return null;
195 }
196 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
197 final TaskAnimationAdapter adapter = mPendingAnimations.get(i);
198 final Task task = adapter.mTask;
199 if (task.mTaskId == taskId) {
Winson Chung23aa7b12018-02-01 11:41:43 -0800200 final TaskSnapshotController snapshotController =
201 mService.mTaskSnapshotController;
202 final ArraySet<Task> tasks = Sets.newArraySet(task);
203 snapshotController.snapshotTasks(tasks);
204 snapshotController.addSkipClosingAppSnapshotTasks(tasks);
205 return snapshotController.getSnapshot(taskId, 0 /* userId */,
Peter Kalauskas4dc04602020-02-12 18:49:03 -0800206 false /* restoreFromDisk */, false /* isLowResolution */);
Winson Chunge2d72172018-01-25 17:46:20 +0000207 }
208 }
209 return null;
210 }
211 } finally {
212 Binder.restoreCallingIdentity(token);
213 }
214 }
215
216 @Override
Tracy Zhou9c675d42019-04-08 00:32:40 -0700217 public void finish(boolean moveHomeToTop, boolean sendUserLeaveHint) {
Adrian Roosb125e0b2019-10-02 14:55:14 +0200218 ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
219 "finish(%b): mCanceled=%b", moveHomeToTop, mCanceled);
Winson Chungf557c3b2018-03-16 10:55:20 -0700220 final long token = Binder.clearCallingIdentity();
Winson Chunge2d72172018-01-25 17:46:20 +0000221 try {
222 synchronized (mService.getWindowManagerLock()) {
223 if (mCanceled) {
224 return;
225 }
lumark04bceb92020-03-07 00:03:33 +0800226 // Remove all new task targets.
227 for (int i = mPendingNewTaskTargets.size() - 1; i >= 0; i--) {
228 removeTaskInternal(mPendingNewTaskTargets.get(i));
229 }
Winson Chunge2d72172018-01-25 17:46:20 +0000230 }
231
232 // Note, the callback will handle its own synchronization, do not lock on WM lock
233 // prior to calling the callback
Winson Chung6a38fca2018-03-28 17:57:09 -0700234 mCallbacks.onAnimationFinished(moveHomeToTop
Winson Chung3e2980e2018-03-29 17:28:57 -0700235 ? REORDER_MOVE_TO_TOP
Wale Ogunwalea441b922019-06-27 19:21:44 -0700236 : REORDER_MOVE_TO_ORIGINAL_POSITION, sendUserLeaveHint);
Winson Chunge2d72172018-01-25 17:46:20 +0000237 } finally {
238 Binder.restoreCallingIdentity(token);
239 }
240 }
241
242 @Override
Jorim Jaggi50bf59c2018-03-09 17:29:48 +0100243 public void setAnimationTargetsBehindSystemBars(boolean behindSystemBars)
244 throws RemoteException {
Winson Chungf557c3b2018-03-16 10:55:20 -0700245 final long token = Binder.clearCallingIdentity();
Jorim Jaggi50bf59c2018-03-09 17:29:48 +0100246 try {
247 synchronized (mService.getWindowManagerLock()) {
248 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
Winson Chungce48a252019-03-21 11:03:03 -0700249 final Task task = mPendingAnimations.get(i).mTask;
250 if (task.getActivityType() != mTargetActivityType) {
251 task.setCanAffectSystemUiFlags(behindSystemBars);
252 }
Jorim Jaggi50bf59c2018-03-09 17:29:48 +0100253 }
254 mService.mWindowPlacerLocked.requestTraversal();
255 }
256 } finally {
257 Binder.restoreCallingIdentity(token);
258 }
259 }
260
261 @Override
Winson Chunge2d72172018-01-25 17:46:20 +0000262 public void setInputConsumerEnabled(boolean enabled) {
Adrian Roosb125e0b2019-10-02 14:55:14 +0200263 ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
264 "setInputConsumerEnabled(%s): mCanceled=%b", enabled, mCanceled);
Winson Chungf557c3b2018-03-16 10:55:20 -0700265 final long token = Binder.clearCallingIdentity();
Winson Chunge2d72172018-01-25 17:46:20 +0000266 try {
267 synchronized (mService.getWindowManagerLock()) {
268 if (mCanceled) {
269 return;
270 }
271
272 mInputConsumerEnabled = enabled;
Winson Chung7a545ae2019-07-16 14:52:13 -0700273 final InputMonitor inputMonitor = mDisplayContent.getInputMonitor();
Arthur Hung95b38a92018-07-20 18:56:12 +0800274 inputMonitor.updateInputWindowsLw(true /*force*/);
Winson Chunge2d72172018-01-25 17:46:20 +0000275 mService.scheduleAnimationLocked();
276 }
277 } finally {
278 Binder.restoreCallingIdentity(token);
279 }
280 }
Winson Chungf557c3b2018-03-16 10:55:20 -0700281
282 @Override
Winson Chunga840c322018-04-20 15:58:18 -0700283 public void hideCurrentInputMethod() {
284 final long token = Binder.clearCallingIdentity();
285 try {
286 final InputMethodManagerInternal inputMethodManagerInternal =
287 LocalServices.getService(InputMethodManagerInternal.class);
288 if (inputMethodManagerInternal != null) {
lumarkd85e1582019-12-29 20:20:41 +0800289 inputMethodManagerInternal.hideCurrentInputMethod(
290 SoftInputShowHideReason.HIDE_RECENTS_ANIMATION);
Winson Chunga840c322018-04-20 15:58:18 -0700291 }
292 } finally {
293 Binder.restoreCallingIdentity(token);
294 }
295 }
lumark54284462019-03-05 20:44:27 +0800296
297 @Override
Winson Chung7a545ae2019-07-16 14:52:13 -0700298 public void setDeferCancelUntilNextTransition(boolean defer, boolean screenshot) {
299 synchronized (mService.mGlobalLock) {
300 setDeferredCancel(defer, screenshot);
lumark54284462019-03-05 20:44:27 +0800301 }
302 }
303
304 @Override
305 public void cleanupScreenshot() {
Winson Chung7a545ae2019-07-16 14:52:13 -0700306 synchronized (mService.mGlobalLock) {
lumark54284462019-03-05 20:44:27 +0800307 if (mRecentScreenshotAnimator != null) {
308 mRecentScreenshotAnimator.cancelAnimation();
309 mRecentScreenshotAnimator = null;
310 }
311 }
312 }
Tracy Zhou9e0354f2019-10-03 18:05:03 -0700313
314 @Override
315 public void setWillFinishToHome(boolean willFinishToHome) {
316 synchronized (mService.getWindowManagerLock()) {
317 mWillFinishToHome = willFinishToHome;
318 }
319 }
lumark04bceb92020-03-07 00:03:33 +0800320
321 @Override
322 public boolean removeTask(int taskId) {
323 final long token = Binder.clearCallingIdentity();
324 try {
325 synchronized (mService.getWindowManagerLock()) {
326 return removeTaskInternal(taskId);
327 }
328 } finally {
329 Binder.restoreCallingIdentity(token);
330 }
331 }
Winson Chunge2d72172018-01-25 17:46:20 +0000332 };
333
334 /**
Winson Chunge2d72172018-01-25 17:46:20 +0000335 * @param remoteAnimationRunner The remote runner which should be notified when the animation is
336 * ready to start or has been canceled
337 * @param callbacks Callbacks to be made when the animation finishes
Winson Chunge2d72172018-01-25 17:46:20 +0000338 */
339 RecentsAnimationController(WindowManagerService service,
340 IRecentsAnimationRunner remoteAnimationRunner, RecentsAnimationCallbacks callbacks,
341 int displayId) {
342 mService = service;
343 mRunner = remoteAnimationRunner;
344 mCallbacks = callbacks;
Winson Chungddf62972018-02-12 11:10:04 -0800345 mDisplayId = displayId;
Winson Chung67e49362019-05-17 16:40:38 -0700346 mStatusBar = LocalServices.getService(StatusBarManagerInternal.class);
Winson Chung7a545ae2019-07-16 14:52:13 -0700347 mDisplayContent = service.mRoot.getDisplayContent(displayId);
Winson Chung732446a2018-09-19 13:15:17 -0700348 }
349
Winson Chungddf62972018-02-12 11:10:04 -0800350 /**
351 * Initializes the recents animation controller. This is a separate call from the constructor
352 * because it may call cancelAnimation() which needs to properly clean up the controller
353 * in the window manager.
354 */
wilsonshih417b70c12019-10-16 16:12:02 +0800355 public void initialize(int targetActivityType, SparseBooleanArray recentTaskIds,
356 ActivityRecord targetActivity) {
Winson Chung732446a2018-09-19 13:15:17 -0700357 mTargetActivityType = targetActivityType;
Winson Chung7a545ae2019-07-16 14:52:13 -0700358 mDisplayContent.mAppTransition.registerListenerLocked(mAppTransitionListener);
Winson Chung732446a2018-09-19 13:15:17 -0700359
360 // Make leashes for each of the visible/target tasks and add it to the recents animation to
361 // be started
Andrii Kulianf9df4a82020-03-31 12:09:27 -0700362 // TODO(b/153090560): Support Recents on multiple task display areas
Andrii Kulian4c0fd0d2020-03-29 13:32:14 -0700363 final ArrayList<Task> visibleTasks = mDisplayContent.getDefaultTaskDisplayArea()
364 .getVisibleTasks();
365 final ActivityStack targetStack = mDisplayContent.getDefaultTaskDisplayArea()
366 .getStack(WINDOWING_MODE_UNDEFINED, targetActivityType);
Winson Chung732446a2018-09-19 13:15:17 -0700367 if (targetStack != null) {
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800368 final PooledConsumer c = PooledLambda.obtainConsumer((t, outList) ->
369 { if (!outList.contains(t)) outList.add(t); }, PooledLambda.__(Task.class),
370 visibleTasks);
Wale Ogunwale0d465192020-01-23 19:14:44 -0800371 targetStack.forAllLeafTasks(c, true /* traverseTopToBottom */);
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800372 c.recycle();
Winson Chung732446a2018-09-19 13:15:17 -0700373 }
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800374
Winson Chunge2d72172018-01-25 17:46:20 +0000375 final int taskCount = visibleTasks.size();
376 for (int i = 0; i < taskCount; i++) {
377 final Task task = visibleTasks.get(i);
378 final WindowConfiguration config = task.getWindowConfiguration();
379 if (config.tasksAreFloating()
Winson Chung732446a2018-09-19 13:15:17 -0700380 || config.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
Winson Chunge2d72172018-01-25 17:46:20 +0000381 continue;
382 }
Vadim Tryshev593e9562018-03-08 17:15:45 -0800383 addAnimation(task, !recentTaskIds.get(task.mTaskId));
Winson Chunge2d72172018-01-25 17:46:20 +0000384 }
385
Winson Chungddf62972018-02-12 11:10:04 -0800386 // Skip the animation if there is nothing to animate
387 if (mPendingAnimations.isEmpty()) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700388 cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "initialize-noVisibleTasks");
Winson Chungddf62972018-02-12 11:10:04 -0800389 return;
390 }
391
Adrian Roos842e7882018-03-26 17:34:06 +0200392 try {
Adrian Roos653c6c12018-04-09 14:12:46 -0700393 linkToDeathOfRunner();
Adrian Roos842e7882018-03-26 17:34:06 +0200394 } catch (RemoteException e) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700395 cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "initialize-failedToLinkToDeath");
Adrian Roos842e7882018-03-26 17:34:06 +0200396 return;
397 }
398
Winson Chung3e2980e2018-03-29 17:28:57 -0700399 // Adjust the wallpaper visibility for the showing target activity
wilsonshih417b70c12019-10-16 16:12:02 +0800400 ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
401 "setHomeApp(%s)", targetActivity.getName());
402 mTargetActivityRecord = targetActivity;
403 if (targetActivity.windowsCanBeWallpaperTarget()) {
404 mDisplayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
405 mDisplayContent.setLayoutNeeded();
Winson Chunge2d72172018-01-25 17:46:20 +0000406 }
407
Winson Chung584d6522018-02-07 23:57:38 +0000408 // Save the minimized home height
Andrii Kulian4c0fd0d2020-03-29 13:32:14 -0700409 mMinimizedHomeBounds = mDisplayContent.getDefaultTaskDisplayArea().getRootHomeTask()
410 .getBounds();
Winson Chung584d6522018-02-07 23:57:38 +0000411
Winson Chunge2d72172018-01-25 17:46:20 +0000412 mService.mWindowPlacerLocked.performSurfacePlacement();
Winson Chung67e49362019-05-17 16:40:38 -0700413
Vadim Caena0fa9662020-01-27 15:00:01 +0100414 // If the target activity has a fixed orientation which is different from the current top
415 // activity, it will be rotated before being shown so we avoid a screen rotation
416 // animation when showing the Recents view.
417 mDisplayContent.rotateInDifferentOrientationIfNeeded(mTargetActivityRecord);
418
Winson Chung67e49362019-05-17 16:40:38 -0700419 // Notify that the animation has started
Winson Chung7a545ae2019-07-16 14:52:13 -0700420 if (mStatusBar != null) {
421 mStatusBar.onRecentsAnimationStateChanged(true /* running */);
422 }
Winson Chunge2d72172018-01-25 17:46:20 +0000423 }
424
Winson Chungda876c92018-04-05 18:31:06 -0700425 @VisibleForTesting
426 AnimationAdapter addAnimation(Task task, boolean isRecentTaskInvisible) {
lumark04bceb92020-03-07 00:03:33 +0800427 return addAnimation(task, isRecentTaskInvisible, null /* finishedCallback */);
428 }
429
430 @VisibleForTesting
431 AnimationAdapter addAnimation(Task task, boolean isRecentTaskInvisible,
432 OnAnimationFinishedCallback finishedCallback) {
Adrian Roosb125e0b2019-10-02 14:55:14 +0200433 ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "addAnimation(%s)", task.getName());
Vadim Tryshev593e9562018-03-08 17:15:45 -0800434 final TaskAnimationAdapter taskAdapter = new TaskAnimationAdapter(task,
435 isRecentTaskInvisible);
Issei Suzuki8b995df2020-01-08 12:23:04 +0100436 task.startAnimation(task.getPendingTransaction(), taskAdapter, false /* hidden */,
lumark04bceb92020-03-07 00:03:33 +0800437 ANIMATION_TYPE_RECENTS, finishedCallback);
Winson Chunge2d72172018-01-25 17:46:20 +0000438 task.commitPendingTransaction();
439 mPendingAnimations.add(taskAdapter);
Winson Chungda876c92018-04-05 18:31:06 -0700440 return taskAdapter;
441 }
442
443 @VisibleForTesting
444 void removeAnimation(TaskAnimationAdapter taskAdapter) {
Adrian Roosb125e0b2019-10-02 14:55:14 +0200445 ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
446 "removeAnimation(%d)", taskAdapter.mTask.mTaskId);
Winson Chungda876c92018-04-05 18:31:06 -0700447 taskAdapter.mTask.setCanAffectSystemUiFlags(true);
Issei Suzuki8b995df2020-01-08 12:23:04 +0100448 taskAdapter.mCapturedFinishCallback.onAnimationFinished(taskAdapter.mLastAnimationType,
449 taskAdapter);
Winson Chungda876c92018-04-05 18:31:06 -0700450 mPendingAnimations.remove(taskAdapter);
Winson Chunge2d72172018-01-25 17:46:20 +0000451 }
452
Winson Chungd5852192019-09-06 17:20:28 -0700453 @VisibleForTesting
454 void removeWallpaperAnimation(WallpaperAnimationAdapter wallpaperAdapter) {
Adrian Roosb125e0b2019-10-02 14:55:14 +0200455 ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "removeWallpaperAnimation()");
Issei Suzuki8b995df2020-01-08 12:23:04 +0100456 wallpaperAdapter.getLeashFinishedCallback().onAnimationFinished(
457 wallpaperAdapter.getLastAnimationType(), wallpaperAdapter);
Winson Chungd5852192019-09-06 17:20:28 -0700458 mPendingWallpaperAnimations.remove(wallpaperAdapter);
459 }
460
Winson Chunge2d72172018-01-25 17:46:20 +0000461 void startAnimation() {
Adrian Roosb125e0b2019-10-02 14:55:14 +0200462 ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
463 "startAnimation(): mPendingStart=%b mCanceled=%b", mPendingStart, mCanceled);
Winson Chungddf62972018-02-12 11:10:04 -0800464 if (!mPendingStart || mCanceled) {
465 // Skip starting if we've already started or canceled the animation
Winson Chunge2d72172018-01-25 17:46:20 +0000466 return;
467 }
468 try {
Winson Chungd5852192019-09-06 17:20:28 -0700469 // Create the app targets
470 final RemoteAnimationTarget[] appTargets = createAppAnimations();
Winson Chungda876c92018-04-05 18:31:06 -0700471
472 // Skip the animation if there is nothing to animate
Winson Chungd5852192019-09-06 17:20:28 -0700473 if (appTargets.length == 0) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700474 cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "startAnimation-noAppWindows");
Winson Chungda876c92018-04-05 18:31:06 -0700475 return;
476 }
477
Winson Chungd5852192019-09-06 17:20:28 -0700478 // Create the wallpaper targets
479 final RemoteAnimationTarget[] wallpaperTargets = createWallpaperAnimations();
480
Winson Chunge2d72172018-01-25 17:46:20 +0000481 mPendingStart = false;
Winson Chung584d6522018-02-07 23:57:38 +0000482
Winson Chung9e8b0cb2018-08-03 16:23:52 -0700483 // Perform layout if it was scheduled before to make sure that we get correct content
484 // insets for the target app window after a rotation
Winson Chung7a545ae2019-07-16 14:52:13 -0700485 mDisplayContent.performLayout(false /* initial */, false /* updateInputWindows */);
Winson Chung9e8b0cb2018-08-03 16:23:52 -0700486
Garfield Tane8d84ab2019-10-11 09:49:40 -0700487 final Rect minimizedHomeBounds = mTargetActivityRecord != null
488 && mTargetActivityRecord.inSplitScreenSecondaryWindowingMode()
Winson Chung3e2980e2018-03-29 17:28:57 -0700489 ? mMinimizedHomeBounds
490 : null;
Vadim Tryshev257f86b2018-08-23 16:45:02 -0700491 final Rect contentInsets;
Garfield Tane8d84ab2019-10-11 09:49:40 -0700492 if (mTargetActivityRecord != null && mTargetActivityRecord.findMainWindow() != null) {
493 contentInsets = mTargetActivityRecord.findMainWindow().getContentInsets();
Vadim Tryshev257f86b2018-08-23 16:45:02 -0700494 } else {
495 // If the window for the activity had not yet been created, use the display insets.
496 mService.getStableInsets(mDisplayId, mTmpRect);
497 contentInsets = mTmpRect;
498 }
Winson Chungd5852192019-09-06 17:20:28 -0700499 mRunner.onAnimationStart(mController, appTargets, wallpaperTargets, contentInsets,
500 minimizedHomeBounds);
Adrian Roosb125e0b2019-10-02 14:55:14 +0200501 ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
502 "startAnimation(): Notify animation start: %s",
503 mPendingAnimations.stream()
504 .map(anim->anim.mTask.mTaskId).collect(Collectors.toList()));
Winson Chunge2d72172018-01-25 17:46:20 +0000505 } catch (RemoteException e) {
506 Slog.e(TAG, "Failed to start recents animation", e);
507 }
Riddle Hsufd66d4d2019-11-14 10:35:55 +0800508
509 if (mTargetActivityRecord != null) {
Evan Rosky55bddd82020-01-29 13:07:18 -0800510 final ArrayMap<WindowContainer, Integer> reasons = new ArrayMap<>(1);
Riddle Hsufd66d4d2019-11-14 10:35:55 +0800511 reasons.put(mTargetActivityRecord, APP_TRANSITION_RECENTS_ANIM);
512 mService.mAtmService.mStackSupervisor.getActivityMetricsLogger()
513 .notifyTransitionStarting(reasons);
514 }
Winson Chunge2d72172018-01-25 17:46:20 +0000515 }
516
lumark04bceb92020-03-07 00:03:33 +0800517 void addTaskToTargets(Task task, OnAnimationFinishedCallback finishedCallback) {
518 if (mRunner != null) {
519 final RemoteAnimationTarget target = createTaskRemoteAnimation(task, finishedCallback);
520 if (target == null) return;
521
522 ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "addTaskToTargets, target: %s", target);
523 try {
524 mRunner.onTaskAppeared(target);
525 } catch (RemoteException e) {
526 Slog.e(TAG, "Failed to report task appeared", e);
527 }
528 }
529 }
530
531 private RemoteAnimationTarget createTaskRemoteAnimation(Task task,
532 OnAnimationFinishedCallback finishedCallback) {
533 final SparseBooleanArray recentTaskIds =
534 mService.mAtmService.getRecentTasks().getRecentTaskIds();
535 TaskAnimationAdapter adapter = (TaskAnimationAdapter) addAnimation(task,
536 !recentTaskIds.get(task.mTaskId), finishedCallback);
537 mPendingNewTaskTargets.add(task.mTaskId);
538 return adapter.createRemoteAnimationTarget();
539 }
540
541 private boolean removeTaskInternal(int taskId) {
542 boolean result = false;
543 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
544 // Only allows when task target has became visible to user, to prevent
545 // the flickering during remove animation and task visible.
546 final TaskAnimationAdapter target = mPendingAnimations.get(i);
547 if (target.mTask.mTaskId == taskId && target.mTask.isOnTop()) {
548 removeAnimation(target);
549 final int taskIndex = mPendingNewTaskTargets.indexOf(taskId);
550 if (taskIndex != -1) {
551 mPendingNewTaskTargets.remove(taskIndex);
552 }
553 result = true;
554 break;
555 }
556 }
557 return result;
558 }
559
Winson Chungd5852192019-09-06 17:20:28 -0700560 private RemoteAnimationTarget[] createAppAnimations() {
561 final ArrayList<RemoteAnimationTarget> targets = new ArrayList<>();
562 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
563 final TaskAnimationAdapter taskAdapter = mPendingAnimations.get(i);
564 final RemoteAnimationTarget target = taskAdapter.createRemoteAnimationTarget();
565 if (target != null) {
566 targets.add(target);
567 } else {
568 removeAnimation(taskAdapter);
569 }
570 }
571 return targets.toArray(new RemoteAnimationTarget[targets.size()]);
572 }
573
574 private RemoteAnimationTarget[] createWallpaperAnimations() {
Adrian Roosb125e0b2019-10-02 14:55:14 +0200575 ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "createWallpaperAnimations()");
Winson Chungd5852192019-09-06 17:20:28 -0700576 return WallpaperAnimationAdapter.startWallpaperAnimations(mService, 0L, 0L,
577 adapter -> {
578 synchronized (mService.mGlobalLock) {
579 // If the wallpaper animation is canceled, continue with the recents
580 // animation
581 mPendingWallpaperAnimations.remove(adapter);
582 }
583 }, mPendingWallpaperAnimations);
584 }
585
Winson Chungc6c3f852018-04-09 15:41:03 -0700586 void cancelAnimation(@ReorderMode int reorderMode, String reason) {
Wale Ogunwalea441b922019-06-27 19:21:44 -0700587 cancelAnimation(reorderMode, false /*screenshot */, reason);
lumark54284462019-03-05 20:44:27 +0800588 }
589
Winson Chung7a545ae2019-07-16 14:52:13 -0700590 void cancelAnimationWithScreenshot(boolean screenshot) {
Wale Ogunwalea441b922019-06-27 19:21:44 -0700591 cancelAnimation(REORDER_KEEP_IN_PLACE, screenshot, "stackOrderChanged");
Winson Chung65c5f992018-04-20 14:58:57 -0700592 }
593
Wale Ogunwalea441b922019-06-27 19:21:44 -0700594 private void cancelAnimation(@ReorderMode int reorderMode, boolean screenshot, String reason) {
Adrian Roosb125e0b2019-10-02 14:55:14 +0200595 ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "cancelAnimation(): reason=%s", reason);
Winson Chung65fc89a2018-02-28 08:32:12 -0800596 synchronized (mService.getWindowManagerLock()) {
597 if (mCanceled) {
598 // We've already canceled the animation
599 return;
600 }
Adrian Roos842e7882018-03-26 17:34:06 +0200601 mService.mH.removeCallbacks(mFailsafeRunnable);
Winson Chung65fc89a2018-02-28 08:32:12 -0800602 mCanceled = true;
Winson Chung7a545ae2019-07-16 14:52:13 -0700603
604 if (screenshot) {
605 // Screen shot previous task when next task starts transition and notify the runner.
606 // We will actually finish the animation once the runner calls cleanUpScreenshot().
607 final Task task = mPendingAnimations.get(0).mTask;
Wale Ogunwalea441b922019-06-27 19:21:44 -0700608 final TaskSnapshot taskSnapshot = screenshotRecentTask(task, reorderMode);
Winson Chung7a545ae2019-07-16 14:52:13 -0700609 try {
Tracy Zhou8089ffa2019-07-30 17:30:43 -0700610 mRunner.onAnimationCanceled(taskSnapshot);
Winson Chung7a545ae2019-07-16 14:52:13 -0700611 } catch (RemoteException e) {
612 Slog.e(TAG, "Failed to cancel recents animation", e);
lumark54284462019-03-05 20:44:27 +0800613 }
Tracy Zhou8089ffa2019-07-30 17:30:43 -0700614 if (taskSnapshot == null) {
Wale Ogunwalea441b922019-06-27 19:21:44 -0700615 mCallbacks.onAnimationFinished(reorderMode, false /* sendUserLeaveHint */);
Tracy Zhou8089ffa2019-07-30 17:30:43 -0700616 }
Winson Chung7a545ae2019-07-16 14:52:13 -0700617 } else {
618 // Otherwise, notify the runner and clean up the animation immediately
619 // Note: In the fallback case, this can trigger multiple onAnimationCancel() calls
620 // to the runner if we this actually triggers cancel twice on the caller
621 try {
Tracy Zhou8089ffa2019-07-30 17:30:43 -0700622 mRunner.onAnimationCanceled(null /* taskSnapshot */);
Winson Chung7a545ae2019-07-16 14:52:13 -0700623 } catch (RemoteException e) {
624 Slog.e(TAG, "Failed to cancel recents animation", e);
625 }
Wale Ogunwalea441b922019-06-27 19:21:44 -0700626 mCallbacks.onAnimationFinished(reorderMode, false /* sendUserLeaveHint */);
Winson Chung65fc89a2018-02-28 08:32:12 -0800627 }
lumark54284462019-03-05 20:44:27 +0800628 }
629 }
630
631 /**
632 * Cancel recents animation when the next app transition starts.
633 * <p>
634 * When we cancel the recents animation due to a stack order change, we can't just cancel it
635 * immediately as it would lead to a flicker in Launcher if we just remove the task from the
636 * leash. Instead we screenshot the previous task and replace the child of the leash with the
637 * screenshot, so that Launcher can still control the leash lifecycle & make the next app
638 * transition animate smoothly without flickering.
639 */
Winson Chung7a545ae2019-07-16 14:52:13 -0700640 void setCancelOnNextTransitionStart() {
lumark54284462019-03-05 20:44:27 +0800641 mCancelOnNextTransitionStart = true;
642 }
643
Winson Chung7a545ae2019-07-16 14:52:13 -0700644 /**
645 * Requests that we attempt to defer the cancel until the next app transition if we are
646 * canceling from a stack order change. If {@param screenshot} is specified, then the system
647 * will replace the contents of the leash with a screenshot, which must be cleaned up when the
648 * runner calls cleanUpScreenshot().
649 */
650 void setDeferredCancel(boolean defer, boolean screenshot) {
651 mRequestDeferCancelUntilNextTransition = defer;
652 mCancelDeferredWithScreenshot = screenshot;
lumark54284462019-03-05 20:44:27 +0800653 }
654
Winson Chung7a545ae2019-07-16 14:52:13 -0700655 /**
656 * @return Whether we should defer the cancel from a stack order change until the next app
657 * transition.
658 */
659 boolean shouldDeferCancelUntilNextTransition() {
660 return mRequestDeferCancelUntilNextTransition;
lumark54284462019-03-05 20:44:27 +0800661 }
662
Winson Chung7a545ae2019-07-16 14:52:13 -0700663 /**
664 * @return Whether we should both defer the cancel from a stack order change until the next
665 * app transition, and also that the deferred cancel should replace the contents of the leash
666 * with a screenshot.
667 */
668 boolean shouldDeferCancelWithScreenshot() {
669 return mRequestDeferCancelUntilNextTransition && mCancelDeferredWithScreenshot;
lumark54284462019-03-05 20:44:27 +0800670 }
671
Wale Ogunwalea441b922019-06-27 19:21:44 -0700672 TaskSnapshot screenshotRecentTask(Task task, @ReorderMode int reorderMode) {
Tracy Zhou8089ffa2019-07-30 17:30:43 -0700673 final TaskSnapshotController snapshotController = mService.mTaskSnapshotController;
674 final ArraySet<Task> tasks = Sets.newArraySet(task);
675 snapshotController.snapshotTasks(tasks);
676 snapshotController.addSkipClosingAppSnapshotTasks(tasks);
677 final TaskSnapshot taskSnapshot = snapshotController.getSnapshot(task.mTaskId,
Peter Kalauskas4dc04602020-02-12 18:49:03 -0800678 task.mUserId, false /* restoreFromDisk */, false /* isLowResolution */);
Tracy Zhou8089ffa2019-07-30 17:30:43 -0700679 if (taskSnapshot == null) {
680 return null;
lumark54284462019-03-05 20:44:27 +0800681 }
Tracy Zhou8089ffa2019-07-30 17:30:43 -0700682
Vishnu Nair33197392019-08-30 10:29:37 -0700683 final TaskScreenshotAnimatable animatable = new TaskScreenshotAnimatable(mService.mSurfaceControlFactory, task,
Tracy Zhou8089ffa2019-07-30 17:30:43 -0700684 new SurfaceControl.ScreenshotGraphicBuffer(taskSnapshot.getSnapshot(),
685 taskSnapshot.getColorSpace(), false /* containsSecureLayers */));
686 mRecentScreenshotAnimator = new SurfaceAnimator(
687 animatable,
Issei Suzuki8b995df2020-01-08 12:23:04 +0100688 (type, anim) -> {
Adrian Roosb125e0b2019-10-02 14:55:14 +0200689 ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "mRecentScreenshotAnimator finish");
Wale Ogunwalea441b922019-06-27 19:21:44 -0700690 mCallbacks.onAnimationFinished(reorderMode, false /* sendUserLeaveHint */);
Tracy Zhou8089ffa2019-07-30 17:30:43 -0700691 }, mService);
692 mRecentScreenshotAnimator.transferAnimation(task.mSurfaceAnimator);
693 return taskSnapshot;
Winson Chunge2d72172018-01-25 17:46:20 +0000694 }
695
Winson Chung6a38fca2018-03-28 17:57:09 -0700696 void cleanupAnimation(@ReorderMode int reorderMode) {
Adrian Roosb125e0b2019-10-02 14:55:14 +0200697 ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
698 "cleanupAnimation(): Notify animation finished mPendingAnimations=%d "
699 + "reorderMode=%d",
700 mPendingAnimations.size(), reorderMode);
Winson Chunge2d72172018-01-25 17:46:20 +0000701 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
Winson Chungda876c92018-04-05 18:31:06 -0700702 final TaskAnimationAdapter taskAdapter = mPendingAnimations.get(i);
Winson Chung3e2980e2018-03-29 17:28:57 -0700703 if (reorderMode == REORDER_MOVE_TO_TOP || reorderMode == REORDER_KEEP_IN_PLACE) {
Winson Chungda876c92018-04-05 18:31:06 -0700704 taskAdapter.mTask.dontAnimateDimExit();
chaviw87ca63a2018-03-26 14:06:17 -0700705 }
Winson Chungda876c92018-04-05 18:31:06 -0700706 removeAnimation(taskAdapter);
Winson Chunge2d72172018-01-25 17:46:20 +0000707 }
Winson Chunge2d72172018-01-25 17:46:20 +0000708
Winson Chungd5852192019-09-06 17:20:28 -0700709 for (int i = mPendingWallpaperAnimations.size() - 1; i >= 0; i--) {
710 final WallpaperAnimationAdapter wallpaperAdapter = mPendingWallpaperAnimations.get(i);
711 removeWallpaperAnimation(wallpaperAdapter);
712 }
713
Winson Chung7906b3e2018-05-10 10:32:39 -0700714 // Clear any pending failsafe runnables
715 mService.mH.removeCallbacks(mFailsafeRunnable);
Winson Chung7a545ae2019-07-16 14:52:13 -0700716 mDisplayContent.mAppTransition.unregisterListener(mAppTransitionListener);
Winson Chung7906b3e2018-05-10 10:32:39 -0700717
Winson Chung5c91e8f2018-05-07 10:06:55 -0700718 // Clear references to the runner
Adrian Roos653c6c12018-04-09 14:12:46 -0700719 unlinkToDeathOfRunner();
Winson Chung5c91e8f2018-05-07 10:06:55 -0700720 mRunner = null;
Winson Chung7906b3e2018-05-10 10:32:39 -0700721 mCanceled = true;
Winson Chung5c91e8f2018-05-07 10:06:55 -0700722
lumark54284462019-03-05 20:44:27 +0800723 // Make sure previous animator has cleaned-up.
724 if (mRecentScreenshotAnimator != null) {
725 mRecentScreenshotAnimator.cancelAnimation();
726 mRecentScreenshotAnimator = null;
727 }
728
Winson Chungdb111ee2018-10-03 14:25:34 -0700729 // Update the input windows after the animation is complete
Winson Chung7a545ae2019-07-16 14:52:13 -0700730 final InputMonitor inputMonitor = mDisplayContent.getInputMonitor();
Arthur Hung95b38a92018-07-20 18:56:12 +0800731 inputMonitor.updateInputWindowsLw(true /*force*/);
Winson Chung0bb66cc2018-04-10 11:58:15 -0700732
733 // We have deferred all notifications to the target app as a part of the recents animation,
734 // so if we are actually transitioning there, notify again here
Garfield Tane8d84ab2019-10-11 09:49:40 -0700735 if (mTargetActivityRecord != null) {
Winson Chung0bb66cc2018-04-10 11:58:15 -0700736 if (reorderMode == REORDER_MOVE_TO_TOP || reorderMode == REORDER_KEEP_IN_PLACE) {
Winson Chung7a545ae2019-07-16 14:52:13 -0700737 mDisplayContent.mAppTransition.notifyAppTransitionFinishedLocked(
Garfield Tane8d84ab2019-10-11 09:49:40 -0700738 mTargetActivityRecord.token);
Winson Chung0bb66cc2018-04-10 11:58:15 -0700739 }
Vadim Caena0fa9662020-01-27 15:00:01 +0100740 if (mTargetActivityRecord.hasFixedRotationTransform()) {
Riddle Hsu06aeb062020-03-24 23:38:40 +0800741 mTargetActivityRecord.finishFixedRotationTransform();
Vadim Caena0fa9662020-01-27 15:00:01 +0100742 }
Winson Chung0bb66cc2018-04-10 11:58:15 -0700743 }
Winson Chung67e49362019-05-17 16:40:38 -0700744
745 // Notify that the animation has ended
Winson Chung7a545ae2019-07-16 14:52:13 -0700746 if (mStatusBar != null) {
747 mStatusBar.onRecentsAnimationStateChanged(false /* running */);
748 }
Winson Chunge2d72172018-01-25 17:46:20 +0000749 }
750
Adrian Roos842e7882018-03-26 17:34:06 +0200751 void scheduleFailsafe() {
752 mService.mH.postDelayed(mFailsafeRunnable, FAILSAFE_DELAY);
753 }
754
Adrian Roos653c6c12018-04-09 14:12:46 -0700755 private void linkToDeathOfRunner() throws RemoteException {
756 if (!mLinkedToDeathOfRunner) {
757 mRunner.asBinder().linkToDeath(this, 0);
758 mLinkedToDeathOfRunner = true;
759 }
760 }
761
762 private void unlinkToDeathOfRunner() {
763 if (mLinkedToDeathOfRunner) {
764 mRunner.asBinder().unlinkToDeath(this, 0);
765 mLinkedToDeathOfRunner = false;
766 }
767 }
768
Adrian Roos842e7882018-03-26 17:34:06 +0200769 @Override
770 public void binderDied() {
Winson Chungc6c3f852018-04-09 15:41:03 -0700771 cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "binderDied");
Winson Chungdb111ee2018-10-03 14:25:34 -0700772
Arthur Hung1b636fa2018-12-04 15:53:49 +0800773 synchronized (mService.getWindowManagerLock()) {
774 // Clear associated input consumers on runner death
Winson Chung7a545ae2019-07-16 14:52:13 -0700775 final InputMonitor inputMonitor = mDisplayContent.getInputMonitor();
Arthur Hung1b636fa2018-12-04 15:53:49 +0800776 inputMonitor.destroyInputConsumer(INPUT_CONSUMER_RECENTS_ANIMATION);
777 }
Adrian Roos842e7882018-03-26 17:34:06 +0200778 }
779
Winson Chunge2d72172018-01-25 17:46:20 +0000780 void checkAnimationReady(WallpaperController wallpaperController) {
781 if (mPendingStart) {
Winson Chung3e2980e2018-03-29 17:28:57 -0700782 final boolean wallpaperReady = !isTargetOverWallpaper()
Winson Chunge2d72172018-01-25 17:46:20 +0000783 || (wallpaperController.getWallpaperTarget() != null
784 && wallpaperController.wallpaperTransitionReady());
785 if (wallpaperReady) {
786 mService.getRecentsAnimationController().startAnimation();
787 }
788 }
789 }
790
791 boolean isWallpaperVisible(WindowState w) {
lumarkae078772019-11-19 02:41:00 +0800792 return w != null && w.mAttrs.type == TYPE_BASE_APPLICATION &&
793 ((w.mActivityRecord != null && mTargetActivityRecord == w.mActivityRecord)
794 || isAnimatingTask(w.getTask()))
795 && isTargetOverWallpaper();
Winson Chunge2d72172018-01-25 17:46:20 +0000796 }
797
Winson Chungdb111ee2018-10-03 14:25:34 -0700798 /**
799 * @return Whether to use the input consumer to override app input to route home/recents.
800 */
Garfield Tane8d84ab2019-10-11 09:49:40 -0700801 boolean shouldApplyInputConsumer(ActivityRecord activity) {
Winson Chungdb111ee2018-10-03 14:25:34 -0700802 // Only apply the input consumer if it is enabled, it is not the target (home/recents)
803 // being revealed with the transition, and we are actively animating the app as a part of
804 // the animation
Winson Chungdc4edb82019-12-16 16:31:04 -0800805 return mInputConsumerEnabled && !isTargetApp(activity) && isAnimatingApp(activity);
Winson Chunga89ffed2018-01-25 17:46:11 +0000806 }
807
Arthur Hung95b38a92018-07-20 18:56:12 +0800808 boolean updateInputConsumerForApp(InputWindowHandle inputWindowHandle,
Winson Chunga89ffed2018-01-25 17:46:11 +0000809 boolean hasFocus) {
Winson Chung3e2980e2018-03-29 17:28:57 -0700810 // Update the input consumer touchable region to match the target app main window
Garfield Tane8d84ab2019-10-11 09:49:40 -0700811 final WindowState targetAppMainWindow = mTargetActivityRecord != null
812 ? mTargetActivityRecord.findMainWindow()
Winson Chunga89ffed2018-01-25 17:46:11 +0000813 : null;
Winson Chung3e2980e2018-03-29 17:28:57 -0700814 if (targetAppMainWindow != null) {
815 targetAppMainWindow.getBounds(mTmpRect);
Arthur Hung95b38a92018-07-20 18:56:12 +0800816 inputWindowHandle.hasFocus = hasFocus;
817 inputWindowHandle.touchableRegion.set(mTmpRect);
Winson Chunga89ffed2018-01-25 17:46:11 +0000818 return true;
819 }
820 return false;
821 }
822
Garfield Tane8d84ab2019-10-11 09:49:40 -0700823 boolean isTargetApp(ActivityRecord activity) {
824 return mTargetActivityRecord != null && activity == mTargetActivityRecord;
Winson Chung0bb66cc2018-04-10 11:58:15 -0700825 }
826
Winson Chung3e2980e2018-03-29 17:28:57 -0700827 private boolean isTargetOverWallpaper() {
Garfield Tane8d84ab2019-10-11 09:49:40 -0700828 if (mTargetActivityRecord == null) {
Winson Chunge2d72172018-01-25 17:46:20 +0000829 return false;
830 }
Garfield Tane8d84ab2019-10-11 09:49:40 -0700831 return mTargetActivityRecord.windowsCanBeWallpaperTarget();
Winson Chunge2d72172018-01-25 17:46:20 +0000832 }
833
Winson Chungd41f71d2018-03-16 15:26:07 -0700834 boolean isAnimatingTask(Task task) {
835 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
836 if (task == mPendingAnimations.get(i).mTask) {
837 return true;
838 }
839 }
840 return false;
841 }
842
Winson Chungd5852192019-09-06 17:20:28 -0700843 boolean isAnimatingWallpaper(WallpaperWindowToken token) {
844 for (int i = mPendingWallpaperAnimations.size() - 1; i >= 0; i--) {
845 if (token == mPendingWallpaperAnimations.get(i).getToken()) {
846 return true;
847 }
848 }
849 return false;
850 }
851
Garfield Tane8d84ab2019-10-11 09:49:40 -0700852 private boolean isAnimatingApp(ActivityRecord activity) {
Winson Chunge2d72172018-01-25 17:46:20 +0000853 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
854 final Task task = mPendingAnimations.get(i).mTask;
Wale Ogunwalea38654f2019-11-17 20:37:15 -0800855 final PooledFunction f = PooledLambda.obtainFunction(
856 (a, b) -> a == b, activity,
857 PooledLambda.__(ActivityRecord.class));
858 boolean isAnimatingApp = task.forAllActivities(f);
859 f.recycle();
Winson Chungdc4edb82019-12-16 16:31:04 -0800860 if (isAnimatingApp) {
861 return true;
862 }
Winson Chunge2d72172018-01-25 17:46:20 +0000863 }
864 return false;
865 }
866
Tracy Zhoud2d3e442019-09-04 13:26:32 -0700867 boolean shouldIgnoreForAccessibility(WindowState windowState) {
868 final Task task = windowState.getTask();
Garfield Tane8d84ab2019-10-11 09:49:40 -0700869 return task != null && isAnimatingTask(task) && !isTargetApp(windowState.mActivityRecord);
Tracy Zhoud2d3e442019-09-04 13:26:32 -0700870 }
871
Vadim Caen2a9ccc92020-01-29 12:21:41 +0100872 /**
873 * If the animation target ActivityRecord has a fixed rotation ({@link
874 * WindowToken#hasFixedRotationTransform()}, the provided wallpaper will be rotated accordingly.
875 *
876 * This avoids any screen rotation animation when animating to the Recents view.
877 */
Riddle Hsu6393ad12020-03-02 23:56:32 +0800878 void linkFixedRotationTransformIfNeeded(@NonNull WindowToken wallpaper) {
Vadim Caen2a9ccc92020-01-29 12:21:41 +0100879 if (mTargetActivityRecord == null) {
880 return;
881 }
Riddle Hsu6393ad12020-03-02 23:56:32 +0800882 wallpaper.linkFixedRotationTransform(mTargetActivityRecord);
Vadim Caen2a9ccc92020-01-29 12:21:41 +0100883 }
884
Winson Chungda876c92018-04-05 18:31:06 -0700885 @VisibleForTesting
886 class TaskAnimationAdapter implements AnimationAdapter {
Winson Chunge2d72172018-01-25 17:46:20 +0000887
Vadim Tryshev593e9562018-03-08 17:15:45 -0800888 private final Task mTask;
Winson Chunge2d72172018-01-25 17:46:20 +0000889 private SurfaceControl mCapturedLeash;
890 private OnAnimationFinishedCallback mCapturedFinishCallback;
Issei Suzuki8b995df2020-01-08 12:23:04 +0100891 private @AnimationType int mLastAnimationType;
Vadim Tryshev593e9562018-03-08 17:15:45 -0800892 private final boolean mIsRecentTaskInvisible;
Jorim Jaggif75d1612018-02-27 15:05:21 +0100893 private RemoteAnimationTarget mTarget;
Winson Chungd41f71d2018-03-16 15:26:07 -0700894 private final Rect mBounds = new Rect();
lumark2ec19122020-01-23 00:09:04 +0800895 // The bounds of the target relative to its parent.
896 private Rect mLocalBounds = new Rect();
Winson Chunge2d72172018-01-25 17:46:20 +0000897
Vadim Tryshev593e9562018-03-08 17:15:45 -0800898 TaskAnimationAdapter(Task task, boolean isRecentTaskInvisible) {
Winson Chunge2d72172018-01-25 17:46:20 +0000899 mTask = task;
Vadim Tryshev593e9562018-03-08 17:15:45 -0800900 mIsRecentTaskInvisible = isRecentTaskInvisible;
Evan Rosky6ecd67c2020-04-14 11:50:43 -0700901 mBounds.set(mTask.getBounds());
lumark2ec19122020-01-23 00:09:04 +0800902
903 mLocalBounds.set(mBounds);
904 Point tmpPos = new Point();
Evan Rosky6ecd67c2020-04-14 11:50:43 -0700905 mTask.getRelativePosition(tmpPos);
lumark2ec19122020-01-23 00:09:04 +0800906 mLocalBounds.offsetTo(tmpPos.x, tmpPos.y);
Winson Chunge2d72172018-01-25 17:46:20 +0000907 }
908
Winson Chungd5852192019-09-06 17:20:28 -0700909 RemoteAnimationTarget createRemoteAnimationTarget() {
Garfield Tane8d84ab2019-10-11 09:49:40 -0700910 final ActivityRecord topApp = mTask.getTopVisibleActivity();
Winson Chung173020c2018-05-04 15:36:47 -0700911 final WindowState mainWindow = topApp != null
912 ? topApp.findMainWindow()
913 : null;
Winson Chung2dc37362018-03-12 17:57:06 -0700914 if (mainWindow == null) {
915 return null;
916 }
chaviw9c81e632018-07-31 11:17:52 -0700917 final Rect insets = new Rect();
918 mainWindow.getContentInsets(insets);
Garfield Tane8d84ab2019-10-11 09:49:40 -0700919 InsetUtils.addInsets(insets, mainWindow.mActivityRecord.getLetterboxInsets());
Winson Chung732446a2018-09-19 13:15:17 -0700920 final int mode = topApp.getActivityType() == mTargetActivityType
921 ? MODE_OPENING
922 : MODE_CLOSING;
923 mTarget = new RemoteAnimationTarget(mTask.mTaskId, mode, mCapturedLeash,
Winson Chung173020c2018-05-04 15:36:47 -0700924 !topApp.fillsParent(), mainWindow.mWinAnimator.mLastClipRect,
lumark2ec19122020-01-23 00:09:04 +0800925 insets, mTask.getPrefixOrderIndex(), new Point(mBounds.left, mBounds.top),
926 mLocalBounds, mBounds, mTask.getWindowConfiguration(),
927 mIsRecentTaskInvisible, null, null);
Jorim Jaggif75d1612018-02-27 15:05:21 +0100928 return mTarget;
Winson Chunge2d72172018-01-25 17:46:20 +0000929 }
930
931 @Override
Jorim Jaggi82c17862018-02-21 17:50:18 +0100932 public boolean getShowWallpaper() {
933 return false;
934 }
935
936 @Override
Winson Chunge2d72172018-01-25 17:46:20 +0000937 public void startAnimation(SurfaceControl animationLeash, Transaction t,
Issei Suzuki8b995df2020-01-08 12:23:04 +0100938 @AnimationType int type, OnAnimationFinishedCallback finishCallback) {
Winson Chung65a05862018-04-12 17:14:50 -0700939 // Restore z-layering, position and stack crop until client has a chance to modify it.
940 t.setLayer(animationLeash, mTask.getPrefixOrderIndex());
lumark2ec19122020-01-23 00:09:04 +0800941 t.setPosition(animationLeash, mLocalBounds.left, mLocalBounds.top);
942 mTmpRect.set(mLocalBounds);
Winson Chung65a05862018-04-12 17:14:50 -0700943 mTmpRect.offsetTo(0, 0);
944 t.setWindowCrop(animationLeash, mTmpRect);
Winson Chunge2d72172018-01-25 17:46:20 +0000945 mCapturedLeash = animationLeash;
946 mCapturedFinishCallback = finishCallback;
Issei Suzuki8b995df2020-01-08 12:23:04 +0100947 mLastAnimationType = type;
Winson Chunge2d72172018-01-25 17:46:20 +0000948 }
949
950 @Override
951 public void onAnimationCancelled(SurfaceControl animationLeash) {
Winson Chungd5852192019-09-06 17:20:28 -0700952 // Cancel the animation immediately if any single task animator is canceled
Winson Chungc6c3f852018-04-09 15:41:03 -0700953 cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "taskAnimationAdapterCanceled");
Winson Chunge2d72172018-01-25 17:46:20 +0000954 }
955
956 @Override
957 public long getDurationHint() {
958 return 0;
959 }
960
961 @Override
962 public long getStatusBarTransitionsStartTime() {
963 return SystemClock.uptimeMillis();
964 }
Jorim Jaggif75d1612018-02-27 15:05:21 +0100965
966 @Override
967 public void dump(PrintWriter pw, String prefix) {
968 pw.print(prefix); pw.println("task=" + mTask);
969 if (mTarget != null) {
970 pw.print(prefix); pw.println("Target:");
971 mTarget.dump(pw, prefix + " ");
972 } else {
973 pw.print(prefix); pw.println("Target: null");
974 }
Winson Chungc6c3f852018-04-09 15:41:03 -0700975 pw.println("mIsRecentTaskInvisible=" + mIsRecentTaskInvisible);
lumark2ec19122020-01-23 00:09:04 +0800976 pw.println("mLocalBounds=" + mLocalBounds);
Winson Chungc6c3f852018-04-09 15:41:03 -0700977 pw.println("mBounds=" + mBounds);
978 pw.println("mIsRecentTaskInvisible=" + mIsRecentTaskInvisible);
Jorim Jaggif75d1612018-02-27 15:05:21 +0100979 }
980
981 @Override
Jeffrey Huangcb782852019-12-05 11:28:11 -0800982 public void dumpDebug(ProtoOutputStream proto) {
Jorim Jaggif75d1612018-02-27 15:05:21 +0100983 final long token = proto.start(REMOTE);
984 if (mTarget != null) {
Jeffrey Huangcb782852019-12-05 11:28:11 -0800985 mTarget.dumpDebug(proto, TARGET);
Jorim Jaggif75d1612018-02-27 15:05:21 +0100986 }
987 proto.end(token);
988 }
Winson Chunge2d72172018-01-25 17:46:20 +0000989 }
990
991 public void dump(PrintWriter pw, String prefix) {
992 final String innerPrefix = prefix + " ";
993 pw.print(prefix); pw.println(RecentsAnimationController.class.getSimpleName() + ":");
994 pw.print(innerPrefix); pw.println("mPendingStart=" + mPendingStart);
Winson Chungdb111ee2018-10-03 14:25:34 -0700995 pw.print(innerPrefix); pw.println("mPendingAnimations=" + mPendingAnimations.size());
Winson Chungc6c3f852018-04-09 15:41:03 -0700996 pw.print(innerPrefix); pw.println("mCanceled=" + mCanceled);
997 pw.print(innerPrefix); pw.println("mInputConsumerEnabled=" + mInputConsumerEnabled);
Garfield Tane8d84ab2019-10-11 09:49:40 -0700998 pw.print(innerPrefix); pw.println("mTargetActivityRecord=" + mTargetActivityRecord);
Winson Chungc6c3f852018-04-09 15:41:03 -0700999 pw.print(innerPrefix); pw.println("isTargetOverWallpaper=" + isTargetOverWallpaper());
Winson Chung7a545ae2019-07-16 14:52:13 -07001000 pw.print(innerPrefix); pw.println("mRequestDeferCancelUntilNextTransition="
1001 + mRequestDeferCancelUntilNextTransition);
1002 pw.print(innerPrefix); pw.println("mCancelOnNextTransitionStart="
1003 + mCancelOnNextTransitionStart);
1004 pw.print(innerPrefix); pw.println("mCancelDeferredWithScreenshot="
1005 + mCancelDeferredWithScreenshot);
Winson Chunge2d72172018-01-25 17:46:20 +00001006 }
1007}