blob: 75e34fb0d453b97897e1f4f539ec63e2f2ad9932 [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;
26import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
27import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
28import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
29import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
30import static android.view.WindowManager.TRANSIT_NONE;
31import static android.view.WindowManager.TRANSIT_TASK_CLOSE;
32import static android.view.WindowManager.TRANSIT_TASK_IN_PLACE;
33import static android.view.WindowManager.TRANSIT_TASK_OPEN;
34import static android.view.WindowManager.TRANSIT_TASK_TO_BACK;
35import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
36import static android.view.WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE;
37import static android.view.WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_OPEN;
38import static android.view.WindowManager.TRANSIT_WALLPAPER_CLOSE;
39import static android.view.WindowManager.TRANSIT_WALLPAPER_INTRA_CLOSE;
40import static android.view.WindowManager.TRANSIT_WALLPAPER_INTRA_OPEN;
41import static android.view.WindowManager.TRANSIT_WALLPAPER_OPEN;
42
43import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
44import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
45import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_SNAPSHOT;
46import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_SPLASH_SCREEN;
47import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_WINDOWS_DRAWN;
48import static com.android.server.wm.AppTransition.isKeyguardGoingAwayTransit;
49import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
50import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
51import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
52import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
lumark588a3e82018-07-20 18:53:54 +080053
Yunfan Chencafc7062019-01-22 17:21:32 +090054import android.os.SystemClock;
lumark588a3e82018-07-20 18:53:54 +080055import android.os.Trace;
56import android.util.ArraySet;
57import android.util.Slog;
58import android.util.SparseIntArray;
59import android.view.Display;
60import android.view.RemoteAnimationAdapter;
61import android.view.RemoteAnimationDefinition;
62import android.view.WindowManager;
63import android.view.WindowManager.LayoutParams;
64import android.view.animation.Animation;
65
66import com.android.internal.annotations.VisibleForTesting;
67
68import java.util.function.Predicate;
69
70
71/**
72 * Checks for app transition readiness, resolves animation attributes and performs visibility
73 * change for apps that animate as part of an app transition.
74 */
75public class AppTransitionController {
76 private static final String TAG = TAG_WITH_CLASS_NAME ? "AppTransitionController" : TAG_WM;
77 private final WindowManagerService mService;
78 private final DisplayContent mDisplayContent;
79 private final WallpaperController mWallpaperControllerLocked;
Evan Rosky966759f2019-01-15 10:33:58 -080080 private RemoteAnimationDefinition mRemoteAnimationDefinition = null;
lumark588a3e82018-07-20 18:53:54 +080081
82 private final SparseIntArray mTempTransitionReasons = new SparseIntArray();
83
84 AppTransitionController(WindowManagerService service, DisplayContent displayContent) {
85 mService = service;
86 mDisplayContent = displayContent;
wilsonshihc32538e2018-11-07 17:27:34 +080087 mWallpaperControllerLocked = mDisplayContent.mWallpaperController;
lumark588a3e82018-07-20 18:53:54 +080088 }
89
Evan Rosky966759f2019-01-15 10:33:58 -080090 void registerRemoteAnimations(RemoteAnimationDefinition definition) {
91 mRemoteAnimationDefinition = definition;
92 }
93
lumark588a3e82018-07-20 18:53:54 +080094 /**
95 * Handle application transition for given display.
96 */
97 void handleAppTransitionReady() {
Evan Rosky2289ba12018-11-19 18:28:18 -080098 mTempTransitionReasons.clear();
99 if (!transitionGoodToGo(mDisplayContent.mOpeningApps, mTempTransitionReasons)
100 || !transitionGoodToGo(mDisplayContent.mChangingApps, mTempTransitionReasons)) {
lumark588a3e82018-07-20 18:53:54 +0800101 return;
102 }
103 Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "AppTransitionReady");
104
105 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
Tiger Huang7c610aa2018-10-27 00:01:01 +0800106 final AppTransition appTransition = mDisplayContent.mAppTransition;
107 int transit = appTransition.getAppTransition();
lumark588a3e82018-07-20 18:53:54 +0800108 if (mDisplayContent.mSkipAppTransitionAnimation && !isKeyguardGoingAwayTransit(transit)) {
109 transit = WindowManager.TRANSIT_UNSET;
110 }
111 mDisplayContent.mSkipAppTransitionAnimation = false;
112 mDisplayContent.mNoAnimationNotifyOnTransitionFinished.clear();
113
Tiger Huang7c610aa2018-10-27 00:01:01 +0800114 appTransition.removeAppTransitionTimeoutCallbacks();
lumark588a3e82018-07-20 18:53:54 +0800115
wilsonshihc32538e2018-11-07 17:27:34 +0800116 mDisplayContent.mWallpaperMayChange = false;
lumark588a3e82018-07-20 18:53:54 +0800117
Evan Rosky2289ba12018-11-19 18:28:18 -0800118 int appCount = mDisplayContent.mOpeningApps.size();
119 for (int i = 0; i < appCount; ++i) {
lumark588a3e82018-07-20 18:53:54 +0800120 // Clearing the mAnimatingExit flag before entering animation. It's set to true if app
121 // window is removed, or window relayout to invisible. This also affects window
122 // visibility. We need to clear it *before* maybeUpdateTransitToWallpaper() as the
123 // transition selection depends on wallpaper target visibility.
Evan Rosky2289ba12018-11-19 18:28:18 -0800124 mDisplayContent.mOpeningApps.valueAtUnchecked(i).clearAnimatingFlags();
125 }
126 appCount = mDisplayContent.mChangingApps.size();
127 for (int i = 0; i < appCount; ++i) {
128 // Clearing for same reason as above.
129 mDisplayContent.mChangingApps.valueAtUnchecked(i).clearAnimatingFlags();
lumark588a3e82018-07-20 18:53:54 +0800130 }
131
132 // Adjust wallpaper before we pull the lower/upper target, since pending changes
133 // (like the clearAnimatingFlags() above) might affect wallpaper target result.
134 // Or, the opening app window should be a wallpaper target.
wilsonshihc32538e2018-11-07 17:27:34 +0800135 mWallpaperControllerLocked.adjustWallpaperWindowsForAppTransitionIfNeeded(
Evan Rosky2289ba12018-11-19 18:28:18 -0800136 mDisplayContent.mOpeningApps, mDisplayContent.mChangingApps);
lumark588a3e82018-07-20 18:53:54 +0800137
138 // Determine if closing and opening app token sets are wallpaper targets, in which case
139 // special animations are needed.
140 final boolean hasWallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget() != null;
141 final boolean openingAppHasWallpaper = canBeWallpaperTarget(mDisplayContent.mOpeningApps)
142 && hasWallpaperTarget;
143 final boolean closingAppHasWallpaper = canBeWallpaperTarget(mDisplayContent.mClosingApps)
144 && hasWallpaperTarget;
145
146 transit = maybeUpdateTransitToTranslucentAnim(transit);
147 transit = maybeUpdateTransitToWallpaper(transit, openingAppHasWallpaper,
148 closingAppHasWallpaper);
149
150 // Find the layout params of the top-most application window in the tokens, which is
151 // what will control the animation theme. If all closing windows are obscured, then there is
152 // no need to do an animation. This is the case, for example, when this transition is being
153 // done behind a dream window.
154 final ArraySet<Integer> activityTypes = collectActivityTypes(mDisplayContent.mOpeningApps,
Evan Rosky2289ba12018-11-19 18:28:18 -0800155 mDisplayContent.mClosingApps, mDisplayContent.mChangingApps);
Tiger Huang7c610aa2018-10-27 00:01:01 +0800156 final boolean allowAnimations = mDisplayContent.getDisplayPolicy().allowAppAnimationsLw();
lumark588a3e82018-07-20 18:53:54 +0800157 final AppWindowToken animLpToken = allowAnimations
158 ? findAnimLayoutParamsToken(transit, activityTypes)
159 : null;
160 final AppWindowToken topOpeningApp = allowAnimations
161 ? getTopApp(mDisplayContent.mOpeningApps, false /* ignoreHidden */)
162 : null;
163 final AppWindowToken topClosingApp = allowAnimations
164 ? getTopApp(mDisplayContent.mClosingApps, false /* ignoreHidden */)
165 : null;
Evan Rosky2289ba12018-11-19 18:28:18 -0800166 final AppWindowToken topChangingApp = allowAnimations
167 ? getTopApp(mDisplayContent.mChangingApps, false /* ignoreHidden */)
168 : null;
lumark588a3e82018-07-20 18:53:54 +0800169 final WindowManager.LayoutParams animLp = getAnimLp(animLpToken);
170 overrideWithRemoteAnimationIfSet(animLpToken, transit, activityTypes);
171
172 final boolean voiceInteraction = containsVoiceInteraction(mDisplayContent.mOpeningApps)
Evan Rosky2289ba12018-11-19 18:28:18 -0800173 || containsVoiceInteraction(mDisplayContent.mOpeningApps)
174 || containsVoiceInteraction(mDisplayContent.mChangingApps);
lumark588a3e82018-07-20 18:53:54 +0800175
176 final int layoutRedo;
177 mService.mSurfaceAnimationRunner.deferStartingAnimations();
178 try {
179 processApplicationsAnimatingInPlace(transit);
180
181 handleClosingApps(transit, animLp, voiceInteraction);
182 handleOpeningApps(transit, animLp, voiceInteraction);
Evan Rosky2289ba12018-11-19 18:28:18 -0800183 handleChangingApps(transit, animLp, voiceInteraction);
lumark588a3e82018-07-20 18:53:54 +0800184
Tiger Huang7c610aa2018-10-27 00:01:01 +0800185 appTransition.setLastAppTransition(transit, topOpeningApp,
Evan Rosky2289ba12018-11-19 18:28:18 -0800186 topClosingApp, topChangingApp);
lumark588a3e82018-07-20 18:53:54 +0800187
Tiger Huang7c610aa2018-10-27 00:01:01 +0800188 final int flags = appTransition.getTransitFlags();
189 layoutRedo = appTransition.goodToGo(transit, topOpeningApp,
Evan Rosky2289ba12018-11-19 18:28:18 -0800190 mDisplayContent.mOpeningApps);
lumark588a3e82018-07-20 18:53:54 +0800191 handleNonAppWindowsInTransition(transit, flags);
Tiger Huang7c610aa2018-10-27 00:01:01 +0800192 appTransition.postAnimationCallback();
193 appTransition.clear();
lumark588a3e82018-07-20 18:53:54 +0800194 } finally {
195 mService.mSurfaceAnimationRunner.continueStartingAnimations();
196 }
197
198 mService.mTaskSnapshotController.onTransitionStarting(mDisplayContent);
199
200 mDisplayContent.mOpeningApps.clear();
201 mDisplayContent.mClosingApps.clear();
Evan Rosky2289ba12018-11-19 18:28:18 -0800202 mDisplayContent.mChangingApps.clear();
lumark588a3e82018-07-20 18:53:54 +0800203 mDisplayContent.mUnknownAppVisibilityController.clear();
204
205 // This has changed the visibility of windows, so perform
206 // a new layout to get them all up-to-date.
207 mDisplayContent.setLayoutNeeded();
208
209 mDisplayContent.computeImeTarget(true /* updateImeTarget */);
210
Yunfan Chencafc7062019-01-22 17:21:32 +0900211 mService.mAtmInternal.notifyAppTransitionStarting(mTempTransitionReasons.clone(),
212 SystemClock.uptimeMillis());
lumark588a3e82018-07-20 18:53:54 +0800213
214 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
215
216 mDisplayContent.pendingLayoutChanges |=
217 layoutRedo | FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG;
218 }
219
220 private static WindowManager.LayoutParams getAnimLp(AppWindowToken wtoken) {
221 final WindowState mainWindow = wtoken != null ? wtoken.findMainWindow() : null;
222 return mainWindow != null ? mainWindow.mAttrs : null;
223 }
224
Evan Rosky966759f2019-01-15 10:33:58 -0800225 RemoteAnimationAdapter getRemoteAnimationOverride(AppWindowToken animLpToken, int transit,
226 ArraySet<Integer> activityTypes) {
227 final RemoteAnimationDefinition definition = animLpToken.getRemoteAnimationDefinition();
228 if (definition != null) {
229 final RemoteAnimationAdapter adapter = definition.getAdapter(transit, activityTypes);
230 if (adapter != null) {
231 return adapter;
232 }
233 }
234 if (mRemoteAnimationDefinition == null) {
235 return null;
236 }
237 return mRemoteAnimationDefinition.getAdapter(transit, activityTypes);
238 }
239
lumark588a3e82018-07-20 18:53:54 +0800240 /**
241 * Overrides the pending transition with the remote animation defined for the transition in the
242 * set of defined remote animations in the app window token.
243 */
244 private void overrideWithRemoteAnimationIfSet(AppWindowToken animLpToken, int transit,
245 ArraySet<Integer> activityTypes) {
246 if (transit == TRANSIT_CRASHING_ACTIVITY_CLOSE) {
247 // The crash transition has higher priority than any involved remote animations.
248 return;
249 }
250 if (animLpToken == null) {
251 return;
252 }
Evan Rosky966759f2019-01-15 10:33:58 -0800253 final RemoteAnimationAdapter adapter =
254 getRemoteAnimationOverride(animLpToken, transit, activityTypes);
lumark588a3e82018-07-20 18:53:54 +0800255 if (adapter != null) {
256 animLpToken.getDisplayContent().mAppTransition.overridePendingAppTransitionRemote(
257 adapter);
258 }
259 }
260
261 /**
262 * @return The window token that determines the animation theme.
263 */
264 private AppWindowToken findAnimLayoutParamsToken(@WindowManager.TransitionType int transit,
265 ArraySet<Integer> activityTypes) {
266 AppWindowToken result;
267 final ArraySet<AppWindowToken> closingApps = mDisplayContent.mClosingApps;
268 final ArraySet<AppWindowToken> openingApps = mDisplayContent.mOpeningApps;
Evan Rosky2289ba12018-11-19 18:28:18 -0800269 final ArraySet<AppWindowToken> changingApps = mDisplayContent.mChangingApps;
lumark588a3e82018-07-20 18:53:54 +0800270
271 // Remote animations always win, but fullscreen tokens override non-fullscreen tokens.
Evan Rosky2289ba12018-11-19 18:28:18 -0800272 result = lookForHighestTokenWithFilter(closingApps, openingApps, changingApps,
lumark588a3e82018-07-20 18:53:54 +0800273 w -> w.getRemoteAnimationDefinition() != null
274 && w.getRemoteAnimationDefinition().hasTransition(transit, activityTypes));
275 if (result != null) {
276 return result;
277 }
Evan Rosky2289ba12018-11-19 18:28:18 -0800278 result = lookForHighestTokenWithFilter(closingApps, openingApps, changingApps,
lumark588a3e82018-07-20 18:53:54 +0800279 w -> w.fillsParent() && w.findMainWindow() != null);
280 if (result != null) {
281 return result;
282 }
Evan Rosky2289ba12018-11-19 18:28:18 -0800283 return lookForHighestTokenWithFilter(closingApps, openingApps, changingApps,
lumark588a3e82018-07-20 18:53:54 +0800284 w -> w.findMainWindow() != null);
285 }
286
287 /**
Tiger Huang7c610aa2018-10-27 00:01:01 +0800288 * @return The set of {@link android.app.WindowConfiguration.ActivityType}s contained in the set
Evan Rosky2289ba12018-11-19 18:28:18 -0800289 * of apps in {@code array1}, {@code array2}, and {@code array3}.
lumark588a3e82018-07-20 18:53:54 +0800290 */
291 private static ArraySet<Integer> collectActivityTypes(ArraySet<AppWindowToken> array1,
Evan Rosky2289ba12018-11-19 18:28:18 -0800292 ArraySet<AppWindowToken> array2, ArraySet<AppWindowToken> array3) {
lumark588a3e82018-07-20 18:53:54 +0800293 final ArraySet<Integer> result = new ArraySet<>();
294 for (int i = array1.size() - 1; i >= 0; i--) {
295 result.add(array1.valueAt(i).getActivityType());
296 }
297 for (int i = array2.size() - 1; i >= 0; i--) {
298 result.add(array2.valueAt(i).getActivityType());
299 }
Evan Rosky2289ba12018-11-19 18:28:18 -0800300 for (int i = array3.size() - 1; i >= 0; i--) {
301 result.add(array3.valueAt(i).getActivityType());
302 }
lumark588a3e82018-07-20 18:53:54 +0800303 return result;
304 }
305
306 private static AppWindowToken lookForHighestTokenWithFilter(ArraySet<AppWindowToken> array1,
Evan Rosky2289ba12018-11-19 18:28:18 -0800307 ArraySet<AppWindowToken> array2, ArraySet<AppWindowToken> array3,
308 Predicate<AppWindowToken> filter) {
309 final int array2base = array1.size();
310 final int array3base = array2.size() + array2base;
311 final int count = array3base + array3.size();
lumark588a3e82018-07-20 18:53:54 +0800312 int bestPrefixOrderIndex = Integer.MIN_VALUE;
313 AppWindowToken bestToken = null;
314 for (int i = 0; i < count; i++) {
Evan Rosky2289ba12018-11-19 18:28:18 -0800315 final AppWindowToken wtoken = i < array2base
lumark588a3e82018-07-20 18:53:54 +0800316 ? array1.valueAt(i)
Evan Rosky2289ba12018-11-19 18:28:18 -0800317 : (i < array3base
318 ? array2.valueAt(i - array2base)
319 : array3.valueAt(i - array3base));
lumark588a3e82018-07-20 18:53:54 +0800320 final int prefixOrderIndex = wtoken.getPrefixOrderIndex();
321 if (filter.test(wtoken) && prefixOrderIndex > bestPrefixOrderIndex) {
322 bestPrefixOrderIndex = prefixOrderIndex;
323 bestToken = wtoken;
324 }
325 }
326 return bestToken;
327 }
328
329 private boolean containsVoiceInteraction(ArraySet<AppWindowToken> apps) {
330 for (int i = apps.size() - 1; i >= 0; i--) {
331 if (apps.valueAt(i).mVoiceInteraction) {
332 return true;
333 }
334 }
335 return false;
336 }
337
338 private void handleOpeningApps(int transit, LayoutParams animLp, boolean voiceInteraction) {
339 final ArraySet<AppWindowToken> openingApps = mDisplayContent.mOpeningApps;
340 final int appsCount = openingApps.size();
341 for (int i = 0; i < appsCount; i++) {
342 AppWindowToken wtoken = openingApps.valueAt(i);
343 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken);
344
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800345 if (!wtoken.commitVisibility(animLp, true, transit, false, voiceInteraction)) {
lumark588a3e82018-07-20 18:53:54 +0800346 // This token isn't going to be animating. Add it to the list of tokens to
347 // be notified of app transition complete since the notification will not be
348 // sent be the app window animator.
349 mDisplayContent.mNoAnimationNotifyOnTransitionFinished.add(wtoken.token);
350 }
351 wtoken.updateReportedVisibilityLocked();
352 wtoken.waitingToShow = false;
353 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
354 ">>> OPEN TRANSACTION handleAppTransitionReady()");
355 mService.openSurfaceTransaction();
356 try {
357 wtoken.showAllWindowsLocked();
358 } finally {
359 mService.closeSurfaceTransaction("handleAppTransitionReady");
360 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
361 "<<< CLOSE TRANSACTION handleAppTransitionReady()");
362 }
363
364 if (mDisplayContent.mAppTransition.isNextAppTransitionThumbnailUp()) {
365 wtoken.attachThumbnailAnimation();
366 } else if (mDisplayContent.mAppTransition.isNextAppTransitionOpenCrossProfileApps()) {
367 wtoken.attachCrossProfileAppsThumbnailAnimation();
368 }
369 }
370 }
371
372 private void handleClosingApps(int transit, LayoutParams animLp, boolean voiceInteraction) {
373 final ArraySet<AppWindowToken> closingApps = mDisplayContent.mClosingApps;
374 final int appsCount = closingApps.size();
375 for (int i = 0; i < appsCount; i++) {
376 AppWindowToken wtoken = closingApps.valueAt(i);
377
378 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now closing app " + wtoken);
379 // TODO: Do we need to add to mNoAnimationNotifyOnTransitionFinished like above if not
380 // animating?
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800381 wtoken.commitVisibility(animLp, false, transit, false, voiceInteraction);
lumark588a3e82018-07-20 18:53:54 +0800382 wtoken.updateReportedVisibilityLocked();
383 // Force the allDrawn flag, because we want to start
384 // this guy's animations regardless of whether it's
385 // gotten drawn.
386 wtoken.allDrawn = true;
387 wtoken.deferClearAllDrawn = false;
388 // Ensure that apps that are mid-starting are also scheduled to have their
389 // starting windows removed after the animation is complete
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800390 if (wtoken.startingWindow != null && !wtoken.startingWindow.mAnimatingExit) {
391 wtoken.removeStartingWindow();
lumark588a3e82018-07-20 18:53:54 +0800392 }
393
394 if (mDisplayContent.mAppTransition.isNextAppTransitionThumbnailDown()) {
395 wtoken.attachThumbnailAnimation();
396 }
397 }
398 }
399
Evan Rosky2289ba12018-11-19 18:28:18 -0800400 private void handleChangingApps(int transit, LayoutParams animLp, boolean voiceInteraction) {
401 final ArraySet<AppWindowToken> apps = mDisplayContent.mChangingApps;
402 final int appsCount = apps.size();
403 for (int i = 0; i < appsCount; i++) {
404 AppWindowToken wtoken = apps.valueAt(i);
405 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now changing app" + wtoken);
406 wtoken.cancelAnimationOnly();
407 wtoken.applyAnimationLocked(null, transit, true, false);
408 wtoken.updateReportedVisibilityLocked();
409 mService.openSurfaceTransaction();
410 try {
411 wtoken.showAllWindowsLocked();
412 } finally {
413 mService.closeSurfaceTransaction("handleChangingApps");
414 }
415 }
416 }
417
lumark588a3e82018-07-20 18:53:54 +0800418 private void handleNonAppWindowsInTransition(int transit, int flags) {
419 if (transit == TRANSIT_KEYGUARD_GOING_AWAY) {
420 if ((flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0
421 && (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION) == 0) {
422 Animation anim = mService.mPolicy.createKeyguardWallpaperExit(
423 (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0);
424 if (anim != null) {
425 mDisplayContent.mWallpaperController.startWallpaperAnimation(anim);
426 }
427 }
428 }
429 if (transit == TRANSIT_KEYGUARD_GOING_AWAY
430 || transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER) {
431 mDisplayContent.startKeyguardExitOnNonAppWindows(
432 transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER,
433 (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0);
434 }
435 }
436
Evan Rosky2289ba12018-11-19 18:28:18 -0800437 private boolean transitionGoodToGo(ArraySet<AppWindowToken> apps, SparseIntArray outReasons) {
lumark588a3e82018-07-20 18:53:54 +0800438 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
Evan Rosky2289ba12018-11-19 18:28:18 -0800439 "Checking " + apps.size() + " opening apps (frozen="
lumark588a3e82018-07-20 18:53:54 +0800440 + mService.mDisplayFrozen + " timeout="
441 + mDisplayContent.mAppTransition.isTimeout() + ")...");
442 final ScreenRotationAnimation screenRotationAnimation =
443 mService.mAnimator.getScreenRotationAnimationLocked(
444 Display.DEFAULT_DISPLAY);
445
lumark588a3e82018-07-20 18:53:54 +0800446 if (!mDisplayContent.mAppTransition.isTimeout()) {
447 // Imagine the case where we are changing orientation due to an app transition, but a
448 // previous orientation change is still in progress. We won't process the orientation
449 // change for our transition because we need to wait for the rotation animation to
450 // finish.
451 // If we start the app transition at this point, we will interrupt it halfway with a
452 // new rotation animation after the old one finally finishes. It's better to defer the
453 // app transition.
454 if (screenRotationAnimation != null && screenRotationAnimation.isAnimating() &&
455 mService.getDefaultDisplayContentLocked().rotationNeedsUpdate()) {
456 if (DEBUG_APP_TRANSITIONS) {
457 Slog.v(TAG, "Delaying app transition for screen rotation animation to finish");
458 }
459 return false;
460 }
Evan Rosky2289ba12018-11-19 18:28:18 -0800461 for (int i = 0; i < apps.size(); i++) {
462 AppWindowToken wtoken = apps.valueAt(i);
lumark588a3e82018-07-20 18:53:54 +0800463 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
464 "Check opening app=" + wtoken + ": allDrawn="
465 + wtoken.allDrawn + " startingDisplayed="
466 + wtoken.startingDisplayed + " startingMoved="
467 + wtoken.startingMoved + " isRelaunching()="
468 + wtoken.isRelaunching() + " startingWindow="
469 + wtoken.startingWindow);
470
471
472 final boolean allDrawn = wtoken.allDrawn && !wtoken.isRelaunching();
473 if (!allDrawn && !wtoken.startingDisplayed && !wtoken.startingMoved) {
474 return false;
475 }
476 final int windowingMode = wtoken.getWindowingMode();
477 if (allDrawn) {
478 outReasons.put(windowingMode, APP_TRANSITION_WINDOWS_DRAWN);
479 } else {
480 outReasons.put(windowingMode,
481 wtoken.startingData instanceof SplashScreenStartingData
482 ? APP_TRANSITION_SPLASH_SCREEN
483 : APP_TRANSITION_SNAPSHOT);
484 }
485 }
486
487 // We also need to wait for the specs to be fetched, if needed.
488 if (mDisplayContent.mAppTransition.isFetchingAppTransitionsSpecs()) {
489 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "isFetchingAppTransitionSpecs=true");
490 return false;
491 }
492
493 if (!mDisplayContent.mUnknownAppVisibilityController.allResolved()) {
494 if (DEBUG_APP_TRANSITIONS) {
495 Slog.v(TAG, "unknownApps is not empty: "
496 + mDisplayContent.mUnknownAppVisibilityController.getDebugMessage());
497 }
498 return false;
499 }
500
501 // If the wallpaper is visible, we need to check it's ready too.
502 boolean wallpaperReady = !mWallpaperControllerLocked.isWallpaperVisible() ||
503 mWallpaperControllerLocked.wallpaperTransitionReady();
504 if (wallpaperReady) {
505 return true;
506 }
507 return false;
508 }
509 return true;
510 }
511
512 private int maybeUpdateTransitToWallpaper(int transit, boolean openingAppHasWallpaper,
513 boolean closingAppHasWallpaper) {
514 // Given no app transition pass it through instead of a wallpaper transition.
515 // Never convert the crashing transition.
516 // Never update the transition for the wallpaper if we are just docking from recents
Evan Roskyec9488c2019-03-01 19:32:12 -0800517 // Never convert a change transition since the top activity isn't changing and will likely
518 // still be above an opening wallpaper.
lumark588a3e82018-07-20 18:53:54 +0800519 if (transit == TRANSIT_NONE || transit == TRANSIT_CRASHING_ACTIVITY_CLOSE
Evan Roskyec9488c2019-03-01 19:32:12 -0800520 || transit == TRANSIT_DOCK_TASK_FROM_RECENTS
521 || AppTransition.isChangeTransit(transit)) {
lumark588a3e82018-07-20 18:53:54 +0800522 return transit;
523 }
524
525 final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget();
526 final boolean showWallpaper = wallpaperTarget != null
527 && (wallpaperTarget.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0;
528 // If wallpaper is animating or wallpaperTarget doesn't have SHOW_WALLPAPER flag set,
529 // don't consider upgrading to wallpaper transition.
530 final WindowState oldWallpaper =
531 (mWallpaperControllerLocked.isWallpaperTargetAnimating() || !showWallpaper)
532 ? null
533 : wallpaperTarget;
534 final ArraySet<AppWindowToken> openingApps = mDisplayContent.mOpeningApps;
535 final ArraySet<AppWindowToken> closingApps = mDisplayContent.mClosingApps;
536 final AppWindowToken topOpeningApp = getTopApp(mDisplayContent.mOpeningApps,
537 false /* ignoreHidden */);
538 final AppWindowToken topClosingApp = getTopApp(mDisplayContent.mClosingApps,
539 true /* ignoreHidden */);
540
541 boolean openingCanBeWallpaperTarget = canBeWallpaperTarget(openingApps);
542 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
543 "New wallpaper target=" + wallpaperTarget
544 + ", oldWallpaper=" + oldWallpaper
545 + ", openingApps=" + openingApps
546 + ", closingApps=" + closingApps);
547
548 if (openingCanBeWallpaperTarget && transit == TRANSIT_KEYGUARD_GOING_AWAY) {
549 transit = TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
550 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
551 "New transit: " + AppTransition.appTransitionToString(transit));
552 }
553 // We never want to change from a Keyguard transit to a non-Keyguard transit, as our logic
554 // relies on the fact that we always execute a Keyguard transition after preparing one.
555 else if (!isKeyguardGoingAwayTransit(transit)) {
556 if (closingAppHasWallpaper && openingAppHasWallpaper) {
557 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Wallpaper animation!");
558 switch (transit) {
559 case TRANSIT_ACTIVITY_OPEN:
560 case TRANSIT_TASK_OPEN:
561 case TRANSIT_TASK_TO_FRONT:
562 transit = TRANSIT_WALLPAPER_INTRA_OPEN;
563 break;
564 case TRANSIT_ACTIVITY_CLOSE:
565 case TRANSIT_TASK_CLOSE:
566 case TRANSIT_TASK_TO_BACK:
567 transit = TRANSIT_WALLPAPER_INTRA_CLOSE;
568 break;
569 }
570 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
571 "New transit: " + AppTransition.appTransitionToString(transit));
572 } else if (oldWallpaper != null && !mDisplayContent.mOpeningApps.isEmpty()
573 && !openingApps.contains(oldWallpaper.mAppToken)
574 && closingApps.contains(oldWallpaper.mAppToken)
575 && topClosingApp == oldWallpaper.mAppToken) {
576 // We are transitioning from an activity with a wallpaper to one without.
577 transit = TRANSIT_WALLPAPER_CLOSE;
578 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit away from wallpaper: "
579 + AppTransition.appTransitionToString(transit));
580 } else if (wallpaperTarget != null && wallpaperTarget.isVisibleLw()
581 && openingApps.contains(wallpaperTarget.mAppToken)
582 && topOpeningApp == wallpaperTarget.mAppToken
583 && transit != TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE) {
584 // We are transitioning from an activity without
585 // a wallpaper to now showing the wallpaper
586 transit = TRANSIT_WALLPAPER_OPEN;
587 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit into wallpaper: "
588 + AppTransition.appTransitionToString(transit));
589 }
590 }
591 return transit;
592 }
593
594 /**
595 * There are cases where we open/close a new task/activity, but in reality only a translucent
596 * activity on top of existing activities is opening/closing. For that one, we have a different
597 * animation because non of the task/activity animations actually work well with translucent
598 * apps.
599 *
600 * @param transit The current transition type.
601 * @return The current transition type or
602 * {@link WindowManager#TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE}/
603 * {@link WindowManager#TRANSIT_TRANSLUCENT_ACTIVITY_OPEN} if appropriate for the
604 * situation.
605 */
606 @VisibleForTesting
607 int maybeUpdateTransitToTranslucentAnim(int transit) {
Evan Roskyec9488c2019-03-01 19:32:12 -0800608 if (AppTransition.isChangeTransit(transit)) {
609 // There's no special animation to handle change animations with translucent apps
610 return transit;
611 }
lumark588a3e82018-07-20 18:53:54 +0800612 final boolean taskOrActivity = AppTransition.isTaskTransit(transit)
613 || AppTransition.isActivityTransit(transit);
614 boolean allOpeningVisible = true;
615 boolean allTranslucentOpeningApps = !mDisplayContent.mOpeningApps.isEmpty();
616 for (int i = mDisplayContent.mOpeningApps.size() - 1; i >= 0; i--) {
617 final AppWindowToken token = mDisplayContent.mOpeningApps.valueAt(i);
618 if (!token.isVisible()) {
619 allOpeningVisible = false;
620 if (token.fillsParent()) {
621 allTranslucentOpeningApps = false;
622 }
623 }
624 }
625 boolean allTranslucentClosingApps = !mDisplayContent.mClosingApps.isEmpty();
626 for (int i = mDisplayContent.mClosingApps.size() - 1; i >= 0; i--) {
627 if (mDisplayContent.mClosingApps.valueAt(i).fillsParent()) {
628 allTranslucentClosingApps = false;
629 break;
630 }
631 }
632
633 if (taskOrActivity && allTranslucentClosingApps && allOpeningVisible) {
634 return TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE;
635 }
636 if (taskOrActivity && allTranslucentOpeningApps && mDisplayContent.mClosingApps.isEmpty()) {
637 return TRANSIT_TRANSLUCENT_ACTIVITY_OPEN;
638 }
639 return transit;
640 }
641
Evan Rosky7735d352019-03-18 17:27:27 -0700642 /**
643 * Identifies whether the current transition occurs within a single task or not. This is used
644 * to determine whether animations should be clipped to the task bounds instead of stack bounds.
645 */
646 @VisibleForTesting
647 boolean isTransitWithinTask(int transit, Task task) {
648 if (task == null
649 || !mDisplayContent.mChangingApps.isEmpty()) {
650 // if there is no task, then we can't constrain to the task.
651 // if anything is changing, it can animate outside its task.
652 return false;
653 }
654 if (!(transit == TRANSIT_ACTIVITY_OPEN
655 || transit == TRANSIT_ACTIVITY_CLOSE
656 || transit == TRANSIT_ACTIVITY_RELAUNCH)) {
657 // only activity-level transitions will be within-task.
658 return false;
659 }
660 // check that all components are in the task.
661 for (AppWindowToken activity : mDisplayContent.mOpeningApps) {
662 Task activityTask = activity.getTask();
663 if (activityTask != task) {
664 return false;
665 }
666 }
667 for (AppWindowToken activity : mDisplayContent.mClosingApps) {
668 if (activity.getTask() != task) {
669 return false;
670 }
671 }
672 return true;
673 }
674
lumark588a3e82018-07-20 18:53:54 +0800675 private boolean canBeWallpaperTarget(ArraySet<AppWindowToken> apps) {
676 for (int i = apps.size() - 1; i >= 0; i--) {
677 if (apps.valueAt(i).windowsCanBeWallpaperTarget()) {
678 return true;
679 }
680 }
681 return false;
682 }
683
684 /**
685 * Finds the top app in a list of apps, using its {@link AppWindowToken#getPrefixOrderIndex} to
686 * compare z-order.
687 *
688 * @param apps The list of apps to search.
689 * @param ignoreHidden If set to true, ignores apps that are {@link AppWindowToken#isHidden}.
690 * @return The top {@link AppWindowToken}.
691 */
692 private AppWindowToken getTopApp(ArraySet<AppWindowToken> apps, boolean ignoreHidden) {
693 int topPrefixOrderIndex = Integer.MIN_VALUE;
694 AppWindowToken topApp = null;
695 for (int i = apps.size() - 1; i >= 0; i--) {
696 final AppWindowToken app = apps.valueAt(i);
697 if (ignoreHidden && app.isHidden()) {
698 continue;
699 }
700 final int prefixOrderIndex = app.getPrefixOrderIndex();
701 if (prefixOrderIndex > topPrefixOrderIndex) {
702 topPrefixOrderIndex = prefixOrderIndex;
703 topApp = app;
704 }
705 }
706 return topApp;
707 }
708
709 private void processApplicationsAnimatingInPlace(int transit) {
710 if (transit == TRANSIT_TASK_IN_PLACE) {
711 // Find the focused window
712 final WindowState win = mDisplayContent.findFocusedWindow();
713 if (win != null) {
714 final AppWindowToken wtoken = win.mAppToken;
715 if (DEBUG_APP_TRANSITIONS)
716 Slog.v(TAG, "Now animating app in place " + wtoken);
717 wtoken.cancelAnimation();
718 wtoken.applyAnimationLocked(null, transit, false, false);
719 wtoken.updateReportedVisibilityLocked();
720 wtoken.showAllWindowsLocked();
721 }
722 }
723 }
724}