blob: b057b1d8fb526255fdb1215bbff0cae2c2a03baf [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 Chung6a38fca2018-03-28 17:57:09 -070086 private final Runnable mFailsafeRunnable = () -> {
Winson Chungc6c3f852018-04-09 15:41:03 -070087 cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "failSafeRunnable");
Winson Chung6a38fca2018-03-28 17:57:09 -070088 };
Winson Chunge2d72172018-01-25 17:46:20 +000089
90 // The recents component app token that is shown behind the visibile tasks
Winson Chung3e2980e2018-03-29 17:28:57 -070091 private AppWindowToken mTargetAppToken;
Winson Chung584d6522018-02-07 23:57:38 +000092 private Rect mMinimizedHomeBounds = new Rect();
Winson Chunge2d72172018-01-25 17:46:20 +000093
94 // We start the RecentsAnimationController in a pending-start state since we need to wait for
95 // the wallpaper/activity to draw before we can give control to the handler to start animating
96 // the visible task surfaces
97 private boolean mPendingStart = true;
98
99 // Set when the animation has been canceled
Winson Chungf557c3b2018-03-16 10:55:20 -0700100 private boolean mCanceled;
Winson Chunge2d72172018-01-25 17:46:20 +0000101
102 // Whether or not the input consumer is enabled. The input consumer must be both registered and
103 // enabled for it to start intercepting touch events.
104 private boolean mInputConsumerEnabled;
105
Winson Chungf557c3b2018-03-16 10:55:20 -0700106 // Whether or not the recents animation should cause the primary split-screen stack to be
107 // minimized
108 private boolean mSplitScreenMinimized;
109
Adrian Roos653c6c12018-04-09 14:12:46 -0700110 private final Rect mTmpRect = new Rect();
111
112 private boolean mLinkedToDeathOfRunner;
Winson Chunga89ffed2018-01-25 17:46:11 +0000113
Winson Chunge2d72172018-01-25 17:46:20 +0000114 public interface RecentsAnimationCallbacks {
Winson Chung6a38fca2018-03-28 17:57:09 -0700115 void onAnimationFinished(@ReorderMode int reorderMode);
Winson Chunge2d72172018-01-25 17:46:20 +0000116 }
117
118 private final IRecentsAnimationController mController =
119 new IRecentsAnimationController.Stub() {
120
121 @Override
122 public TaskSnapshot screenshotTask(int taskId) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700123 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "screenshotTask(" + taskId + "):"
124 + " mCanceled=" + mCanceled);
Winson Chungf557c3b2018-03-16 10:55:20 -0700125 final long token = Binder.clearCallingIdentity();
Winson Chunge2d72172018-01-25 17:46:20 +0000126 try {
127 synchronized (mService.getWindowManagerLock()) {
128 if (mCanceled) {
129 return null;
130 }
131 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
132 final TaskAnimationAdapter adapter = mPendingAnimations.get(i);
133 final Task task = adapter.mTask;
134 if (task.mTaskId == taskId) {
Winson Chung23aa7b12018-02-01 11:41:43 -0800135 final TaskSnapshotController snapshotController =
136 mService.mTaskSnapshotController;
137 final ArraySet<Task> tasks = Sets.newArraySet(task);
138 snapshotController.snapshotTasks(tasks);
139 snapshotController.addSkipClosingAppSnapshotTasks(tasks);
140 return snapshotController.getSnapshot(taskId, 0 /* userId */,
141 false /* restoreFromDisk */, false /* reducedResolution */);
Winson Chunge2d72172018-01-25 17:46:20 +0000142 }
143 }
144 return null;
145 }
146 } finally {
147 Binder.restoreCallingIdentity(token);
148 }
149 }
150
151 @Override
152 public void finish(boolean moveHomeToTop) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700153 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "finish(" + moveHomeToTop + "):"
154 + " mCanceled=" + mCanceled);
Winson Chungf557c3b2018-03-16 10:55:20 -0700155 final long token = Binder.clearCallingIdentity();
Winson Chunge2d72172018-01-25 17:46:20 +0000156 try {
157 synchronized (mService.getWindowManagerLock()) {
158 if (mCanceled) {
159 return;
160 }
161 }
162
163 // Note, the callback will handle its own synchronization, do not lock on WM lock
164 // prior to calling the callback
Winson Chung6a38fca2018-03-28 17:57:09 -0700165 mCallbacks.onAnimationFinished(moveHomeToTop
Winson Chung3e2980e2018-03-29 17:28:57 -0700166 ? REORDER_MOVE_TO_TOP
167 : REORDER_MOVE_TO_ORIGINAL_POSITION);
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 Chung703719b2018-04-18 17:53:15 -0700388 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "cancelAnimation(): reason=" + reason);
Winson Chung65fc89a2018-02-28 08:32:12 -0800389 synchronized (mService.getWindowManagerLock()) {
390 if (mCanceled) {
391 // We've already canceled the animation
392 return;
393 }
Adrian Roos842e7882018-03-26 17:34:06 +0200394 mService.mH.removeCallbacks(mFailsafeRunnable);
Winson Chung65fc89a2018-02-28 08:32:12 -0800395 mCanceled = true;
396 try {
397 mRunner.onAnimationCanceled();
398 } catch (RemoteException e) {
399 Slog.e(TAG, "Failed to cancel recents animation", e);
400 }
Winson Chunge2d72172018-01-25 17:46:20 +0000401 }
Winson Chungf557c3b2018-03-16 10:55:20 -0700402
Winson Chunge2d72172018-01-25 17:46:20 +0000403 // Clean up and return to the previous app
Winson Chung65fc89a2018-02-28 08:32:12 -0800404 // Don't hold the WM lock here as it calls back to AM/RecentsAnimation
Winson Chung6a38fca2018-03-28 17:57:09 -0700405 mCallbacks.onAnimationFinished(reorderMode);
Winson Chunge2d72172018-01-25 17:46:20 +0000406 }
407
Winson Chung6a38fca2018-03-28 17:57:09 -0700408 void cleanupAnimation(@ReorderMode int reorderMode) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700409 if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG,
410 "cleanupAnimation(): Notify animation finished mPendingAnimations="
411 + mPendingAnimations.size() + " reorderMode=" + reorderMode);
Winson Chunge2d72172018-01-25 17:46:20 +0000412 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
Winson Chungda876c92018-04-05 18:31:06 -0700413 final TaskAnimationAdapter taskAdapter = mPendingAnimations.get(i);
Winson Chung3e2980e2018-03-29 17:28:57 -0700414 if (reorderMode == REORDER_MOVE_TO_TOP || reorderMode == REORDER_KEEP_IN_PLACE) {
Winson Chungda876c92018-04-05 18:31:06 -0700415 taskAdapter.mTask.dontAnimateDimExit();
chaviw87ca63a2018-03-26 14:06:17 -0700416 }
Winson Chungda876c92018-04-05 18:31:06 -0700417 removeAnimation(taskAdapter);
Winson Chunge2d72172018-01-25 17:46:20 +0000418 }
Winson Chunge2d72172018-01-25 17:46:20 +0000419
Adrian Roos653c6c12018-04-09 14:12:46 -0700420 unlinkToDeathOfRunner();
Winson Chungf557c3b2018-03-16 10:55:20 -0700421 // Clear associated input consumers
Winson Chunge2d72172018-01-25 17:46:20 +0000422 mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
Winson Chunga89ffed2018-01-25 17:46:11 +0000423 mService.destroyInputConsumer(INPUT_CONSUMER_RECENTS_ANIMATION);
Winson Chung0bb66cc2018-04-10 11:58:15 -0700424
425 // We have deferred all notifications to the target app as a part of the recents animation,
426 // so if we are actually transitioning there, notify again here
427 if (mTargetAppToken != null) {
428 if (reorderMode == REORDER_MOVE_TO_TOP || reorderMode == REORDER_KEEP_IN_PLACE) {
429 mService.mAppTransition.notifyAppTransitionFinishedLocked(mTargetAppToken.token);
430 }
431 }
Winson Chunge2d72172018-01-25 17:46:20 +0000432 }
433
Adrian Roos842e7882018-03-26 17:34:06 +0200434 void scheduleFailsafe() {
435 mService.mH.postDelayed(mFailsafeRunnable, FAILSAFE_DELAY);
436 }
437
Adrian Roos653c6c12018-04-09 14:12:46 -0700438 private void linkToDeathOfRunner() throws RemoteException {
439 if (!mLinkedToDeathOfRunner) {
440 mRunner.asBinder().linkToDeath(this, 0);
441 mLinkedToDeathOfRunner = true;
442 }
443 }
444
445 private void unlinkToDeathOfRunner() {
446 if (mLinkedToDeathOfRunner) {
447 mRunner.asBinder().unlinkToDeath(this, 0);
448 mLinkedToDeathOfRunner = false;
449 }
450 }
451
Adrian Roos842e7882018-03-26 17:34:06 +0200452 @Override
453 public void binderDied() {
Winson Chungc6c3f852018-04-09 15:41:03 -0700454 cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "binderDied");
Adrian Roos842e7882018-03-26 17:34:06 +0200455 }
456
Winson Chunge2d72172018-01-25 17:46:20 +0000457 void checkAnimationReady(WallpaperController wallpaperController) {
458 if (mPendingStart) {
Winson Chung3e2980e2018-03-29 17:28:57 -0700459 final boolean wallpaperReady = !isTargetOverWallpaper()
Winson Chunge2d72172018-01-25 17:46:20 +0000460 || (wallpaperController.getWallpaperTarget() != null
461 && wallpaperController.wallpaperTransitionReady());
462 if (wallpaperReady) {
463 mService.getRecentsAnimationController().startAnimation();
464 }
465 }
466 }
467
Winson Chungf557c3b2018-03-16 10:55:20 -0700468 boolean isSplitScreenMinimized() {
469 return mSplitScreenMinimized;
470 }
471
Winson Chunge2d72172018-01-25 17:46:20 +0000472 boolean isWallpaperVisible(WindowState w) {
Winson Chung3e2980e2018-03-29 17:28:57 -0700473 return w != null && w.mAppToken != null && mTargetAppToken == w.mAppToken
474 && isTargetOverWallpaper();
Winson Chunge2d72172018-01-25 17:46:20 +0000475 }
476
Winson Chunga89ffed2018-01-25 17:46:11 +0000477 boolean hasInputConsumerForApp(AppWindowToken appToken) {
478 return mInputConsumerEnabled && isAnimatingApp(appToken);
479 }
480
481 boolean updateInputConsumerForApp(InputConsumerImpl recentsAnimationInputConsumer,
482 boolean hasFocus) {
Winson Chung3e2980e2018-03-29 17:28:57 -0700483 // Update the input consumer touchable region to match the target app main window
484 final WindowState targetAppMainWindow = mTargetAppToken != null
485 ? mTargetAppToken.findMainWindow()
Winson Chunga89ffed2018-01-25 17:46:11 +0000486 : null;
Winson Chung3e2980e2018-03-29 17:28:57 -0700487 if (targetAppMainWindow != null) {
488 targetAppMainWindow.getBounds(mTmpRect);
Winson Chunga89ffed2018-01-25 17:46:11 +0000489 recentsAnimationInputConsumer.mWindowHandle.hasFocus = hasFocus;
490 recentsAnimationInputConsumer.mWindowHandle.touchableRegion.set(mTmpRect);
491 return true;
492 }
493 return false;
494 }
495
Winson Chung0bb66cc2018-04-10 11:58:15 -0700496 boolean isTargetApp(AppWindowToken token) {
497 return mTargetAppToken != null && token == mTargetAppToken;
498 }
499
Winson Chung3e2980e2018-03-29 17:28:57 -0700500 private boolean isTargetOverWallpaper() {
501 if (mTargetAppToken == null) {
Winson Chunge2d72172018-01-25 17:46:20 +0000502 return false;
503 }
Winson Chung3e2980e2018-03-29 17:28:57 -0700504 return mTargetAppToken.windowsCanBeWallpaperTarget();
Winson Chunge2d72172018-01-25 17:46:20 +0000505 }
506
Winson Chungd41f71d2018-03-16 15:26:07 -0700507 boolean isAnimatingTask(Task task) {
508 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
509 if (task == mPendingAnimations.get(i).mTask) {
510 return true;
511 }
512 }
513 return false;
514 }
515
Winson Chunga89ffed2018-01-25 17:46:11 +0000516 private boolean isAnimatingApp(AppWindowToken appToken) {
Winson Chunge2d72172018-01-25 17:46:20 +0000517 for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
518 final Task task = mPendingAnimations.get(i).mTask;
519 for (int j = task.getChildCount() - 1; j >= 0; j--) {
520 final AppWindowToken app = task.getChildAt(j);
521 if (app == appToken) {
522 return true;
523 }
524 }
525 }
526 return false;
527 }
528
Winson Chungda876c92018-04-05 18:31:06 -0700529 @VisibleForTesting
530 class TaskAnimationAdapter implements AnimationAdapter {
Winson Chunge2d72172018-01-25 17:46:20 +0000531
Vadim Tryshev593e9562018-03-08 17:15:45 -0800532 private final Task mTask;
Winson Chunge2d72172018-01-25 17:46:20 +0000533 private SurfaceControl mCapturedLeash;
534 private OnAnimationFinishedCallback mCapturedFinishCallback;
Vadim Tryshev593e9562018-03-08 17:15:45 -0800535 private final boolean mIsRecentTaskInvisible;
Jorim Jaggif75d1612018-02-27 15:05:21 +0100536 private RemoteAnimationTarget mTarget;
Winson Chungd41f71d2018-03-16 15:26:07 -0700537 private final Point mPosition = new Point();
538 private final Rect mBounds = new Rect();
Winson Chunge2d72172018-01-25 17:46:20 +0000539
Vadim Tryshev593e9562018-03-08 17:15:45 -0800540 TaskAnimationAdapter(Task task, boolean isRecentTaskInvisible) {
Winson Chunge2d72172018-01-25 17:46:20 +0000541 mTask = task;
Vadim Tryshev593e9562018-03-08 17:15:45 -0800542 mIsRecentTaskInvisible = isRecentTaskInvisible;
Winson Chungd41f71d2018-03-16 15:26:07 -0700543 final WindowContainer container = mTask.getParent();
544 container.getRelativePosition(mPosition);
545 container.getBounds(mBounds);
Winson Chunge2d72172018-01-25 17:46:20 +0000546 }
547
548 RemoteAnimationTarget createRemoteAnimationApp() {
Winson Chung584d6522018-02-07 23:57:38 +0000549 final WindowState mainWindow = mTask.getTopVisibleAppMainWindow();
Winson Chung2dc37362018-03-12 17:57:06 -0700550 if (mainWindow == null) {
551 return null;
552 }
Jorim Jaggi817ebdd2018-03-26 15:46:01 +0200553 final Rect insets = new Rect(mainWindow.mContentInsets);
554 InsetUtils.addInsets(insets, mainWindow.mAppToken.getLetterboxInsets());
Jorim Jaggif75d1612018-02-27 15:05:21 +0100555 mTarget = new RemoteAnimationTarget(mTask.mTaskId, MODE_CLOSING, mCapturedLeash,
Winson Chung584d6522018-02-07 23:57:38 +0000556 !mTask.fillsParent(), mainWindow.mWinAnimator.mLastClipRect,
Winson Chungd41f71d2018-03-16 15:26:07 -0700557 insets, mTask.getPrefixOrderIndex(), mPosition, mBounds,
Vadim Tryshev593e9562018-03-08 17:15:45 -0800558 mTask.getWindowConfiguration(), mIsRecentTaskInvisible);
Jorim Jaggif75d1612018-02-27 15:05:21 +0100559 return mTarget;
Winson Chunge2d72172018-01-25 17:46:20 +0000560 }
561
562 @Override
563 public boolean getDetachWallpaper() {
564 return false;
565 }
566
567 @Override
Jorim Jaggi82c17862018-02-21 17:50:18 +0100568 public boolean getShowWallpaper() {
569 return false;
570 }
571
572 @Override
Winson Chunge2d72172018-01-25 17:46:20 +0000573 public int getBackgroundColor() {
574 return 0;
575 }
576
577 @Override
578 public void startAnimation(SurfaceControl animationLeash, Transaction t,
579 OnAnimationFinishedCallback finishCallback) {
Winson Chung65a05862018-04-12 17:14:50 -0700580 // Restore z-layering, position and stack crop until client has a chance to modify it.
581 t.setLayer(animationLeash, mTask.getPrefixOrderIndex());
Winson Chungd41f71d2018-03-16 15:26:07 -0700582 t.setPosition(animationLeash, mPosition.x, mPosition.y);
Winson Chung65a05862018-04-12 17:14:50 -0700583 mTmpRect.set(mBounds);
584 mTmpRect.offsetTo(0, 0);
585 t.setWindowCrop(animationLeash, mTmpRect);
Winson Chunge2d72172018-01-25 17:46:20 +0000586 mCapturedLeash = animationLeash;
587 mCapturedFinishCallback = finishCallback;
588 }
589
590 @Override
591 public void onAnimationCancelled(SurfaceControl animationLeash) {
Winson Chungc6c3f852018-04-09 15:41:03 -0700592 cancelAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION, "taskAnimationAdapterCanceled");
Winson Chunge2d72172018-01-25 17:46:20 +0000593 }
594
595 @Override
596 public long getDurationHint() {
597 return 0;
598 }
599
600 @Override
601 public long getStatusBarTransitionsStartTime() {
602 return SystemClock.uptimeMillis();
603 }
Jorim Jaggif75d1612018-02-27 15:05:21 +0100604
605 @Override
606 public void dump(PrintWriter pw, String prefix) {
607 pw.print(prefix); pw.println("task=" + mTask);
608 if (mTarget != null) {
609 pw.print(prefix); pw.println("Target:");
610 mTarget.dump(pw, prefix + " ");
611 } else {
612 pw.print(prefix); pw.println("Target: null");
613 }
Winson Chungc6c3f852018-04-09 15:41:03 -0700614 pw.println("mIsRecentTaskInvisible=" + mIsRecentTaskInvisible);
615 pw.println("mPosition=" + mPosition);
616 pw.println("mBounds=" + mBounds);
617 pw.println("mIsRecentTaskInvisible=" + mIsRecentTaskInvisible);
Jorim Jaggif75d1612018-02-27 15:05:21 +0100618 }
619
620 @Override
621 public void writeToProto(ProtoOutputStream proto) {
622 final long token = proto.start(REMOTE);
623 if (mTarget != null) {
624 mTarget.writeToProto(proto, TARGET);
625 }
626 proto.end(token);
627 }
Winson Chunge2d72172018-01-25 17:46:20 +0000628 }
629
630 public void dump(PrintWriter pw, String prefix) {
631 final String innerPrefix = prefix + " ";
632 pw.print(prefix); pw.println(RecentsAnimationController.class.getSimpleName() + ":");
633 pw.print(innerPrefix); pw.println("mPendingStart=" + mPendingStart);
Winson Chungc6c3f852018-04-09 15:41:03 -0700634 pw.print(innerPrefix); pw.println("mCanceled=" + mCanceled);
635 pw.print(innerPrefix); pw.println("mInputConsumerEnabled=" + mInputConsumerEnabled);
636 pw.print(innerPrefix); pw.println("mSplitScreenMinimized=" + mSplitScreenMinimized);
Winson Chung3e2980e2018-03-29 17:28:57 -0700637 pw.print(innerPrefix); pw.println("mTargetAppToken=" + mTargetAppToken);
Winson Chungc6c3f852018-04-09 15:41:03 -0700638 pw.print(innerPrefix); pw.println("isTargetOverWallpaper=" + isTargetOverWallpaper());
Winson Chunge2d72172018-01-25 17:46:20 +0000639 }
640}