blob: 85e4ac7fe4ce2d6e2bf22b84efb3333f2703e4f1 [file] [log] [blame]
Winson Chunge2d72172018-01-25 17:46:20 +00001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
17package com.android.server.wm;
18
Jorim Jaggi54cff642018-03-15 15:51:32 +010019import static android.app.ActivityManagerInternal.APP_TRANSITION_RECENTS_ANIM;
Jorim Jaggi54cff642018-03-15 15:51:32 +010020import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
Winson Chunge2d72172018-01-25 17:46:20 +000021import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
Winson Chung3e2980e2018-03-29 17:28:57 -070022import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
Winson Chunge2d72172018-01-25 17:46:20 +000023import static android.view.RemoteAnimationTarget.MODE_CLOSING;
Winson Chunga89ffed2018-01-25 17:46:11 +000024import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION;
Winson Chunge2d72172018-01-25 17:46:20 +000025import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
Yi Jin6c6e9ca2018-03-20 16:53:35 -070026import static com.android.server.wm.AnimationAdapterProto.REMOTE;
Winson Chungc6c3f852018-04-09 15:41:03 -070027import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET;
28import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RECENTS_ANIMATIONS;
29import static com.android.server.wm.WindowManagerService.H.NOTIFY_APP_TRANSITION_STARTING;
Winson Chunge2d72172018-01-25 17:46:20 +000030
Winson Chung6a38fca2018-03-28 17:57:09 -070031import android.annotation.IntDef;
Winson Chunge2d72172018-01-25 17:46:20 +000032import android.app.ActivityManager.TaskSnapshot;
33import android.app.WindowConfiguration;
Winson Chunge2d72172018-01-25 17:46:20 +000034import android.graphics.Point;
35import android.graphics.Rect;
36import android.os.Binder;
Adrian Roos842e7882018-03-26 17:34:06 +020037import android.os.IBinder.DeathRecipient;
Winson Chunge2d72172018-01-25 17:46:20 +000038import android.os.RemoteException;
39import android.os.SystemClock;
Winson Chung23aa7b12018-02-01 11:41:43 -080040import android.util.ArraySet;
Winson Chungc6c3f852018-04-09 15:41:03 -070041import android.util.Slog;
Vadim Tryshev593e9562018-03-08 17:15:45 -080042import android.util.SparseBooleanArray;
Jorim Jaggi54cff642018-03-15 15:51:32 +010043import android.util.SparseIntArray;
Winson Chungc6c3f852018-04-09 15:41:03 -070044import android.util.proto.ProtoOutputStream;
Winson Chunge2d72172018-01-25 17:46:20 +000045import android.view.IRecentsAnimationController;
46import android.view.IRecentsAnimationRunner;
47import android.view.RemoteAnimationTarget;
48import android.view.SurfaceControl;
49import android.view.SurfaceControl.Transaction;
Winson Chunga840c322018-04-20 15:58:18 -070050import android.view.inputmethod.InputMethodManagerInternal;
Winson Chungda876c92018-04-05 18:31:06 -070051import com.android.internal.annotations.VisibleForTesting;
Winson Chunga840c322018-04-20 15:58:18 -070052import com.android.server.LocalServices;
Jorim Jaggif75d1612018-02-27 15:05:21 +010053import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
Jorim Jaggi817ebdd2018-03-26 15:46:01 +020054import com.android.server.wm.utils.InsetUtils;
Winson Chungc6c3f852018-04-09 15:41:03 -070055import com.google.android.collect.Sets;
Winson Chunge2d72172018-01-25 17:46:20 +000056import java.io.PrintWriter;
57import java.util.ArrayList;
Winson Chungc6c3f852018-04-09 15:41:03 -070058
Winson Chunge2d72172018-01-25 17:46:20 +000059/**
60 * Controls a single instance of the remote driven recents animation. In particular, this allows
61 * the calling SystemUI to animate the visible task windows as a part of the transition. The remote
62 * runner is provided an animation controller which allows it to take screenshots and to notify
63 * window manager when the animation is completed. In addition, window manager may also notify the
64 * app if it requires the animation to be canceled at any time (ie. due to timeout, etc.)
65 */
Adrian Roos842e7882018-03-26 17:34:06 +020066public class RecentsAnimationController implements DeathRecipient {
Winson Chungc6c3f852018-04-09 15:41:03 -070067 private static final String TAG = RecentsAnimationController.class.getSimpleName();
Adrian Roos842e7882018-03-26 17:34:06 +020068 private static final long FAILSAFE_DELAY = 1000;
Winson Chunge2d72172018-01-25 17:46:20 +000069
Winson Chung3e2980e2018-03-29 17:28:57 -070070 public static final int REORDER_KEEP_IN_PLACE = 0;
71 public static final int REORDER_MOVE_TO_TOP = 1;
72 public static final int REORDER_MOVE_TO_ORIGINAL_POSITION = 2;
Winson Chung6a38fca2018-03-28 17:57:09 -070073
74 @IntDef(prefix = { "REORDER_MODE_" }, value = {
Winson Chung3e2980e2018-03-29 17:28:57 -070075 REORDER_KEEP_IN_PLACE,
76 REORDER_MOVE_TO_TOP,
77 REORDER_MOVE_TO_ORIGINAL_POSITION
Winson Chung6a38fca2018-03-28 17:57:09 -070078 })
79 public @interface ReorderMode {}
80
Winson Chunge2d72172018-01-25 17:46:20 +000081 private final WindowManagerService mService;
82 private final IRecentsAnimationRunner mRunner;
83 private final RecentsAnimationCallbacks mCallbacks;
84 private final ArrayList<TaskAnimationAdapter> mPendingAnimations = new ArrayList<>();
Winson Chungddf62972018-02-12 11:10:04 -080085 private final int mDisplayId;
Winson Chung65c5f992018-04-20 14:58:57 -070086 private final Runnable mFailsafeRunnable = () ->
87 cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "failSafeRunnable");
Winson Chunge2d72172018-01-25 17:46:20 +000088
89 // The recents component app token that is shown behind the visibile tasks
Winson Chung3e2980e2018-03-29 17:28:57 -070090 private AppWindowToken mTargetAppToken;
Winson Chung584d6522018-02-07 23:57:38 +000091 private Rect mMinimizedHomeBounds = new Rect();
Winson Chunge2d72172018-01-25 17:46:20 +000092
93 // We start the RecentsAnimationController in a pending-start state since we need to wait for
94 // the wallpaper/activity to draw before we can give control to the handler to start animating
95 // the visible task surfaces
96 private boolean mPendingStart = true;
97
98 // Set when the animation has been canceled
Winson Chungf557c3b2018-03-16 10:55:20 -070099 private boolean mCanceled;
Winson Chunge2d72172018-01-25 17:46:20 +0000100
101 // Whether or not the input consumer is enabled. The input consumer must be both registered and
102 // enabled for it to start intercepting touch events.
103 private boolean mInputConsumerEnabled;
104
Winson Chungf557c3b2018-03-16 10:55:20 -0700105 // Whether or not the recents animation should cause the primary split-screen stack to be
106 // minimized
107 private boolean mSplitScreenMinimized;
108
Adrian Roos653c6c12018-04-09 14:12:46 -0700109 private final Rect mTmpRect = new Rect();
110
111 private boolean mLinkedToDeathOfRunner;
Winson Chunga89ffed2018-01-25 17:46:11 +0000112
Winson Chunge2d72172018-01-25 17:46:20 +0000113 public interface RecentsAnimationCallbacks {
Winson Chung65c5f992018-04-20 14:58:57 -0700114 void onAnimationFinished(@ReorderMode int reorderMode, boolean runSychronously);
Winson Chunge2d72172018-01-25 17:46:20 +0000115 }
116
117 private final IRecentsAnimationController mController =
118 new IRecentsAnimationController.Stub() {
119
120 @Override
121 public TaskSnapshot screenshotTask(int taskId) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700122 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "screenshotTask(" + taskId + "):"
123 + " mCanceled=" + mCanceled);
Winson Chungf557c3b2018-03-16 10:55:20 -0700124 final long token = Binder.clearCallingIdentity();
Winson Chunge2d72172018-01-25 17:46:20 +0000125 try {
126 synchronized (mService.getWindowManagerLock()) {
127 if (mCanceled) {
128 return null;
129 }
130 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
131 final TaskAnimationAdapter adapter = mPendingAnimations.get(i);
132 final Task task = adapter.mTask;
133 if (task.mTaskId == taskId) {
Winson Chung23aa7b12018-02-01 11:41:43 -0800134 final TaskSnapshotController snapshotController =
135 mService.mTaskSnapshotController;
136 final ArraySet<Task> tasks = Sets.newArraySet(task);
137 snapshotController.snapshotTasks(tasks);
138 snapshotController.addSkipClosingAppSnapshotTasks(tasks);
139 return snapshotController.getSnapshot(taskId, 0 /* userId */,
140 false /* restoreFromDisk */, false /* reducedResolution */);
Winson Chunge2d72172018-01-25 17:46:20 +0000141 }
142 }
143 return null;
144 }
145 } finally {
146 Binder.restoreCallingIdentity(token);
147 }
148 }
149
150 @Override
151 public void finish(boolean moveHomeToTop) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700152 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "finish(" + moveHomeToTop + "):"
153 + " mCanceled=" + mCanceled);
Winson Chungf557c3b2018-03-16 10:55:20 -0700154 final long token = Binder.clearCallingIdentity();
Winson Chunge2d72172018-01-25 17:46:20 +0000155 try {
156 synchronized (mService.getWindowManagerLock()) {
157 if (mCanceled) {
158 return;
159 }
160 }
161
162 // Note, the callback will handle its own synchronization, do not lock on WM lock
163 // prior to calling the callback
Winson Chung6a38fca2018-03-28 17:57:09 -0700164 mCallbacks.onAnimationFinished(moveHomeToTop
Winson Chung3e2980e2018-03-29 17:28:57 -0700165 ? REORDER_MOVE_TO_TOP
Winson Chung65c5f992018-04-20 14:58:57 -0700166 : REORDER_MOVE_TO_ORIGINAL_POSITION,
167 true /* runSynchronously */);
Winson Chunge2d72172018-01-25 17:46:20 +0000168 } finally {
169 Binder.restoreCallingIdentity(token);
170 }
171 }
172
173 @Override
Jorim Jaggi50bf59c2018-03-09 17:29:48 +0100174 public void setAnimationTargetsBehindSystemBars(boolean behindSystemBars)
175 throws RemoteException {
Winson Chungf557c3b2018-03-16 10:55:20 -0700176 final long token = Binder.clearCallingIdentity();
Jorim Jaggi50bf59c2018-03-09 17:29:48 +0100177 try {
178 synchronized (mService.getWindowManagerLock()) {
179 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
180 mPendingAnimations.get(i).mTask.setCanAffectSystemUiFlags(behindSystemBars);
181 }
182 mService.mWindowPlacerLocked.requestTraversal();
183 }
184 } finally {
185 Binder.restoreCallingIdentity(token);
186 }
187 }
188
189 @Override
Winson Chunge2d72172018-01-25 17:46:20 +0000190 public void setInputConsumerEnabled(boolean enabled) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700191 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "setInputConsumerEnabled(" + enabled + "):"
192 + " mCanceled=" + mCanceled);
Winson Chungf557c3b2018-03-16 10:55:20 -0700193 final long token = Binder.clearCallingIdentity();
Winson Chunge2d72172018-01-25 17:46:20 +0000194 try {
195 synchronized (mService.getWindowManagerLock()) {
196 if (mCanceled) {
197 return;
198 }
199
200 mInputConsumerEnabled = enabled;
201 mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
202 mService.scheduleAnimationLocked();
203 }
204 } finally {
205 Binder.restoreCallingIdentity(token);
206 }
207 }
Winson Chungf557c3b2018-03-16 10:55:20 -0700208
209 @Override
210 public void setSplitScreenMinimized(boolean minimized) {
211 final long token = Binder.clearCallingIdentity();
212 try {
213 synchronized (mService.getWindowManagerLock()) {
214 if (mCanceled) {
215 return;
216 }
217
218 mSplitScreenMinimized = minimized;
219 mService.checkSplitScreenMinimizedChanged(true /* animate */);
220 }
221 } finally {
222 Binder.restoreCallingIdentity(token);
223 }
224 }
Winson Chunga840c322018-04-20 15:58:18 -0700225
226 @Override
227 public void hideCurrentInputMethod() {
228 final long token = Binder.clearCallingIdentity();
229 try {
230 final InputMethodManagerInternal inputMethodManagerInternal =
231 LocalServices.getService(InputMethodManagerInternal.class);
232 if (inputMethodManagerInternal != null) {
233 inputMethodManagerInternal.hideCurrentInputMethod();
234 }
235 } finally {
236 Binder.restoreCallingIdentity(token);
237 }
238 }
Winson Chunge2d72172018-01-25 17:46:20 +0000239 };
240
241 /**
Winson Chunge2d72172018-01-25 17:46:20 +0000242 * @param remoteAnimationRunner The remote runner which should be notified when the animation is
243 * ready to start or has been canceled
244 * @param callbacks Callbacks to be made when the animation finishes
Winson Chunge2d72172018-01-25 17:46:20 +0000245 */
246 RecentsAnimationController(WindowManagerService service,
247 IRecentsAnimationRunner remoteAnimationRunner, RecentsAnimationCallbacks callbacks,
248 int displayId) {
249 mService = service;
250 mRunner = remoteAnimationRunner;
251 mCallbacks = callbacks;
Winson Chungddf62972018-02-12 11:10:04 -0800252 mDisplayId = displayId;
253 }
Winson Chunge2d72172018-01-25 17:46:20 +0000254
Winson Chungddf62972018-02-12 11:10:04 -0800255 /**
256 * Initializes the recents animation controller. This is a separate call from the constructor
257 * because it may call cancelAnimation() which needs to properly clean up the controller
258 * in the window manager.
259 */
Winson Chung3e2980e2018-03-29 17:28:57 -0700260 public void initialize(int targetActivityType, SparseBooleanArray recentTaskIds) {
Winson Chunge2d72172018-01-25 17:46:20 +0000261 // Make leashes for each of the visible tasks and add it to the recents animation to be
262 // started
Winson Chungddf62972018-02-12 11:10:04 -0800263 final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId);
264 final ArrayList<Task> visibleTasks = dc.getVisibleTasks();
Winson Chunge2d72172018-01-25 17:46:20 +0000265 final int taskCount = visibleTasks.size();
266 for (int i = 0; i < taskCount; i++) {
267 final Task task = visibleTasks.get(i);
268 final WindowConfiguration config = task.getWindowConfiguration();
269 if (config.tasksAreFloating()
270 || config.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
Winson Chung3e2980e2018-03-29 17:28:57 -0700271 || config.getActivityType() == targetActivityType) {
Winson Chunge2d72172018-01-25 17:46:20 +0000272 continue;
273 }
Vadim Tryshev593e9562018-03-08 17:15:45 -0800274 addAnimation(task, !recentTaskIds.get(task.mTaskId));
Winson Chunge2d72172018-01-25 17:46:20 +0000275 }
276
Winson Chungddf62972018-02-12 11:10:04 -0800277 // Skip the animation if there is nothing to animate
278 if (mPendingAnimations.isEmpty()) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700279 cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "initialize-noVisibleTasks");
Winson Chungddf62972018-02-12 11:10:04 -0800280 return;
281 }
282
Adrian Roos842e7882018-03-26 17:34:06 +0200283 try {
Adrian Roos653c6c12018-04-09 14:12:46 -0700284 linkToDeathOfRunner();
Adrian Roos842e7882018-03-26 17:34:06 +0200285 } catch (RemoteException e) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700286 cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "initialize-failedToLinkToDeath");
Adrian Roos842e7882018-03-26 17:34:06 +0200287 return;
288 }
289
Winson Chung3e2980e2018-03-29 17:28:57 -0700290 // Adjust the wallpaper visibility for the showing target activity
291 final AppWindowToken recentsComponentAppToken = dc.getStack(WINDOWING_MODE_UNDEFINED,
292 targetActivityType).getTopChild().getTopFullscreenAppToken();
Winson Chunge2d72172018-01-25 17:46:20 +0000293 if (recentsComponentAppToken != null) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700294 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "setHomeApp("
295 + recentsComponentAppToken.getName() + ")");
Winson Chung3e2980e2018-03-29 17:28:57 -0700296 mTargetAppToken = recentsComponentAppToken;
Winson Chunge2d72172018-01-25 17:46:20 +0000297 if (recentsComponentAppToken.windowsCanBeWallpaperTarget()) {
298 dc.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
299 dc.setLayoutNeeded();
300 }
301 }
302
Winson Chung584d6522018-02-07 23:57:38 +0000303 // Save the minimized home height
304 dc.getDockedDividerController().getHomeStackBoundsInDockedMode(mMinimizedHomeBounds);
305
Winson Chunge2d72172018-01-25 17:46:20 +0000306 mService.mWindowPlacerLocked.performSurfacePlacement();
307 }
308
Winson Chungda876c92018-04-05 18:31:06 -0700309 @VisibleForTesting
310 AnimationAdapter addAnimation(Task task, boolean isRecentTaskInvisible) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700311 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "addAnimation(" + task.getName() + ")");
Winson Chungda876c92018-04-05 18:31:06 -0700312 // TODO: Refactor this to use the task's animator
Winson Chunge2d72172018-01-25 17:46:20 +0000313 final SurfaceAnimator anim = new SurfaceAnimator(task, null /* animationFinishedCallback */,
Chavi Weingartenb736e322018-02-23 00:27:54 +0000314 mService);
Vadim Tryshev593e9562018-03-08 17:15:45 -0800315 final TaskAnimationAdapter taskAdapter = new TaskAnimationAdapter(task,
316 isRecentTaskInvisible);
Winson Chunge2d72172018-01-25 17:46:20 +0000317 anim.startAnimation(task.getPendingTransaction(), taskAdapter, false /* hidden */);
318 task.commitPendingTransaction();
319 mPendingAnimations.add(taskAdapter);
Winson Chungda876c92018-04-05 18:31:06 -0700320 return taskAdapter;
321 }
322
323 @VisibleForTesting
324 void removeAnimation(TaskAnimationAdapter taskAdapter) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700325 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "removeAnimation("
326 + taskAdapter.mTask.mTaskId + ")");
Winson Chungda876c92018-04-05 18:31:06 -0700327 taskAdapter.mTask.setCanAffectSystemUiFlags(true);
328 taskAdapter.mCapturedFinishCallback.onAnimationFinished(taskAdapter);
329 mPendingAnimations.remove(taskAdapter);
Winson Chunge2d72172018-01-25 17:46:20 +0000330 }
331
332 void startAnimation() {
Winson Chungc6c3f852018-04-09 15:41:03 -0700333 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "startAnimation(): mPendingStart=" + mPendingStart
Winson Chungddf62972018-02-12 11:10:04 -0800334 + " mCanceled=" + mCanceled);
335 if (!mPendingStart || mCanceled) {
336 // Skip starting if we've already started or canceled the animation
Winson Chunge2d72172018-01-25 17:46:20 +0000337 return;
338 }
339 try {
Winson Chung2dc37362018-03-12 17:57:06 -0700340 final ArrayList<RemoteAnimationTarget> appAnimations = new ArrayList<>();
Winson Chunge2d72172018-01-25 17:46:20 +0000341 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
Winson Chungda876c92018-04-05 18:31:06 -0700342 final TaskAnimationAdapter taskAdapter = mPendingAnimations.get(i);
343 final RemoteAnimationTarget target = taskAdapter.createRemoteAnimationApp();
Winson Chung2dc37362018-03-12 17:57:06 -0700344 if (target != null) {
345 appAnimations.add(target);
Winson Chungda876c92018-04-05 18:31:06 -0700346 } else {
347 removeAnimation(taskAdapter);
Winson Chung2dc37362018-03-12 17:57:06 -0700348 }
Winson Chunge2d72172018-01-25 17:46:20 +0000349 }
Winson Chungda876c92018-04-05 18:31:06 -0700350
351 // Skip the animation if there is nothing to animate
352 if (appAnimations.isEmpty()) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700353 cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "startAnimation-noAppWindows");
Winson Chungda876c92018-04-05 18:31:06 -0700354 return;
355 }
356
Winson Chung2dc37362018-03-12 17:57:06 -0700357 final RemoteAnimationTarget[] appTargets = appAnimations.toArray(
358 new RemoteAnimationTarget[appAnimations.size()]);
Winson Chunge2d72172018-01-25 17:46:20 +0000359 mPendingStart = false;
Winson Chung584d6522018-02-07 23:57:38 +0000360
Winson Chung3e2980e2018-03-29 17:28:57 -0700361 final Rect minimizedHomeBounds = mTargetAppToken != null
362 && mTargetAppToken.inSplitScreenSecondaryWindowingMode()
363 ? mMinimizedHomeBounds
364 : null;
365 final Rect contentInsets = mTargetAppToken != null
366 && mTargetAppToken.findMainWindow() != null
367 ? mTargetAppToken.findMainWindow().mContentInsets
368 : null;
Winson Chung2dc37362018-03-12 17:57:06 -0700369 mRunner.onAnimationStart_New(mController, appTargets, contentInsets,
Winson Chung584d6522018-02-07 23:57:38 +0000370 minimizedHomeBounds);
Winson Chungc6c3f852018-04-09 15:41:03 -0700371 if (DEBUG_RECENTS_ANIMATIONS) {
372 Slog.d(TAG, "startAnimation(): Notify animation start:");
373 for (int i = 0; i < mPendingAnimations.size(); i++) {
374 final Task task = mPendingAnimations.get(i).mTask;
375 Slog.d(TAG, "\t" + task.mTaskId);
376 }
377 }
Winson Chunge2d72172018-01-25 17:46:20 +0000378 } catch (RemoteException e) {
379 Slog.e(TAG, "Failed to start recents animation", e);
380 }
Jorim Jaggi54cff642018-03-15 15:51:32 +0100381 final SparseIntArray reasons = new SparseIntArray();
382 reasons.put(WINDOWING_MODE_FULLSCREEN, APP_TRANSITION_RECENTS_ANIM);
383 mService.mH.obtainMessage(NOTIFY_APP_TRANSITION_STARTING,
384 reasons).sendToTarget();
Winson Chunge2d72172018-01-25 17:46:20 +0000385 }
386
Winson Chungc6c3f852018-04-09 15:41:03 -0700387 void cancelAnimation(@ReorderMode int reorderMode, String reason) {
Winson Chung65c5f992018-04-20 14:58:57 -0700388 cancelAnimation(reorderMode, false /* runSynchronously */, reason);
389 }
390
391 void cancelAnimationSynchronously(@ReorderMode int reorderMode, String reason) {
392 cancelAnimation(reorderMode, true /* runSynchronously */, reason);
393 }
394
395 private void cancelAnimation(@ReorderMode int reorderMode, boolean runSynchronously,
396 String reason) {
397 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "cancelAnimation(): reason=" + reason
398 + " runSynchronously=" + runSynchronously);
Winson Chung65fc89a2018-02-28 08:32:12 -0800399 synchronized (mService.getWindowManagerLock()) {
400 if (mCanceled) {
401 // We've already canceled the animation
402 return;
403 }
Adrian Roos842e7882018-03-26 17:34:06 +0200404 mService.mH.removeCallbacks(mFailsafeRunnable);
Winson Chung65fc89a2018-02-28 08:32:12 -0800405 mCanceled = true;
406 try {
407 mRunner.onAnimationCanceled();
408 } catch (RemoteException e) {
409 Slog.e(TAG, "Failed to cancel recents animation", e);
410 }
Winson Chunge2d72172018-01-25 17:46:20 +0000411 }
Winson Chungf557c3b2018-03-16 10:55:20 -0700412
Winson Chunge2d72172018-01-25 17:46:20 +0000413 // Clean up and return to the previous app
Winson Chung65c5f992018-04-20 14:58:57 -0700414 mCallbacks.onAnimationFinished(reorderMode, runSynchronously);
Winson Chunge2d72172018-01-25 17:46:20 +0000415 }
416
Winson Chung6a38fca2018-03-28 17:57:09 -0700417 void cleanupAnimation(@ReorderMode int reorderMode) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700418 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG,
419 "cleanupAnimation(): Notify animation finished mPendingAnimations="
420 + mPendingAnimations.size() + " reorderMode=" + reorderMode);
Winson Chunge2d72172018-01-25 17:46:20 +0000421 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
Winson Chungda876c92018-04-05 18:31:06 -0700422 final TaskAnimationAdapter taskAdapter = mPendingAnimations.get(i);
Winson Chung3e2980e2018-03-29 17:28:57 -0700423 if (reorderMode == REORDER_MOVE_TO_TOP || reorderMode == REORDER_KEEP_IN_PLACE) {
Winson Chungda876c92018-04-05 18:31:06 -0700424 taskAdapter.mTask.dontAnimateDimExit();
chaviw87ca63a2018-03-26 14:06:17 -0700425 }
Winson Chungda876c92018-04-05 18:31:06 -0700426 removeAnimation(taskAdapter);
Winson Chunge2d72172018-01-25 17:46:20 +0000427 }
Winson Chunge2d72172018-01-25 17:46:20 +0000428
Adrian Roos653c6c12018-04-09 14:12:46 -0700429 unlinkToDeathOfRunner();
Winson Chungf557c3b2018-03-16 10:55:20 -0700430 // Clear associated input consumers
Winson Chunge2d72172018-01-25 17:46:20 +0000431 mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
Winson Chunga89ffed2018-01-25 17:46:11 +0000432 mService.destroyInputConsumer(INPUT_CONSUMER_RECENTS_ANIMATION);
Winson Chung0bb66cc2018-04-10 11:58:15 -0700433
434 // We have deferred all notifications to the target app as a part of the recents animation,
435 // so if we are actually transitioning there, notify again here
436 if (mTargetAppToken != null) {
437 if (reorderMode == REORDER_MOVE_TO_TOP || reorderMode == REORDER_KEEP_IN_PLACE) {
438 mService.mAppTransition.notifyAppTransitionFinishedLocked(mTargetAppToken.token);
439 }
440 }
Winson Chunge2d72172018-01-25 17:46:20 +0000441 }
442
Adrian Roos842e7882018-03-26 17:34:06 +0200443 void scheduleFailsafe() {
444 mService.mH.postDelayed(mFailsafeRunnable, FAILSAFE_DELAY);
445 }
446
Adrian Roos653c6c12018-04-09 14:12:46 -0700447 private void linkToDeathOfRunner() throws RemoteException {
448 if (!mLinkedToDeathOfRunner) {
449 mRunner.asBinder().linkToDeath(this, 0);
450 mLinkedToDeathOfRunner = true;
451 }
452 }
453
454 private void unlinkToDeathOfRunner() {
455 if (mLinkedToDeathOfRunner) {
456 mRunner.asBinder().unlinkToDeath(this, 0);
457 mLinkedToDeathOfRunner = false;
458 }
459 }
460
Adrian Roos842e7882018-03-26 17:34:06 +0200461 @Override
462 public void binderDied() {
Winson Chungc6c3f852018-04-09 15:41:03 -0700463 cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "binderDied");
Adrian Roos842e7882018-03-26 17:34:06 +0200464 }
465
Winson Chunge2d72172018-01-25 17:46:20 +0000466 void checkAnimationReady(WallpaperController wallpaperController) {
467 if (mPendingStart) {
Winson Chung3e2980e2018-03-29 17:28:57 -0700468 final boolean wallpaperReady = !isTargetOverWallpaper()
Winson Chunge2d72172018-01-25 17:46:20 +0000469 || (wallpaperController.getWallpaperTarget() != null
470 && wallpaperController.wallpaperTransitionReady());
471 if (wallpaperReady) {
472 mService.getRecentsAnimationController().startAnimation();
473 }
474 }
475 }
476
Winson Chungf557c3b2018-03-16 10:55:20 -0700477 boolean isSplitScreenMinimized() {
478 return mSplitScreenMinimized;
479 }
480
Winson Chunge2d72172018-01-25 17:46:20 +0000481 boolean isWallpaperVisible(WindowState w) {
Winson Chung3e2980e2018-03-29 17:28:57 -0700482 return w != null && w.mAppToken != null && mTargetAppToken == w.mAppToken
483 && isTargetOverWallpaper();
Winson Chunge2d72172018-01-25 17:46:20 +0000484 }
485
Winson Chunga89ffed2018-01-25 17:46:11 +0000486 boolean hasInputConsumerForApp(AppWindowToken appToken) {
487 return mInputConsumerEnabled && isAnimatingApp(appToken);
488 }
489
490 boolean updateInputConsumerForApp(InputConsumerImpl recentsAnimationInputConsumer,
491 boolean hasFocus) {
Winson Chung3e2980e2018-03-29 17:28:57 -0700492 // Update the input consumer touchable region to match the target app main window
493 final WindowState targetAppMainWindow = mTargetAppToken != null
494 ? mTargetAppToken.findMainWindow()
Winson Chunga89ffed2018-01-25 17:46:11 +0000495 : null;
Winson Chung3e2980e2018-03-29 17:28:57 -0700496 if (targetAppMainWindow != null) {
497 targetAppMainWindow.getBounds(mTmpRect);
Winson Chunga89ffed2018-01-25 17:46:11 +0000498 recentsAnimationInputConsumer.mWindowHandle.hasFocus = hasFocus;
499 recentsAnimationInputConsumer.mWindowHandle.touchableRegion.set(mTmpRect);
500 return true;
501 }
502 return false;
503 }
504
Winson Chung0bb66cc2018-04-10 11:58:15 -0700505 boolean isTargetApp(AppWindowToken token) {
506 return mTargetAppToken != null && token == mTargetAppToken;
507 }
508
Winson Chung3e2980e2018-03-29 17:28:57 -0700509 private boolean isTargetOverWallpaper() {
510 if (mTargetAppToken == null) {
Winson Chunge2d72172018-01-25 17:46:20 +0000511 return false;
512 }
Winson Chung3e2980e2018-03-29 17:28:57 -0700513 return mTargetAppToken.windowsCanBeWallpaperTarget();
Winson Chunge2d72172018-01-25 17:46:20 +0000514 }
515
Winson Chungd41f71d2018-03-16 15:26:07 -0700516 boolean isAnimatingTask(Task task) {
517 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
518 if (task == mPendingAnimations.get(i).mTask) {
519 return true;
520 }
521 }
522 return false;
523 }
524
Winson Chunga89ffed2018-01-25 17:46:11 +0000525 private boolean isAnimatingApp(AppWindowToken appToken) {
Winson Chunge2d72172018-01-25 17:46:20 +0000526 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
527 final Task task = mPendingAnimations.get(i).mTask;
528 for (int j = task.getChildCount() - 1; j >= 0; j--) {
529 final AppWindowToken app = task.getChildAt(j);
530 if (app == appToken) {
531 return true;
532 }
533 }
534 }
535 return false;
536 }
537
Winson Chungda876c92018-04-05 18:31:06 -0700538 @VisibleForTesting
539 class TaskAnimationAdapter implements AnimationAdapter {
Winson Chunge2d72172018-01-25 17:46:20 +0000540
Vadim Tryshev593e9562018-03-08 17:15:45 -0800541 private final Task mTask;
Winson Chunge2d72172018-01-25 17:46:20 +0000542 private SurfaceControl mCapturedLeash;
543 private OnAnimationFinishedCallback mCapturedFinishCallback;
Vadim Tryshev593e9562018-03-08 17:15:45 -0800544 private final boolean mIsRecentTaskInvisible;
Jorim Jaggif75d1612018-02-27 15:05:21 +0100545 private RemoteAnimationTarget mTarget;
Winson Chungd41f71d2018-03-16 15:26:07 -0700546 private final Point mPosition = new Point();
547 private final Rect mBounds = new Rect();
Winson Chunge2d72172018-01-25 17:46:20 +0000548
Vadim Tryshev593e9562018-03-08 17:15:45 -0800549 TaskAnimationAdapter(Task task, boolean isRecentTaskInvisible) {
Winson Chunge2d72172018-01-25 17:46:20 +0000550 mTask = task;
Vadim Tryshev593e9562018-03-08 17:15:45 -0800551 mIsRecentTaskInvisible = isRecentTaskInvisible;
Winson Chungd41f71d2018-03-16 15:26:07 -0700552 final WindowContainer container = mTask.getParent();
553 container.getRelativePosition(mPosition);
554 container.getBounds(mBounds);
Winson Chunge2d72172018-01-25 17:46:20 +0000555 }
556
557 RemoteAnimationTarget createRemoteAnimationApp() {
Winson Chung584d6522018-02-07 23:57:38 +0000558 final WindowState mainWindow = mTask.getTopVisibleAppMainWindow();
Winson Chung2dc37362018-03-12 17:57:06 -0700559 if (mainWindow == null) {
560 return null;
561 }
Jorim Jaggi817ebdd2018-03-26 15:46:01 +0200562 final Rect insets = new Rect(mainWindow.mContentInsets);
563 InsetUtils.addInsets(insets, mainWindow.mAppToken.getLetterboxInsets());
Jorim Jaggif75d1612018-02-27 15:05:21 +0100564 mTarget = new RemoteAnimationTarget(mTask.mTaskId, MODE_CLOSING, mCapturedLeash,
Winson Chung584d6522018-02-07 23:57:38 +0000565 !mTask.fillsParent(), mainWindow.mWinAnimator.mLastClipRect,
Winson Chungd41f71d2018-03-16 15:26:07 -0700566 insets, mTask.getPrefixOrderIndex(), mPosition, mBounds,
Vadim Tryshev593e9562018-03-08 17:15:45 -0800567 mTask.getWindowConfiguration(), mIsRecentTaskInvisible);
Jorim Jaggif75d1612018-02-27 15:05:21 +0100568 return mTarget;
Winson Chunge2d72172018-01-25 17:46:20 +0000569 }
570
571 @Override
572 public boolean getDetachWallpaper() {
573 return false;
574 }
575
576 @Override
Jorim Jaggi82c17862018-02-21 17:50:18 +0100577 public boolean getShowWallpaper() {
578 return false;
579 }
580
581 @Override
Winson Chunge2d72172018-01-25 17:46:20 +0000582 public int getBackgroundColor() {
583 return 0;
584 }
585
586 @Override
587 public void startAnimation(SurfaceControl animationLeash, Transaction t,
588 OnAnimationFinishedCallback finishCallback) {
Winson Chung65a05862018-04-12 17:14:50 -0700589 // Restore z-layering, position and stack crop until client has a chance to modify it.
590 t.setLayer(animationLeash, mTask.getPrefixOrderIndex());
Winson Chungd41f71d2018-03-16 15:26:07 -0700591 t.setPosition(animationLeash, mPosition.x, mPosition.y);
Winson Chung65a05862018-04-12 17:14:50 -0700592 mTmpRect.set(mBounds);
593 mTmpRect.offsetTo(0, 0);
594 t.setWindowCrop(animationLeash, mTmpRect);
Winson Chunge2d72172018-01-25 17:46:20 +0000595 mCapturedLeash = animationLeash;
596 mCapturedFinishCallback = finishCallback;
597 }
598
599 @Override
600 public void onAnimationCancelled(SurfaceControl animationLeash) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700601 cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "taskAnimationAdapterCanceled");
Winson Chunge2d72172018-01-25 17:46:20 +0000602 }
603
604 @Override
605 public long getDurationHint() {
606 return 0;
607 }
608
609 @Override
610 public long getStatusBarTransitionsStartTime() {
611 return SystemClock.uptimeMillis();
612 }
Jorim Jaggif75d1612018-02-27 15:05:21 +0100613
614 @Override
615 public void dump(PrintWriter pw, String prefix) {
616 pw.print(prefix); pw.println("task=" + mTask);
617 if (mTarget != null) {
618 pw.print(prefix); pw.println("Target:");
619 mTarget.dump(pw, prefix + " ");
620 } else {
621 pw.print(prefix); pw.println("Target: null");
622 }
Winson Chungc6c3f852018-04-09 15:41:03 -0700623 pw.println("mIsRecentTaskInvisible=" + mIsRecentTaskInvisible);
624 pw.println("mPosition=" + mPosition);
625 pw.println("mBounds=" + mBounds);
626 pw.println("mIsRecentTaskInvisible=" + mIsRecentTaskInvisible);
Jorim Jaggif75d1612018-02-27 15:05:21 +0100627 }
628
629 @Override
630 public void writeToProto(ProtoOutputStream proto) {
631 final long token = proto.start(REMOTE);
632 if (mTarget != null) {
633 mTarget.writeToProto(proto, TARGET);
634 }
635 proto.end(token);
636 }
Winson Chunge2d72172018-01-25 17:46:20 +0000637 }
638
639 public void dump(PrintWriter pw, String prefix) {
640 final String innerPrefix = prefix + " ";
641 pw.print(prefix); pw.println(RecentsAnimationController.class.getSimpleName() + ":");
642 pw.print(innerPrefix); pw.println("mPendingStart=" + mPendingStart);
Winson Chungc6c3f852018-04-09 15:41:03 -0700643 pw.print(innerPrefix); pw.println("mCanceled=" + mCanceled);
644 pw.print(innerPrefix); pw.println("mInputConsumerEnabled=" + mInputConsumerEnabled);
645 pw.print(innerPrefix); pw.println("mSplitScreenMinimized=" + mSplitScreenMinimized);
Winson Chung3e2980e2018-03-29 17:28:57 -0700646 pw.print(innerPrefix); pw.println("mTargetAppToken=" + mTargetAppToken);
Winson Chungc6c3f852018-04-09 15:41:03 -0700647 pw.print(innerPrefix); pw.println("isTargetOverWallpaper=" + isTargetOverWallpaper());
Winson Chunge2d72172018-01-25 17:46:20 +0000648 }
649}