blob: 20a871baada4a60c0d5a08b23d4a880690e62b8f [file] [log] [blame]
lumark588a3e82018-07-20 18:53:54 +08001/*
2 * Copyright (C) 2018 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
19import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
20import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE;
21import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
Evan Rosky7735d352019-03-18 17:27:27 -070022import static android.view.WindowManager.TRANSIT_ACTIVITY_RELAUNCH;
lumark588a3e82018-07-20 18:53:54 +080023import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE;
24import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
25import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
Issei Suzuki5609ccb2019-06-13 15:04:08 +020026import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION;
lumark588a3e82018-07-20 18:53:54 +080027import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
28import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
29import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
30import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
31import static android.view.WindowManager.TRANSIT_NONE;
Issei Suzukicac2a502019-04-16 16:52:50 +020032import static android.view.WindowManager.TRANSIT_SHOW_SINGLE_TASK_DISPLAY;
lumark588a3e82018-07-20 18:53:54 +080033import static android.view.WindowManager.TRANSIT_TASK_CLOSE;
34import static android.view.WindowManager.TRANSIT_TASK_IN_PLACE;
35import static android.view.WindowManager.TRANSIT_TASK_OPEN;
36import static android.view.WindowManager.TRANSIT_TASK_TO_BACK;
37import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
38import static android.view.WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE;
39import static android.view.WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_OPEN;
40import static android.view.WindowManager.TRANSIT_WALLPAPER_CLOSE;
41import static android.view.WindowManager.TRANSIT_WALLPAPER_INTRA_CLOSE;
42import static android.view.WindowManager.TRANSIT_WALLPAPER_INTRA_OPEN;
43import static android.view.WindowManager.TRANSIT_WALLPAPER_OPEN;
44
45import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
46import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
47import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_SNAPSHOT;
48import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_SPLASH_SCREEN;
49import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_WINDOWS_DRAWN;
50import static com.android.server.wm.AppTransition.isKeyguardGoingAwayTransit;
Adrian Roosb125e0b2019-10-02 14:55:14 +020051import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
lumark588a3e82018-07-20 18:53:54 +080052import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
53import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
54import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
lumark588a3e82018-07-20 18:53:54 +080055
Yunfan Chencafc7062019-01-22 17:21:32 +090056import android.os.SystemClock;
lumark588a3e82018-07-20 18:53:54 +080057import android.os.Trace;
58import android.util.ArraySet;
59import android.util.Slog;
60import android.util.SparseIntArray;
61import android.view.Display;
62import android.view.RemoteAnimationAdapter;
63import android.view.RemoteAnimationDefinition;
64import android.view.WindowManager;
65import android.view.WindowManager.LayoutParams;
66import android.view.animation.Animation;
67
68import com.android.internal.annotations.VisibleForTesting;
Adrian Roosb125e0b2019-10-02 14:55:14 +020069import com.android.server.protolog.common.ProtoLog;
lumark588a3e82018-07-20 18:53:54 +080070
71import java.util.function.Predicate;
72
73
74/**
75 * Checks for app transition readiness, resolves animation attributes and performs visibility
76 * change for apps that animate as part of an app transition.
77 */
78public class AppTransitionController {
79 private static final String TAG = TAG_WITH_CLASS_NAME ? "AppTransitionController" : TAG_WM;
80 private final WindowManagerService mService;
81 private final DisplayContent mDisplayContent;
82 private final WallpaperController mWallpaperControllerLocked;
Evan Rosky966759f2019-01-15 10:33:58 -080083 private RemoteAnimationDefinition mRemoteAnimationDefinition = null;
lumark588a3e82018-07-20 18:53:54 +080084
85 private final SparseIntArray mTempTransitionReasons = new SparseIntArray();
86
87 AppTransitionController(WindowManagerService service, DisplayContent displayContent) {
88 mService = service;
89 mDisplayContent = displayContent;
wilsonshihc32538e2018-11-07 17:27:34 +080090 mWallpaperControllerLocked = mDisplayContent.mWallpaperController;
lumark588a3e82018-07-20 18:53:54 +080091 }
92
Evan Rosky966759f2019-01-15 10:33:58 -080093 void registerRemoteAnimations(RemoteAnimationDefinition definition) {
94 mRemoteAnimationDefinition = definition;
95 }
96
lumark588a3e82018-07-20 18:53:54 +080097 /**
98 * Handle application transition for given display.
99 */
100 void handleAppTransitionReady() {
Evan Rosky2289ba12018-11-19 18:28:18 -0800101 mTempTransitionReasons.clear();
102 if (!transitionGoodToGo(mDisplayContent.mOpeningApps, mTempTransitionReasons)
103 || !transitionGoodToGo(mDisplayContent.mChangingApps, mTempTransitionReasons)) {
lumark588a3e82018-07-20 18:53:54 +0800104 return;
105 }
106 Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "AppTransitionReady");
107
Adrian Roosb125e0b2019-10-02 14:55:14 +0200108 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "**** GOOD TO GO");
Tiger Huang7c610aa2018-10-27 00:01:01 +0800109 final AppTransition appTransition = mDisplayContent.mAppTransition;
110 int transit = appTransition.getAppTransition();
lumark588a3e82018-07-20 18:53:54 +0800111 if (mDisplayContent.mSkipAppTransitionAnimation && !isKeyguardGoingAwayTransit(transit)) {
112 transit = WindowManager.TRANSIT_UNSET;
113 }
114 mDisplayContent.mSkipAppTransitionAnimation = false;
115 mDisplayContent.mNoAnimationNotifyOnTransitionFinished.clear();
116
Tiger Huang7c610aa2018-10-27 00:01:01 +0800117 appTransition.removeAppTransitionTimeoutCallbacks();
lumark588a3e82018-07-20 18:53:54 +0800118
wilsonshihc32538e2018-11-07 17:27:34 +0800119 mDisplayContent.mWallpaperMayChange = false;
lumark588a3e82018-07-20 18:53:54 +0800120
Evan Rosky2289ba12018-11-19 18:28:18 -0800121 int appCount = mDisplayContent.mOpeningApps.size();
122 for (int i = 0; i < appCount; ++i) {
lumark588a3e82018-07-20 18:53:54 +0800123 // Clearing the mAnimatingExit flag before entering animation. It's set to true if app
124 // window is removed, or window relayout to invisible. This also affects window
125 // visibility. We need to clear it *before* maybeUpdateTransitToWallpaper() as the
126 // transition selection depends on wallpaper target visibility.
Evan Rosky2289ba12018-11-19 18:28:18 -0800127 mDisplayContent.mOpeningApps.valueAtUnchecked(i).clearAnimatingFlags();
128 }
129 appCount = mDisplayContent.mChangingApps.size();
130 for (int i = 0; i < appCount; ++i) {
131 // Clearing for same reason as above.
132 mDisplayContent.mChangingApps.valueAtUnchecked(i).clearAnimatingFlags();
lumark588a3e82018-07-20 18:53:54 +0800133 }
134
135 // Adjust wallpaper before we pull the lower/upper target, since pending changes
136 // (like the clearAnimatingFlags() above) might affect wallpaper target result.
137 // Or, the opening app window should be a wallpaper target.
wilsonshihc32538e2018-11-07 17:27:34 +0800138 mWallpaperControllerLocked.adjustWallpaperWindowsForAppTransitionIfNeeded(
Evan Rosky2289ba12018-11-19 18:28:18 -0800139 mDisplayContent.mOpeningApps, mDisplayContent.mChangingApps);
lumark588a3e82018-07-20 18:53:54 +0800140
141 // Determine if closing and opening app token sets are wallpaper targets, in which case
142 // special animations are needed.
143 final boolean hasWallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget() != null;
144 final boolean openingAppHasWallpaper = canBeWallpaperTarget(mDisplayContent.mOpeningApps)
145 && hasWallpaperTarget;
146 final boolean closingAppHasWallpaper = canBeWallpaperTarget(mDisplayContent.mClosingApps)
147 && hasWallpaperTarget;
148
149 transit = maybeUpdateTransitToTranslucentAnim(transit);
150 transit = maybeUpdateTransitToWallpaper(transit, openingAppHasWallpaper,
151 closingAppHasWallpaper);
152
153 // Find the layout params of the top-most application window in the tokens, which is
154 // what will control the animation theme. If all closing windows are obscured, then there is
155 // no need to do an animation. This is the case, for example, when this transition is being
156 // done behind a dream window.
157 final ArraySet<Integer> activityTypes = collectActivityTypes(mDisplayContent.mOpeningApps,
Evan Rosky2289ba12018-11-19 18:28:18 -0800158 mDisplayContent.mClosingApps, mDisplayContent.mChangingApps);
Tiger Huang7c610aa2018-10-27 00:01:01 +0800159 final boolean allowAnimations = mDisplayContent.getDisplayPolicy().allowAppAnimationsLw();
lumark588a3e82018-07-20 18:53:54 +0800160 final AppWindowToken animLpToken = allowAnimations
161 ? findAnimLayoutParamsToken(transit, activityTypes)
162 : null;
163 final AppWindowToken topOpeningApp = allowAnimations
164 ? getTopApp(mDisplayContent.mOpeningApps, false /* ignoreHidden */)
165 : null;
166 final AppWindowToken topClosingApp = allowAnimations
167 ? getTopApp(mDisplayContent.mClosingApps, false /* ignoreHidden */)
168 : null;
Evan Rosky2289ba12018-11-19 18:28:18 -0800169 final AppWindowToken topChangingApp = allowAnimations
170 ? getTopApp(mDisplayContent.mChangingApps, false /* ignoreHidden */)
171 : null;
lumark588a3e82018-07-20 18:53:54 +0800172 final WindowManager.LayoutParams animLp = getAnimLp(animLpToken);
173 overrideWithRemoteAnimationIfSet(animLpToken, transit, activityTypes);
174
175 final boolean voiceInteraction = containsVoiceInteraction(mDisplayContent.mOpeningApps)
Evan Rosky2289ba12018-11-19 18:28:18 -0800176 || containsVoiceInteraction(mDisplayContent.mOpeningApps)
177 || containsVoiceInteraction(mDisplayContent.mChangingApps);
lumark588a3e82018-07-20 18:53:54 +0800178
179 final int layoutRedo;
180 mService.mSurfaceAnimationRunner.deferStartingAnimations();
181 try {
182 processApplicationsAnimatingInPlace(transit);
183
184 handleClosingApps(transit, animLp, voiceInteraction);
185 handleOpeningApps(transit, animLp, voiceInteraction);
Evan Rosky2289ba12018-11-19 18:28:18 -0800186 handleChangingApps(transit, animLp, voiceInteraction);
lumark588a3e82018-07-20 18:53:54 +0800187
Tiger Huang7c610aa2018-10-27 00:01:01 +0800188 appTransition.setLastAppTransition(transit, topOpeningApp,
Evan Rosky2289ba12018-11-19 18:28:18 -0800189 topClosingApp, topChangingApp);
lumark588a3e82018-07-20 18:53:54 +0800190
Tiger Huang7c610aa2018-10-27 00:01:01 +0800191 final int flags = appTransition.getTransitFlags();
192 layoutRedo = appTransition.goodToGo(transit, topOpeningApp,
Evan Rosky2289ba12018-11-19 18:28:18 -0800193 mDisplayContent.mOpeningApps);
lumark588a3e82018-07-20 18:53:54 +0800194 handleNonAppWindowsInTransition(transit, flags);
Tiger Huang7c610aa2018-10-27 00:01:01 +0800195 appTransition.postAnimationCallback();
196 appTransition.clear();
lumark588a3e82018-07-20 18:53:54 +0800197 } finally {
198 mService.mSurfaceAnimationRunner.continueStartingAnimations();
199 }
200
201 mService.mTaskSnapshotController.onTransitionStarting(mDisplayContent);
202
203 mDisplayContent.mOpeningApps.clear();
204 mDisplayContent.mClosingApps.clear();
Evan Rosky2289ba12018-11-19 18:28:18 -0800205 mDisplayContent.mChangingApps.clear();
lumark588a3e82018-07-20 18:53:54 +0800206 mDisplayContent.mUnknownAppVisibilityController.clear();
207
208 // This has changed the visibility of windows, so perform
209 // a new layout to get them all up-to-date.
210 mDisplayContent.setLayoutNeeded();
211
212 mDisplayContent.computeImeTarget(true /* updateImeTarget */);
213
Yunfan Chencafc7062019-01-22 17:21:32 +0900214 mService.mAtmInternal.notifyAppTransitionStarting(mTempTransitionReasons.clone(),
215 SystemClock.uptimeMillis());
lumark588a3e82018-07-20 18:53:54 +0800216
Issei Suzukicac2a502019-04-16 16:52:50 +0200217 if (transit == TRANSIT_SHOW_SINGLE_TASK_DISPLAY) {
218 mService.mAnimator.addAfterPrepareSurfacesRunnable(() -> {
219 mService.mAtmInternal.notifySingleTaskDisplayDrawn(mDisplayContent.getDisplayId());
220 });
221 }
222
lumark588a3e82018-07-20 18:53:54 +0800223 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
224
225 mDisplayContent.pendingLayoutChanges |=
226 layoutRedo | FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG;
227 }
228
229 private static WindowManager.LayoutParams getAnimLp(AppWindowToken wtoken) {
230 final WindowState mainWindow = wtoken != null ? wtoken.findMainWindow() : null;
231 return mainWindow != null ? mainWindow.mAttrs : null;
232 }
233
Evan Rosky966759f2019-01-15 10:33:58 -0800234 RemoteAnimationAdapter getRemoteAnimationOverride(AppWindowToken animLpToken, int transit,
235 ArraySet<Integer> activityTypes) {
236 final RemoteAnimationDefinition definition = animLpToken.getRemoteAnimationDefinition();
237 if (definition != null) {
238 final RemoteAnimationAdapter adapter = definition.getAdapter(transit, activityTypes);
239 if (adapter != null) {
240 return adapter;
241 }
242 }
243 if (mRemoteAnimationDefinition == null) {
244 return null;
245 }
246 return mRemoteAnimationDefinition.getAdapter(transit, activityTypes);
247 }
248
lumark588a3e82018-07-20 18:53:54 +0800249 /**
250 * Overrides the pending transition with the remote animation defined for the transition in the
251 * set of defined remote animations in the app window token.
252 */
253 private void overrideWithRemoteAnimationIfSet(AppWindowToken animLpToken, int transit,
254 ArraySet<Integer> activityTypes) {
255 if (transit == TRANSIT_CRASHING_ACTIVITY_CLOSE) {
256 // The crash transition has higher priority than any involved remote animations.
257 return;
258 }
259 if (animLpToken == null) {
260 return;
261 }
Evan Rosky966759f2019-01-15 10:33:58 -0800262 final RemoteAnimationAdapter adapter =
263 getRemoteAnimationOverride(animLpToken, transit, activityTypes);
lumark588a3e82018-07-20 18:53:54 +0800264 if (adapter != null) {
265 animLpToken.getDisplayContent().mAppTransition.overridePendingAppTransitionRemote(
266 adapter);
267 }
268 }
269
270 /**
271 * @return The window token that determines the animation theme.
272 */
273 private AppWindowToken findAnimLayoutParamsToken(@WindowManager.TransitionType int transit,
274 ArraySet<Integer> activityTypes) {
275 AppWindowToken result;
276 final ArraySet<AppWindowToken> closingApps = mDisplayContent.mClosingApps;
277 final ArraySet<AppWindowToken> openingApps = mDisplayContent.mOpeningApps;
Evan Rosky2289ba12018-11-19 18:28:18 -0800278 final ArraySet<AppWindowToken> changingApps = mDisplayContent.mChangingApps;
lumark588a3e82018-07-20 18:53:54 +0800279
280 // Remote animations always win, but fullscreen tokens override non-fullscreen tokens.
Evan Rosky2289ba12018-11-19 18:28:18 -0800281 result = lookForHighestTokenWithFilter(closingApps, openingApps, changingApps,
lumark588a3e82018-07-20 18:53:54 +0800282 w -> w.getRemoteAnimationDefinition() != null
283 && w.getRemoteAnimationDefinition().hasTransition(transit, activityTypes));
284 if (result != null) {
285 return result;
286 }
Evan Rosky2289ba12018-11-19 18:28:18 -0800287 result = lookForHighestTokenWithFilter(closingApps, openingApps, changingApps,
lumark588a3e82018-07-20 18:53:54 +0800288 w -> w.fillsParent() && w.findMainWindow() != null);
289 if (result != null) {
290 return result;
291 }
Evan Rosky2289ba12018-11-19 18:28:18 -0800292 return lookForHighestTokenWithFilter(closingApps, openingApps, changingApps,
lumark588a3e82018-07-20 18:53:54 +0800293 w -> w.findMainWindow() != null);
294 }
295
296 /**
Tiger Huang7c610aa2018-10-27 00:01:01 +0800297 * @return The set of {@link android.app.WindowConfiguration.ActivityType}s contained in the set
Evan Rosky2289ba12018-11-19 18:28:18 -0800298 * of apps in {@code array1}, {@code array2}, and {@code array3}.
lumark588a3e82018-07-20 18:53:54 +0800299 */
300 private static ArraySet<Integer> collectActivityTypes(ArraySet<AppWindowToken> array1,
Evan Rosky2289ba12018-11-19 18:28:18 -0800301 ArraySet<AppWindowToken> array2, ArraySet<AppWindowToken> array3) {
lumark588a3e82018-07-20 18:53:54 +0800302 final ArraySet<Integer> result = new ArraySet<>();
303 for (int i = array1.size() - 1; i >= 0; i--) {
304 result.add(array1.valueAt(i).getActivityType());
305 }
306 for (int i = array2.size() - 1; i >= 0; i--) {
307 result.add(array2.valueAt(i).getActivityType());
308 }
Evan Rosky2289ba12018-11-19 18:28:18 -0800309 for (int i = array3.size() - 1; i >= 0; i--) {
310 result.add(array3.valueAt(i).getActivityType());
311 }
lumark588a3e82018-07-20 18:53:54 +0800312 return result;
313 }
314
315 private static AppWindowToken lookForHighestTokenWithFilter(ArraySet<AppWindowToken> array1,
Evan Rosky2289ba12018-11-19 18:28:18 -0800316 ArraySet<AppWindowToken> array2, ArraySet<AppWindowToken> array3,
317 Predicate<AppWindowToken> filter) {
318 final int array2base = array1.size();
319 final int array3base = array2.size() + array2base;
320 final int count = array3base + array3.size();
lumark588a3e82018-07-20 18:53:54 +0800321 int bestPrefixOrderIndex = Integer.MIN_VALUE;
322 AppWindowToken bestToken = null;
323 for (int i = 0; i < count; i++) {
Evan Rosky2289ba12018-11-19 18:28:18 -0800324 final AppWindowToken wtoken = i < array2base
lumark588a3e82018-07-20 18:53:54 +0800325 ? array1.valueAt(i)
Evan Rosky2289ba12018-11-19 18:28:18 -0800326 : (i < array3base
327 ? array2.valueAt(i - array2base)
328 : array3.valueAt(i - array3base));
lumark588a3e82018-07-20 18:53:54 +0800329 final int prefixOrderIndex = wtoken.getPrefixOrderIndex();
330 if (filter.test(wtoken) && prefixOrderIndex > bestPrefixOrderIndex) {
331 bestPrefixOrderIndex = prefixOrderIndex;
332 bestToken = wtoken;
333 }
334 }
335 return bestToken;
336 }
337
338 private boolean containsVoiceInteraction(ArraySet<AppWindowToken> apps) {
339 for (int i = apps.size() - 1; i >= 0; i--) {
340 if (apps.valueAt(i).mVoiceInteraction) {
341 return true;
342 }
343 }
344 return false;
345 }
346
347 private void handleOpeningApps(int transit, LayoutParams animLp, boolean voiceInteraction) {
348 final ArraySet<AppWindowToken> openingApps = mDisplayContent.mOpeningApps;
349 final int appsCount = openingApps.size();
350 for (int i = 0; i < appsCount; i++) {
351 AppWindowToken wtoken = openingApps.valueAt(i);
Adrian Roosb125e0b2019-10-02 14:55:14 +0200352 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now opening app %s", wtoken);
lumark588a3e82018-07-20 18:53:54 +0800353
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800354 if (!wtoken.commitVisibility(animLp, true, transit, false, voiceInteraction)) {
lumark588a3e82018-07-20 18:53:54 +0800355 // This token isn't going to be animating. Add it to the list of tokens to
356 // be notified of app transition complete since the notification will not be
357 // sent be the app window animator.
358 mDisplayContent.mNoAnimationNotifyOnTransitionFinished.add(wtoken.token);
359 }
360 wtoken.updateReportedVisibilityLocked();
361 wtoken.waitingToShow = false;
362 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
363 ">>> OPEN TRANSACTION handleAppTransitionReady()");
364 mService.openSurfaceTransaction();
365 try {
366 wtoken.showAllWindowsLocked();
367 } finally {
368 mService.closeSurfaceTransaction("handleAppTransitionReady");
369 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
370 "<<< CLOSE TRANSACTION handleAppTransitionReady()");
371 }
372
373 if (mDisplayContent.mAppTransition.isNextAppTransitionThumbnailUp()) {
374 wtoken.attachThumbnailAnimation();
375 } else if (mDisplayContent.mAppTransition.isNextAppTransitionOpenCrossProfileApps()) {
376 wtoken.attachCrossProfileAppsThumbnailAnimation();
377 }
378 }
379 }
380
381 private void handleClosingApps(int transit, LayoutParams animLp, boolean voiceInteraction) {
382 final ArraySet<AppWindowToken> closingApps = mDisplayContent.mClosingApps;
383 final int appsCount = closingApps.size();
384 for (int i = 0; i < appsCount; i++) {
385 AppWindowToken wtoken = closingApps.valueAt(i);
386
Adrian Roosb125e0b2019-10-02 14:55:14 +0200387 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now closing app %s", wtoken);
lumark588a3e82018-07-20 18:53:54 +0800388 // TODO: Do we need to add to mNoAnimationNotifyOnTransitionFinished like above if not
389 // animating?
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800390 wtoken.commitVisibility(animLp, false, transit, false, voiceInteraction);
lumark588a3e82018-07-20 18:53:54 +0800391 wtoken.updateReportedVisibilityLocked();
392 // Force the allDrawn flag, because we want to start
393 // this guy's animations regardless of whether it's
394 // gotten drawn.
395 wtoken.allDrawn = true;
396 wtoken.deferClearAllDrawn = false;
397 // Ensure that apps that are mid-starting are also scheduled to have their
398 // starting windows removed after the animation is complete
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800399 if (wtoken.startingWindow != null && !wtoken.startingWindow.mAnimatingExit) {
400 wtoken.removeStartingWindow();
lumark588a3e82018-07-20 18:53:54 +0800401 }
402
403 if (mDisplayContent.mAppTransition.isNextAppTransitionThumbnailDown()) {
404 wtoken.attachThumbnailAnimation();
405 }
406 }
407 }
408
Evan Rosky2289ba12018-11-19 18:28:18 -0800409 private void handleChangingApps(int transit, LayoutParams animLp, boolean voiceInteraction) {
410 final ArraySet<AppWindowToken> apps = mDisplayContent.mChangingApps;
411 final int appsCount = apps.size();
412 for (int i = 0; i < appsCount; i++) {
413 AppWindowToken wtoken = apps.valueAt(i);
Adrian Roosb125e0b2019-10-02 14:55:14 +0200414 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now changing app %s", wtoken);
Evan Rosky2289ba12018-11-19 18:28:18 -0800415 wtoken.cancelAnimationOnly();
416 wtoken.applyAnimationLocked(null, transit, true, false);
417 wtoken.updateReportedVisibilityLocked();
418 mService.openSurfaceTransaction();
419 try {
420 wtoken.showAllWindowsLocked();
421 } finally {
422 mService.closeSurfaceTransaction("handleChangingApps");
423 }
424 }
425 }
426
lumark588a3e82018-07-20 18:53:54 +0800427 private void handleNonAppWindowsInTransition(int transit, int flags) {
428 if (transit == TRANSIT_KEYGUARD_GOING_AWAY) {
429 if ((flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0
Issei Suzuki5609ccb2019-06-13 15:04:08 +0200430 && (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION) == 0
431 && (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION) == 0) {
lumark588a3e82018-07-20 18:53:54 +0800432 Animation anim = mService.mPolicy.createKeyguardWallpaperExit(
433 (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0);
434 if (anim != null) {
435 mDisplayContent.mWallpaperController.startWallpaperAnimation(anim);
436 }
437 }
438 }
439 if (transit == TRANSIT_KEYGUARD_GOING_AWAY
440 || transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER) {
441 mDisplayContent.startKeyguardExitOnNonAppWindows(
442 transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER,
Issei Suzuki5609ccb2019-06-13 15:04:08 +0200443 (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0,
444 (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION) != 0);
lumark588a3e82018-07-20 18:53:54 +0800445 }
446 }
447
Evan Rosky2289ba12018-11-19 18:28:18 -0800448 private boolean transitionGoodToGo(ArraySet<AppWindowToken> apps, SparseIntArray outReasons) {
Adrian Roosb125e0b2019-10-02 14:55:14 +0200449 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
450 "Checking %d opening apps (frozen=%b timeout=%b)...", apps.size(),
451 mService.mDisplayFrozen, mDisplayContent.mAppTransition.isTimeout());
Vadim Caenb3715832019-08-13 17:06:38 +0200452
453 final ScreenRotationAnimation screenRotationAnimation = mService.mRoot.getDisplayContent(
454 Display.DEFAULT_DISPLAY).getRotationAnimation();
lumark588a3e82018-07-20 18:53:54 +0800455
lumark588a3e82018-07-20 18:53:54 +0800456 if (!mDisplayContent.mAppTransition.isTimeout()) {
457 // Imagine the case where we are changing orientation due to an app transition, but a
458 // previous orientation change is still in progress. We won't process the orientation
459 // change for our transition because we need to wait for the rotation animation to
460 // finish.
461 // If we start the app transition at this point, we will interrupt it halfway with a
462 // new rotation animation after the old one finally finishes. It's better to defer the
463 // app transition.
464 if (screenRotationAnimation != null && screenRotationAnimation.isAnimating() &&
Riddle Hsuccf09402019-08-13 00:33:06 +0800465 mDisplayContent.getDisplayRotation().needsUpdate()) {
Adrian Roosb125e0b2019-10-02 14:55:14 +0200466 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
467 "Delaying app transition for screen rotation animation to finish");
lumark588a3e82018-07-20 18:53:54 +0800468 return false;
469 }
Evan Rosky2289ba12018-11-19 18:28:18 -0800470 for (int i = 0; i < apps.size(); i++) {
471 AppWindowToken wtoken = apps.valueAt(i);
Adrian Roosb125e0b2019-10-02 14:55:14 +0200472 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
473 "Check opening app=%s: allDrawn=%b startingDisplayed=%b "
474 + "startingMoved=%b isRelaunching()=%b startingWindow=%s",
475 wtoken, wtoken.allDrawn, wtoken.startingDisplayed,
476 wtoken.startingMoved, wtoken.isRelaunching(),
477 wtoken.startingWindow);
lumark588a3e82018-07-20 18:53:54 +0800478
479
480 final boolean allDrawn = wtoken.allDrawn && !wtoken.isRelaunching();
481 if (!allDrawn && !wtoken.startingDisplayed && !wtoken.startingMoved) {
482 return false;
483 }
484 final int windowingMode = wtoken.getWindowingMode();
485 if (allDrawn) {
486 outReasons.put(windowingMode, APP_TRANSITION_WINDOWS_DRAWN);
487 } else {
488 outReasons.put(windowingMode,
chaviwa8f07a72019-05-01 16:25:39 -0700489 wtoken.mStartingData instanceof SplashScreenStartingData
lumark588a3e82018-07-20 18:53:54 +0800490 ? APP_TRANSITION_SPLASH_SCREEN
491 : APP_TRANSITION_SNAPSHOT);
492 }
493 }
494
495 // We also need to wait for the specs to be fetched, if needed.
496 if (mDisplayContent.mAppTransition.isFetchingAppTransitionsSpecs()) {
Adrian Roosb125e0b2019-10-02 14:55:14 +0200497 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "isFetchingAppTransitionSpecs=true");
lumark588a3e82018-07-20 18:53:54 +0800498 return false;
499 }
500
501 if (!mDisplayContent.mUnknownAppVisibilityController.allResolved()) {
Adrian Roosb125e0b2019-10-02 14:55:14 +0200502 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "unknownApps is not empty: %s",
503 mDisplayContent.mUnknownAppVisibilityController.getDebugMessage());
lumark588a3e82018-07-20 18:53:54 +0800504 return false;
505 }
506
507 // If the wallpaper is visible, we need to check it's ready too.
508 boolean wallpaperReady = !mWallpaperControllerLocked.isWallpaperVisible() ||
509 mWallpaperControllerLocked.wallpaperTransitionReady();
510 if (wallpaperReady) {
511 return true;
512 }
513 return false;
514 }
515 return true;
516 }
517
518 private int maybeUpdateTransitToWallpaper(int transit, boolean openingAppHasWallpaper,
519 boolean closingAppHasWallpaper) {
520 // Given no app transition pass it through instead of a wallpaper transition.
521 // Never convert the crashing transition.
522 // Never update the transition for the wallpaper if we are just docking from recents
Evan Roskyec9488c2019-03-01 19:32:12 -0800523 // Never convert a change transition since the top activity isn't changing and will likely
524 // still be above an opening wallpaper.
lumark588a3e82018-07-20 18:53:54 +0800525 if (transit == TRANSIT_NONE || transit == TRANSIT_CRASHING_ACTIVITY_CLOSE
Evan Roskyec9488c2019-03-01 19:32:12 -0800526 || transit == TRANSIT_DOCK_TASK_FROM_RECENTS
527 || AppTransition.isChangeTransit(transit)) {
lumark588a3e82018-07-20 18:53:54 +0800528 return transit;
529 }
530
531 final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget();
532 final boolean showWallpaper = wallpaperTarget != null
533 && (wallpaperTarget.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0;
534 // If wallpaper is animating or wallpaperTarget doesn't have SHOW_WALLPAPER flag set,
535 // don't consider upgrading to wallpaper transition.
536 final WindowState oldWallpaper =
537 (mWallpaperControllerLocked.isWallpaperTargetAnimating() || !showWallpaper)
538 ? null
539 : wallpaperTarget;
540 final ArraySet<AppWindowToken> openingApps = mDisplayContent.mOpeningApps;
541 final ArraySet<AppWindowToken> closingApps = mDisplayContent.mClosingApps;
542 final AppWindowToken topOpeningApp = getTopApp(mDisplayContent.mOpeningApps,
543 false /* ignoreHidden */);
544 final AppWindowToken topClosingApp = getTopApp(mDisplayContent.mClosingApps,
545 true /* ignoreHidden */);
546
547 boolean openingCanBeWallpaperTarget = canBeWallpaperTarget(openingApps);
Adrian Roosb125e0b2019-10-02 14:55:14 +0200548 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
549 "New wallpaper target=%s, oldWallpaper=%s, openingApps=%s, closingApps=%s",
550 wallpaperTarget, oldWallpaper, openingApps, closingApps);
lumark588a3e82018-07-20 18:53:54 +0800551
552 if (openingCanBeWallpaperTarget && transit == TRANSIT_KEYGUARD_GOING_AWAY) {
553 transit = TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
Adrian Roosb125e0b2019-10-02 14:55:14 +0200554 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
555 "New transit: %s", AppTransition.appTransitionToString(transit));
lumark588a3e82018-07-20 18:53:54 +0800556 }
557 // We never want to change from a Keyguard transit to a non-Keyguard transit, as our logic
558 // relies on the fact that we always execute a Keyguard transition after preparing one.
559 else if (!isKeyguardGoingAwayTransit(transit)) {
560 if (closingAppHasWallpaper && openingAppHasWallpaper) {
Adrian Roosb125e0b2019-10-02 14:55:14 +0200561 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Wallpaper animation!");
lumark588a3e82018-07-20 18:53:54 +0800562 switch (transit) {
563 case TRANSIT_ACTIVITY_OPEN:
564 case TRANSIT_TASK_OPEN:
565 case TRANSIT_TASK_TO_FRONT:
566 transit = TRANSIT_WALLPAPER_INTRA_OPEN;
567 break;
568 case TRANSIT_ACTIVITY_CLOSE:
569 case TRANSIT_TASK_CLOSE:
570 case TRANSIT_TASK_TO_BACK:
571 transit = TRANSIT_WALLPAPER_INTRA_CLOSE;
572 break;
573 }
Adrian Roosb125e0b2019-10-02 14:55:14 +0200574 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
575 "New transit: %s", AppTransition.appTransitionToString(transit));
lumark588a3e82018-07-20 18:53:54 +0800576 } else if (oldWallpaper != null && !mDisplayContent.mOpeningApps.isEmpty()
577 && !openingApps.contains(oldWallpaper.mAppToken)
578 && closingApps.contains(oldWallpaper.mAppToken)
579 && topClosingApp == oldWallpaper.mAppToken) {
580 // We are transitioning from an activity with a wallpaper to one without.
581 transit = TRANSIT_WALLPAPER_CLOSE;
Adrian Roosb125e0b2019-10-02 14:55:14 +0200582 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
583 "New transit away from wallpaper: %s",
584 AppTransition.appTransitionToString(transit));
lumark588a3e82018-07-20 18:53:54 +0800585 } else if (wallpaperTarget != null && wallpaperTarget.isVisibleLw()
586 && openingApps.contains(wallpaperTarget.mAppToken)
587 && topOpeningApp == wallpaperTarget.mAppToken
588 && transit != TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE) {
589 // We are transitioning from an activity without
590 // a wallpaper to now showing the wallpaper
591 transit = TRANSIT_WALLPAPER_OPEN;
Adrian Roosb125e0b2019-10-02 14:55:14 +0200592 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "New transit into wallpaper: %s",
593 AppTransition.appTransitionToString(transit));
lumark588a3e82018-07-20 18:53:54 +0800594 }
595 }
596 return transit;
597 }
598
599 /**
600 * There are cases where we open/close a new task/activity, but in reality only a translucent
601 * activity on top of existing activities is opening/closing. For that one, we have a different
602 * animation because non of the task/activity animations actually work well with translucent
603 * apps.
604 *
605 * @param transit The current transition type.
606 * @return The current transition type or
607 * {@link WindowManager#TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE}/
608 * {@link WindowManager#TRANSIT_TRANSLUCENT_ACTIVITY_OPEN} if appropriate for the
609 * situation.
610 */
611 @VisibleForTesting
612 int maybeUpdateTransitToTranslucentAnim(int transit) {
Evan Roskyec9488c2019-03-01 19:32:12 -0800613 if (AppTransition.isChangeTransit(transit)) {
614 // There's no special animation to handle change animations with translucent apps
615 return transit;
616 }
lumark588a3e82018-07-20 18:53:54 +0800617 final boolean taskOrActivity = AppTransition.isTaskTransit(transit)
618 || AppTransition.isActivityTransit(transit);
619 boolean allOpeningVisible = true;
620 boolean allTranslucentOpeningApps = !mDisplayContent.mOpeningApps.isEmpty();
621 for (int i = mDisplayContent.mOpeningApps.size() - 1; i >= 0; i--) {
622 final AppWindowToken token = mDisplayContent.mOpeningApps.valueAt(i);
623 if (!token.isVisible()) {
624 allOpeningVisible = false;
625 if (token.fillsParent()) {
626 allTranslucentOpeningApps = false;
627 }
628 }
629 }
630 boolean allTranslucentClosingApps = !mDisplayContent.mClosingApps.isEmpty();
631 for (int i = mDisplayContent.mClosingApps.size() - 1; i >= 0; i--) {
632 if (mDisplayContent.mClosingApps.valueAt(i).fillsParent()) {
633 allTranslucentClosingApps = false;
634 break;
635 }
636 }
637
638 if (taskOrActivity && allTranslucentClosingApps && allOpeningVisible) {
639 return TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE;
640 }
641 if (taskOrActivity && allTranslucentOpeningApps && mDisplayContent.mClosingApps.isEmpty()) {
642 return TRANSIT_TRANSLUCENT_ACTIVITY_OPEN;
643 }
644 return transit;
645 }
646
Evan Rosky7735d352019-03-18 17:27:27 -0700647 /**
648 * Identifies whether the current transition occurs within a single task or not. This is used
649 * to determine whether animations should be clipped to the task bounds instead of stack bounds.
650 */
651 @VisibleForTesting
652 boolean isTransitWithinTask(int transit, Task task) {
653 if (task == null
654 || !mDisplayContent.mChangingApps.isEmpty()) {
655 // if there is no task, then we can't constrain to the task.
656 // if anything is changing, it can animate outside its task.
657 return false;
658 }
659 if (!(transit == TRANSIT_ACTIVITY_OPEN
660 || transit == TRANSIT_ACTIVITY_CLOSE
661 || transit == TRANSIT_ACTIVITY_RELAUNCH)) {
662 // only activity-level transitions will be within-task.
663 return false;
664 }
665 // check that all components are in the task.
666 for (AppWindowToken activity : mDisplayContent.mOpeningApps) {
667 Task activityTask = activity.getTask();
668 if (activityTask != task) {
669 return false;
670 }
671 }
672 for (AppWindowToken activity : mDisplayContent.mClosingApps) {
673 if (activity.getTask() != task) {
674 return false;
675 }
676 }
677 return true;
678 }
679
lumark588a3e82018-07-20 18:53:54 +0800680 private boolean canBeWallpaperTarget(ArraySet<AppWindowToken> apps) {
681 for (int i = apps.size() - 1; i >= 0; i--) {
682 if (apps.valueAt(i).windowsCanBeWallpaperTarget()) {
683 return true;
684 }
685 }
686 return false;
687 }
688
689 /**
690 * Finds the top app in a list of apps, using its {@link AppWindowToken#getPrefixOrderIndex} to
691 * compare z-order.
692 *
693 * @param apps The list of apps to search.
694 * @param ignoreHidden If set to true, ignores apps that are {@link AppWindowToken#isHidden}.
695 * @return The top {@link AppWindowToken}.
696 */
697 private AppWindowToken getTopApp(ArraySet<AppWindowToken> apps, boolean ignoreHidden) {
698 int topPrefixOrderIndex = Integer.MIN_VALUE;
699 AppWindowToken topApp = null;
700 for (int i = apps.size() - 1; i >= 0; i--) {
701 final AppWindowToken app = apps.valueAt(i);
702 if (ignoreHidden && app.isHidden()) {
703 continue;
704 }
705 final int prefixOrderIndex = app.getPrefixOrderIndex();
706 if (prefixOrderIndex > topPrefixOrderIndex) {
707 topPrefixOrderIndex = prefixOrderIndex;
708 topApp = app;
709 }
710 }
711 return topApp;
712 }
713
714 private void processApplicationsAnimatingInPlace(int transit) {
715 if (transit == TRANSIT_TASK_IN_PLACE) {
716 // Find the focused window
717 final WindowState win = mDisplayContent.findFocusedWindow();
718 if (win != null) {
719 final AppWindowToken wtoken = win.mAppToken;
Adrian Roosb125e0b2019-10-02 14:55:14 +0200720 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now animating app in place %s", wtoken);
lumark588a3e82018-07-20 18:53:54 +0800721 wtoken.cancelAnimation();
722 wtoken.applyAnimationLocked(null, transit, false, false);
723 wtoken.updateReportedVisibilityLocked();
724 wtoken.showAllWindowsLocked();
725 }
726 }
727 }
728}