blob: 6c5ef52592851a6a38d0f0a09f125288abecb911 [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;
Issei Suzukicac2a502019-04-16 16:52:50 +020031import static android.view.WindowManager.TRANSIT_SHOW_SINGLE_TASK_DISPLAY;
lumark588a3e82018-07-20 18:53:54 +080032import static android.view.WindowManager.TRANSIT_TASK_CLOSE;
33import static android.view.WindowManager.TRANSIT_TASK_IN_PLACE;
34import static android.view.WindowManager.TRANSIT_TASK_OPEN;
35import static android.view.WindowManager.TRANSIT_TASK_TO_BACK;
36import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
37import static android.view.WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE;
38import static android.view.WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_OPEN;
39import static android.view.WindowManager.TRANSIT_WALLPAPER_CLOSE;
40import static android.view.WindowManager.TRANSIT_WALLPAPER_INTRA_CLOSE;
41import static android.view.WindowManager.TRANSIT_WALLPAPER_INTRA_OPEN;
42import static android.view.WindowManager.TRANSIT_WALLPAPER_OPEN;
43
44import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
45import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
46import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_SNAPSHOT;
47import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_SPLASH_SCREEN;
48import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_WINDOWS_DRAWN;
49import static com.android.server.wm.AppTransition.isKeyguardGoingAwayTransit;
50import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
51import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
52import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
53import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
lumark588a3e82018-07-20 18:53:54 +080054
Yunfan Chencafc7062019-01-22 17:21:32 +090055import android.os.SystemClock;
lumark588a3e82018-07-20 18:53:54 +080056import android.os.Trace;
57import android.util.ArraySet;
58import android.util.Slog;
59import android.util.SparseIntArray;
60import android.view.Display;
61import android.view.RemoteAnimationAdapter;
62import android.view.RemoteAnimationDefinition;
63import android.view.WindowManager;
64import android.view.WindowManager.LayoutParams;
65import android.view.animation.Animation;
66
67import com.android.internal.annotations.VisibleForTesting;
68
69import java.util.function.Predicate;
70
71
72/**
73 * Checks for app transition readiness, resolves animation attributes and performs visibility
74 * change for apps that animate as part of an app transition.
75 */
76public class AppTransitionController {
77 private static final String TAG = TAG_WITH_CLASS_NAME ? "AppTransitionController" : TAG_WM;
78 private final WindowManagerService mService;
79 private final DisplayContent mDisplayContent;
80 private final WallpaperController mWallpaperControllerLocked;
Evan Rosky966759f2019-01-15 10:33:58 -080081 private RemoteAnimationDefinition mRemoteAnimationDefinition = null;
lumark588a3e82018-07-20 18:53:54 +080082
83 private final SparseIntArray mTempTransitionReasons = new SparseIntArray();
84
85 AppTransitionController(WindowManagerService service, DisplayContent displayContent) {
86 mService = service;
87 mDisplayContent = displayContent;
wilsonshihc32538e2018-11-07 17:27:34 +080088 mWallpaperControllerLocked = mDisplayContent.mWallpaperController;
lumark588a3e82018-07-20 18:53:54 +080089 }
90
Evan Rosky966759f2019-01-15 10:33:58 -080091 void registerRemoteAnimations(RemoteAnimationDefinition definition) {
92 mRemoteAnimationDefinition = definition;
93 }
94
lumark588a3e82018-07-20 18:53:54 +080095 /**
96 * Handle application transition for given display.
97 */
98 void handleAppTransitionReady() {
Evan Rosky2289ba12018-11-19 18:28:18 -080099 mTempTransitionReasons.clear();
100 if (!transitionGoodToGo(mDisplayContent.mOpeningApps, mTempTransitionReasons)
101 || !transitionGoodToGo(mDisplayContent.mChangingApps, mTempTransitionReasons)) {
lumark588a3e82018-07-20 18:53:54 +0800102 return;
103 }
104 Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "AppTransitionReady");
105
106 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
Tiger Huang7c610aa2018-10-27 00:01:01 +0800107 final AppTransition appTransition = mDisplayContent.mAppTransition;
108 int transit = appTransition.getAppTransition();
lumark588a3e82018-07-20 18:53:54 +0800109 if (mDisplayContent.mSkipAppTransitionAnimation && !isKeyguardGoingAwayTransit(transit)) {
110 transit = WindowManager.TRANSIT_UNSET;
111 }
112 mDisplayContent.mSkipAppTransitionAnimation = false;
113 mDisplayContent.mNoAnimationNotifyOnTransitionFinished.clear();
114
Tiger Huang7c610aa2018-10-27 00:01:01 +0800115 appTransition.removeAppTransitionTimeoutCallbacks();
lumark588a3e82018-07-20 18:53:54 +0800116
wilsonshihc32538e2018-11-07 17:27:34 +0800117 mDisplayContent.mWallpaperMayChange = false;
lumark588a3e82018-07-20 18:53:54 +0800118
Evan Rosky2289ba12018-11-19 18:28:18 -0800119 int appCount = mDisplayContent.mOpeningApps.size();
120 for (int i = 0; i < appCount; ++i) {
lumark588a3e82018-07-20 18:53:54 +0800121 // Clearing the mAnimatingExit flag before entering animation. It's set to true if app
122 // window is removed, or window relayout to invisible. This also affects window
123 // visibility. We need to clear it *before* maybeUpdateTransitToWallpaper() as the
124 // transition selection depends on wallpaper target visibility.
Evan Rosky2289ba12018-11-19 18:28:18 -0800125 mDisplayContent.mOpeningApps.valueAtUnchecked(i).clearAnimatingFlags();
126 }
127 appCount = mDisplayContent.mChangingApps.size();
128 for (int i = 0; i < appCount; ++i) {
129 // Clearing for same reason as above.
130 mDisplayContent.mChangingApps.valueAtUnchecked(i).clearAnimatingFlags();
lumark588a3e82018-07-20 18:53:54 +0800131 }
132
133 // Adjust wallpaper before we pull the lower/upper target, since pending changes
134 // (like the clearAnimatingFlags() above) might affect wallpaper target result.
135 // Or, the opening app window should be a wallpaper target.
wilsonshihc32538e2018-11-07 17:27:34 +0800136 mWallpaperControllerLocked.adjustWallpaperWindowsForAppTransitionIfNeeded(
Evan Rosky2289ba12018-11-19 18:28:18 -0800137 mDisplayContent.mOpeningApps, mDisplayContent.mChangingApps);
lumark588a3e82018-07-20 18:53:54 +0800138
139 // Determine if closing and opening app token sets are wallpaper targets, in which case
140 // special animations are needed.
141 final boolean hasWallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget() != null;
142 final boolean openingAppHasWallpaper = canBeWallpaperTarget(mDisplayContent.mOpeningApps)
143 && hasWallpaperTarget;
144 final boolean closingAppHasWallpaper = canBeWallpaperTarget(mDisplayContent.mClosingApps)
145 && hasWallpaperTarget;
146
147 transit = maybeUpdateTransitToTranslucentAnim(transit);
148 transit = maybeUpdateTransitToWallpaper(transit, openingAppHasWallpaper,
149 closingAppHasWallpaper);
150
151 // Find the layout params of the top-most application window in the tokens, which is
152 // what will control the animation theme. If all closing windows are obscured, then there is
153 // no need to do an animation. This is the case, for example, when this transition is being
154 // done behind a dream window.
155 final ArraySet<Integer> activityTypes = collectActivityTypes(mDisplayContent.mOpeningApps,
Evan Rosky2289ba12018-11-19 18:28:18 -0800156 mDisplayContent.mClosingApps, mDisplayContent.mChangingApps);
Tiger Huang7c610aa2018-10-27 00:01:01 +0800157 final boolean allowAnimations = mDisplayContent.getDisplayPolicy().allowAppAnimationsLw();
lumark588a3e82018-07-20 18:53:54 +0800158 final AppWindowToken animLpToken = allowAnimations
159 ? findAnimLayoutParamsToken(transit, activityTypes)
160 : null;
161 final AppWindowToken topOpeningApp = allowAnimations
162 ? getTopApp(mDisplayContent.mOpeningApps, false /* ignoreHidden */)
163 : null;
164 final AppWindowToken topClosingApp = allowAnimations
165 ? getTopApp(mDisplayContent.mClosingApps, false /* ignoreHidden */)
166 : null;
Evan Rosky2289ba12018-11-19 18:28:18 -0800167 final AppWindowToken topChangingApp = allowAnimations
168 ? getTopApp(mDisplayContent.mChangingApps, false /* ignoreHidden */)
169 : null;
lumark588a3e82018-07-20 18:53:54 +0800170 final WindowManager.LayoutParams animLp = getAnimLp(animLpToken);
171 overrideWithRemoteAnimationIfSet(animLpToken, transit, activityTypes);
172
173 final boolean voiceInteraction = containsVoiceInteraction(mDisplayContent.mOpeningApps)
Evan Rosky2289ba12018-11-19 18:28:18 -0800174 || containsVoiceInteraction(mDisplayContent.mOpeningApps)
175 || containsVoiceInteraction(mDisplayContent.mChangingApps);
lumark588a3e82018-07-20 18:53:54 +0800176
177 final int layoutRedo;
178 mService.mSurfaceAnimationRunner.deferStartingAnimations();
179 try {
180 processApplicationsAnimatingInPlace(transit);
181
182 handleClosingApps(transit, animLp, voiceInteraction);
183 handleOpeningApps(transit, animLp, voiceInteraction);
Evan Rosky2289ba12018-11-19 18:28:18 -0800184 handleChangingApps(transit, animLp, voiceInteraction);
lumark588a3e82018-07-20 18:53:54 +0800185
Tiger Huang7c610aa2018-10-27 00:01:01 +0800186 appTransition.setLastAppTransition(transit, topOpeningApp,
Evan Rosky2289ba12018-11-19 18:28:18 -0800187 topClosingApp, topChangingApp);
lumark588a3e82018-07-20 18:53:54 +0800188
Tiger Huang7c610aa2018-10-27 00:01:01 +0800189 final int flags = appTransition.getTransitFlags();
190 layoutRedo = appTransition.goodToGo(transit, topOpeningApp,
Evan Rosky2289ba12018-11-19 18:28:18 -0800191 mDisplayContent.mOpeningApps);
lumark588a3e82018-07-20 18:53:54 +0800192 handleNonAppWindowsInTransition(transit, flags);
Tiger Huang7c610aa2018-10-27 00:01:01 +0800193 appTransition.postAnimationCallback();
194 appTransition.clear();
lumark588a3e82018-07-20 18:53:54 +0800195 } finally {
196 mService.mSurfaceAnimationRunner.continueStartingAnimations();
197 }
198
199 mService.mTaskSnapshotController.onTransitionStarting(mDisplayContent);
200
201 mDisplayContent.mOpeningApps.clear();
202 mDisplayContent.mClosingApps.clear();
Evan Rosky2289ba12018-11-19 18:28:18 -0800203 mDisplayContent.mChangingApps.clear();
lumark588a3e82018-07-20 18:53:54 +0800204 mDisplayContent.mUnknownAppVisibilityController.clear();
205
206 // This has changed the visibility of windows, so perform
207 // a new layout to get them all up-to-date.
208 mDisplayContent.setLayoutNeeded();
209
210 mDisplayContent.computeImeTarget(true /* updateImeTarget */);
211
Yunfan Chencafc7062019-01-22 17:21:32 +0900212 mService.mAtmInternal.notifyAppTransitionStarting(mTempTransitionReasons.clone(),
213 SystemClock.uptimeMillis());
lumark588a3e82018-07-20 18:53:54 +0800214
Issei Suzukicac2a502019-04-16 16:52:50 +0200215 if (transit == TRANSIT_SHOW_SINGLE_TASK_DISPLAY) {
216 mService.mAnimator.addAfterPrepareSurfacesRunnable(() -> {
217 mService.mAtmInternal.notifySingleTaskDisplayDrawn(mDisplayContent.getDisplayId());
218 });
219 }
220
lumark588a3e82018-07-20 18:53:54 +0800221 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
222
223 mDisplayContent.pendingLayoutChanges |=
224 layoutRedo | FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG;
225 }
226
227 private static WindowManager.LayoutParams getAnimLp(AppWindowToken wtoken) {
228 final WindowState mainWindow = wtoken != null ? wtoken.findMainWindow() : null;
229 return mainWindow != null ? mainWindow.mAttrs : null;
230 }
231
Evan Rosky966759f2019-01-15 10:33:58 -0800232 RemoteAnimationAdapter getRemoteAnimationOverride(AppWindowToken animLpToken, int transit,
233 ArraySet<Integer> activityTypes) {
234 final RemoteAnimationDefinition definition = animLpToken.getRemoteAnimationDefinition();
235 if (definition != null) {
236 final RemoteAnimationAdapter adapter = definition.getAdapter(transit, activityTypes);
237 if (adapter != null) {
238 return adapter;
239 }
240 }
241 if (mRemoteAnimationDefinition == null) {
242 return null;
243 }
244 return mRemoteAnimationDefinition.getAdapter(transit, activityTypes);
245 }
246
lumark588a3e82018-07-20 18:53:54 +0800247 /**
248 * Overrides the pending transition with the remote animation defined for the transition in the
249 * set of defined remote animations in the app window token.
250 */
251 private void overrideWithRemoteAnimationIfSet(AppWindowToken animLpToken, int transit,
252 ArraySet<Integer> activityTypes) {
253 if (transit == TRANSIT_CRASHING_ACTIVITY_CLOSE) {
254 // The crash transition has higher priority than any involved remote animations.
255 return;
256 }
257 if (animLpToken == null) {
258 return;
259 }
Evan Rosky966759f2019-01-15 10:33:58 -0800260 final RemoteAnimationAdapter adapter =
261 getRemoteAnimationOverride(animLpToken, transit, activityTypes);
lumark588a3e82018-07-20 18:53:54 +0800262 if (adapter != null) {
263 animLpToken.getDisplayContent().mAppTransition.overridePendingAppTransitionRemote(
264 adapter);
265 }
266 }
267
268 /**
269 * @return The window token that determines the animation theme.
270 */
271 private AppWindowToken findAnimLayoutParamsToken(@WindowManager.TransitionType int transit,
272 ArraySet<Integer> activityTypes) {
273 AppWindowToken result;
274 final ArraySet<AppWindowToken> closingApps = mDisplayContent.mClosingApps;
275 final ArraySet<AppWindowToken> openingApps = mDisplayContent.mOpeningApps;
Evan Rosky2289ba12018-11-19 18:28:18 -0800276 final ArraySet<AppWindowToken> changingApps = mDisplayContent.mChangingApps;
lumark588a3e82018-07-20 18:53:54 +0800277
278 // Remote animations always win, but fullscreen tokens override non-fullscreen tokens.
Evan Rosky2289ba12018-11-19 18:28:18 -0800279 result = lookForHighestTokenWithFilter(closingApps, openingApps, changingApps,
lumark588a3e82018-07-20 18:53:54 +0800280 w -> w.getRemoteAnimationDefinition() != null
281 && w.getRemoteAnimationDefinition().hasTransition(transit, activityTypes));
282 if (result != null) {
283 return result;
284 }
Evan Rosky2289ba12018-11-19 18:28:18 -0800285 result = lookForHighestTokenWithFilter(closingApps, openingApps, changingApps,
lumark588a3e82018-07-20 18:53:54 +0800286 w -> w.fillsParent() && w.findMainWindow() != null);
287 if (result != null) {
288 return result;
289 }
Evan Rosky2289ba12018-11-19 18:28:18 -0800290 return lookForHighestTokenWithFilter(closingApps, openingApps, changingApps,
lumark588a3e82018-07-20 18:53:54 +0800291 w -> w.findMainWindow() != null);
292 }
293
294 /**
Tiger Huang7c610aa2018-10-27 00:01:01 +0800295 * @return The set of {@link android.app.WindowConfiguration.ActivityType}s contained in the set
Evan Rosky2289ba12018-11-19 18:28:18 -0800296 * of apps in {@code array1}, {@code array2}, and {@code array3}.
lumark588a3e82018-07-20 18:53:54 +0800297 */
298 private static ArraySet<Integer> collectActivityTypes(ArraySet<AppWindowToken> array1,
Evan Rosky2289ba12018-11-19 18:28:18 -0800299 ArraySet<AppWindowToken> array2, ArraySet<AppWindowToken> array3) {
lumark588a3e82018-07-20 18:53:54 +0800300 final ArraySet<Integer> result = new ArraySet<>();
301 for (int i = array1.size() - 1; i >= 0; i--) {
302 result.add(array1.valueAt(i).getActivityType());
303 }
304 for (int i = array2.size() - 1; i >= 0; i--) {
305 result.add(array2.valueAt(i).getActivityType());
306 }
Evan Rosky2289ba12018-11-19 18:28:18 -0800307 for (int i = array3.size() - 1; i >= 0; i--) {
308 result.add(array3.valueAt(i).getActivityType());
309 }
lumark588a3e82018-07-20 18:53:54 +0800310 return result;
311 }
312
313 private static AppWindowToken lookForHighestTokenWithFilter(ArraySet<AppWindowToken> array1,
Evan Rosky2289ba12018-11-19 18:28:18 -0800314 ArraySet<AppWindowToken> array2, ArraySet<AppWindowToken> array3,
315 Predicate<AppWindowToken> filter) {
316 final int array2base = array1.size();
317 final int array3base = array2.size() + array2base;
318 final int count = array3base + array3.size();
lumark588a3e82018-07-20 18:53:54 +0800319 int bestPrefixOrderIndex = Integer.MIN_VALUE;
320 AppWindowToken bestToken = null;
321 for (int i = 0; i < count; i++) {
Evan Rosky2289ba12018-11-19 18:28:18 -0800322 final AppWindowToken wtoken = i < array2base
lumark588a3e82018-07-20 18:53:54 +0800323 ? array1.valueAt(i)
Evan Rosky2289ba12018-11-19 18:28:18 -0800324 : (i < array3base
325 ? array2.valueAt(i - array2base)
326 : array3.valueAt(i - array3base));
lumark588a3e82018-07-20 18:53:54 +0800327 final int prefixOrderIndex = wtoken.getPrefixOrderIndex();
328 if (filter.test(wtoken) && prefixOrderIndex > bestPrefixOrderIndex) {
329 bestPrefixOrderIndex = prefixOrderIndex;
330 bestToken = wtoken;
331 }
332 }
333 return bestToken;
334 }
335
336 private boolean containsVoiceInteraction(ArraySet<AppWindowToken> apps) {
337 for (int i = apps.size() - 1; i >= 0; i--) {
338 if (apps.valueAt(i).mVoiceInteraction) {
339 return true;
340 }
341 }
342 return false;
343 }
344
345 private void handleOpeningApps(int transit, LayoutParams animLp, boolean voiceInteraction) {
346 final ArraySet<AppWindowToken> openingApps = mDisplayContent.mOpeningApps;
347 final int appsCount = openingApps.size();
348 for (int i = 0; i < appsCount; i++) {
349 AppWindowToken wtoken = openingApps.valueAt(i);
350 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken);
351
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800352 if (!wtoken.commitVisibility(animLp, true, transit, false, voiceInteraction)) {
lumark588a3e82018-07-20 18:53:54 +0800353 // This token isn't going to be animating. Add it to the list of tokens to
354 // be notified of app transition complete since the notification will not be
355 // sent be the app window animator.
356 mDisplayContent.mNoAnimationNotifyOnTransitionFinished.add(wtoken.token);
357 }
358 wtoken.updateReportedVisibilityLocked();
359 wtoken.waitingToShow = false;
360 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
361 ">>> OPEN TRANSACTION handleAppTransitionReady()");
362 mService.openSurfaceTransaction();
363 try {
364 wtoken.showAllWindowsLocked();
365 } finally {
366 mService.closeSurfaceTransaction("handleAppTransitionReady");
367 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
368 "<<< CLOSE TRANSACTION handleAppTransitionReady()");
369 }
370
371 if (mDisplayContent.mAppTransition.isNextAppTransitionThumbnailUp()) {
372 wtoken.attachThumbnailAnimation();
373 } else if (mDisplayContent.mAppTransition.isNextAppTransitionOpenCrossProfileApps()) {
374 wtoken.attachCrossProfileAppsThumbnailAnimation();
375 }
376 }
377 }
378
379 private void handleClosingApps(int transit, LayoutParams animLp, boolean voiceInteraction) {
380 final ArraySet<AppWindowToken> closingApps = mDisplayContent.mClosingApps;
381 final int appsCount = closingApps.size();
382 for (int i = 0; i < appsCount; i++) {
383 AppWindowToken wtoken = closingApps.valueAt(i);
384
385 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now closing app " + wtoken);
386 // TODO: Do we need to add to mNoAnimationNotifyOnTransitionFinished like above if not
387 // animating?
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800388 wtoken.commitVisibility(animLp, false, transit, false, voiceInteraction);
lumark588a3e82018-07-20 18:53:54 +0800389 wtoken.updateReportedVisibilityLocked();
390 // Force the allDrawn flag, because we want to start
391 // this guy's animations regardless of whether it's
392 // gotten drawn.
393 wtoken.allDrawn = true;
394 wtoken.deferClearAllDrawn = false;
395 // Ensure that apps that are mid-starting are also scheduled to have their
396 // starting windows removed after the animation is complete
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800397 if (wtoken.startingWindow != null && !wtoken.startingWindow.mAnimatingExit) {
398 wtoken.removeStartingWindow();
lumark588a3e82018-07-20 18:53:54 +0800399 }
400
401 if (mDisplayContent.mAppTransition.isNextAppTransitionThumbnailDown()) {
402 wtoken.attachThumbnailAnimation();
403 }
404 }
405 }
406
Evan Rosky2289ba12018-11-19 18:28:18 -0800407 private void handleChangingApps(int transit, LayoutParams animLp, boolean voiceInteraction) {
408 final ArraySet<AppWindowToken> apps = mDisplayContent.mChangingApps;
409 final int appsCount = apps.size();
410 for (int i = 0; i < appsCount; i++) {
411 AppWindowToken wtoken = apps.valueAt(i);
412 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now changing app" + wtoken);
413 wtoken.cancelAnimationOnly();
414 wtoken.applyAnimationLocked(null, transit, true, false);
415 wtoken.updateReportedVisibilityLocked();
416 mService.openSurfaceTransaction();
417 try {
418 wtoken.showAllWindowsLocked();
419 } finally {
420 mService.closeSurfaceTransaction("handleChangingApps");
421 }
422 }
423 }
424
lumark588a3e82018-07-20 18:53:54 +0800425 private void handleNonAppWindowsInTransition(int transit, int flags) {
426 if (transit == TRANSIT_KEYGUARD_GOING_AWAY) {
427 if ((flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0
428 && (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION) == 0) {
429 Animation anim = mService.mPolicy.createKeyguardWallpaperExit(
430 (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0);
431 if (anim != null) {
432 mDisplayContent.mWallpaperController.startWallpaperAnimation(anim);
433 }
434 }
435 }
436 if (transit == TRANSIT_KEYGUARD_GOING_AWAY
437 || transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER) {
438 mDisplayContent.startKeyguardExitOnNonAppWindows(
439 transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER,
440 (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0);
441 }
442 }
443
Evan Rosky2289ba12018-11-19 18:28:18 -0800444 private boolean transitionGoodToGo(ArraySet<AppWindowToken> apps, SparseIntArray outReasons) {
lumark588a3e82018-07-20 18:53:54 +0800445 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
Evan Rosky2289ba12018-11-19 18:28:18 -0800446 "Checking " + apps.size() + " opening apps (frozen="
lumark588a3e82018-07-20 18:53:54 +0800447 + mService.mDisplayFrozen + " timeout="
448 + mDisplayContent.mAppTransition.isTimeout() + ")...");
449 final ScreenRotationAnimation screenRotationAnimation =
450 mService.mAnimator.getScreenRotationAnimationLocked(
451 Display.DEFAULT_DISPLAY);
452
lumark588a3e82018-07-20 18:53:54 +0800453 if (!mDisplayContent.mAppTransition.isTimeout()) {
454 // Imagine the case where we are changing orientation due to an app transition, but a
455 // previous orientation change is still in progress. We won't process the orientation
456 // change for our transition because we need to wait for the rotation animation to
457 // finish.
458 // If we start the app transition at this point, we will interrupt it halfway with a
459 // new rotation animation after the old one finally finishes. It's better to defer the
460 // app transition.
461 if (screenRotationAnimation != null && screenRotationAnimation.isAnimating() &&
462 mService.getDefaultDisplayContentLocked().rotationNeedsUpdate()) {
463 if (DEBUG_APP_TRANSITIONS) {
464 Slog.v(TAG, "Delaying app transition for screen rotation animation to finish");
465 }
466 return false;
467 }
Evan Rosky2289ba12018-11-19 18:28:18 -0800468 for (int i = 0; i < apps.size(); i++) {
469 AppWindowToken wtoken = apps.valueAt(i);
lumark588a3e82018-07-20 18:53:54 +0800470 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
471 "Check opening app=" + wtoken + ": allDrawn="
472 + wtoken.allDrawn + " startingDisplayed="
473 + wtoken.startingDisplayed + " startingMoved="
474 + wtoken.startingMoved + " isRelaunching()="
475 + wtoken.isRelaunching() + " startingWindow="
476 + wtoken.startingWindow);
477
478
479 final boolean allDrawn = wtoken.allDrawn && !wtoken.isRelaunching();
480 if (!allDrawn && !wtoken.startingDisplayed && !wtoken.startingMoved) {
481 return false;
482 }
483 final int windowingMode = wtoken.getWindowingMode();
484 if (allDrawn) {
485 outReasons.put(windowingMode, APP_TRANSITION_WINDOWS_DRAWN);
486 } else {
487 outReasons.put(windowingMode,
chaviwa8f07a72019-05-01 16:25:39 -0700488 wtoken.mStartingData instanceof SplashScreenStartingData
lumark588a3e82018-07-20 18:53:54 +0800489 ? APP_TRANSITION_SPLASH_SCREEN
490 : APP_TRANSITION_SNAPSHOT);
491 }
492 }
493
494 // We also need to wait for the specs to be fetched, if needed.
495 if (mDisplayContent.mAppTransition.isFetchingAppTransitionsSpecs()) {
496 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "isFetchingAppTransitionSpecs=true");
497 return false;
498 }
499
500 if (!mDisplayContent.mUnknownAppVisibilityController.allResolved()) {
501 if (DEBUG_APP_TRANSITIONS) {
502 Slog.v(TAG, "unknownApps is not empty: "
503 + mDisplayContent.mUnknownAppVisibilityController.getDebugMessage());
504 }
505 return false;
506 }
507
508 // If the wallpaper is visible, we need to check it's ready too.
509 boolean wallpaperReady = !mWallpaperControllerLocked.isWallpaperVisible() ||
510 mWallpaperControllerLocked.wallpaperTransitionReady();
511 if (wallpaperReady) {
512 return true;
513 }
514 return false;
515 }
516 return true;
517 }
518
519 private int maybeUpdateTransitToWallpaper(int transit, boolean openingAppHasWallpaper,
520 boolean closingAppHasWallpaper) {
521 // Given no app transition pass it through instead of a wallpaper transition.
522 // Never convert the crashing transition.
523 // Never update the transition for the wallpaper if we are just docking from recents
Evan Roskyec9488c2019-03-01 19:32:12 -0800524 // Never convert a change transition since the top activity isn't changing and will likely
525 // still be above an opening wallpaper.
lumark588a3e82018-07-20 18:53:54 +0800526 if (transit == TRANSIT_NONE || transit == TRANSIT_CRASHING_ACTIVITY_CLOSE
Evan Roskyec9488c2019-03-01 19:32:12 -0800527 || transit == TRANSIT_DOCK_TASK_FROM_RECENTS
528 || AppTransition.isChangeTransit(transit)) {
lumark588a3e82018-07-20 18:53:54 +0800529 return transit;
530 }
531
532 final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget();
533 final boolean showWallpaper = wallpaperTarget != null
534 && (wallpaperTarget.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0;
535 // If wallpaper is animating or wallpaperTarget doesn't have SHOW_WALLPAPER flag set,
536 // don't consider upgrading to wallpaper transition.
537 final WindowState oldWallpaper =
538 (mWallpaperControllerLocked.isWallpaperTargetAnimating() || !showWallpaper)
539 ? null
540 : wallpaperTarget;
541 final ArraySet<AppWindowToken> openingApps = mDisplayContent.mOpeningApps;
542 final ArraySet<AppWindowToken> closingApps = mDisplayContent.mClosingApps;
543 final AppWindowToken topOpeningApp = getTopApp(mDisplayContent.mOpeningApps,
544 false /* ignoreHidden */);
545 final AppWindowToken topClosingApp = getTopApp(mDisplayContent.mClosingApps,
546 true /* ignoreHidden */);
547
548 boolean openingCanBeWallpaperTarget = canBeWallpaperTarget(openingApps);
549 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
550 "New wallpaper target=" + wallpaperTarget
551 + ", oldWallpaper=" + oldWallpaper
552 + ", openingApps=" + openingApps
553 + ", closingApps=" + closingApps);
554
555 if (openingCanBeWallpaperTarget && transit == TRANSIT_KEYGUARD_GOING_AWAY) {
556 transit = TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
557 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
558 "New transit: " + AppTransition.appTransitionToString(transit));
559 }
560 // We never want to change from a Keyguard transit to a non-Keyguard transit, as our logic
561 // relies on the fact that we always execute a Keyguard transition after preparing one.
562 else if (!isKeyguardGoingAwayTransit(transit)) {
563 if (closingAppHasWallpaper && openingAppHasWallpaper) {
564 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Wallpaper animation!");
565 switch (transit) {
566 case TRANSIT_ACTIVITY_OPEN:
567 case TRANSIT_TASK_OPEN:
568 case TRANSIT_TASK_TO_FRONT:
569 transit = TRANSIT_WALLPAPER_INTRA_OPEN;
570 break;
571 case TRANSIT_ACTIVITY_CLOSE:
572 case TRANSIT_TASK_CLOSE:
573 case TRANSIT_TASK_TO_BACK:
574 transit = TRANSIT_WALLPAPER_INTRA_CLOSE;
575 break;
576 }
577 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
578 "New transit: " + AppTransition.appTransitionToString(transit));
579 } else if (oldWallpaper != null && !mDisplayContent.mOpeningApps.isEmpty()
580 && !openingApps.contains(oldWallpaper.mAppToken)
581 && closingApps.contains(oldWallpaper.mAppToken)
582 && topClosingApp == oldWallpaper.mAppToken) {
583 // We are transitioning from an activity with a wallpaper to one without.
584 transit = TRANSIT_WALLPAPER_CLOSE;
585 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit away from wallpaper: "
586 + AppTransition.appTransitionToString(transit));
587 } else if (wallpaperTarget != null && wallpaperTarget.isVisibleLw()
588 && openingApps.contains(wallpaperTarget.mAppToken)
589 && topOpeningApp == wallpaperTarget.mAppToken
590 && transit != TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE) {
591 // We are transitioning from an activity without
592 // a wallpaper to now showing the wallpaper
593 transit = TRANSIT_WALLPAPER_OPEN;
594 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit into wallpaper: "
595 + AppTransition.appTransitionToString(transit));
596 }
597 }
598 return transit;
599 }
600
601 /**
602 * There are cases where we open/close a new task/activity, but in reality only a translucent
603 * activity on top of existing activities is opening/closing. For that one, we have a different
604 * animation because non of the task/activity animations actually work well with translucent
605 * apps.
606 *
607 * @param transit The current transition type.
608 * @return The current transition type or
609 * {@link WindowManager#TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE}/
610 * {@link WindowManager#TRANSIT_TRANSLUCENT_ACTIVITY_OPEN} if appropriate for the
611 * situation.
612 */
613 @VisibleForTesting
614 int maybeUpdateTransitToTranslucentAnim(int transit) {
Evan Roskyec9488c2019-03-01 19:32:12 -0800615 if (AppTransition.isChangeTransit(transit)) {
616 // There's no special animation to handle change animations with translucent apps
617 return transit;
618 }
lumark588a3e82018-07-20 18:53:54 +0800619 final boolean taskOrActivity = AppTransition.isTaskTransit(transit)
620 || AppTransition.isActivityTransit(transit);
621 boolean allOpeningVisible = true;
622 boolean allTranslucentOpeningApps = !mDisplayContent.mOpeningApps.isEmpty();
623 for (int i = mDisplayContent.mOpeningApps.size() - 1; i >= 0; i--) {
624 final AppWindowToken token = mDisplayContent.mOpeningApps.valueAt(i);
625 if (!token.isVisible()) {
626 allOpeningVisible = false;
627 if (token.fillsParent()) {
628 allTranslucentOpeningApps = false;
629 }
630 }
631 }
632 boolean allTranslucentClosingApps = !mDisplayContent.mClosingApps.isEmpty();
633 for (int i = mDisplayContent.mClosingApps.size() - 1; i >= 0; i--) {
634 if (mDisplayContent.mClosingApps.valueAt(i).fillsParent()) {
635 allTranslucentClosingApps = false;
636 break;
637 }
638 }
639
640 if (taskOrActivity && allTranslucentClosingApps && allOpeningVisible) {
641 return TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE;
642 }
643 if (taskOrActivity && allTranslucentOpeningApps && mDisplayContent.mClosingApps.isEmpty()) {
644 return TRANSIT_TRANSLUCENT_ACTIVITY_OPEN;
645 }
646 return transit;
647 }
648
Evan Rosky7735d352019-03-18 17:27:27 -0700649 /**
650 * Identifies whether the current transition occurs within a single task or not. This is used
651 * to determine whether animations should be clipped to the task bounds instead of stack bounds.
652 */
653 @VisibleForTesting
654 boolean isTransitWithinTask(int transit, Task task) {
655 if (task == null
656 || !mDisplayContent.mChangingApps.isEmpty()) {
657 // if there is no task, then we can't constrain to the task.
658 // if anything is changing, it can animate outside its task.
659 return false;
660 }
661 if (!(transit == TRANSIT_ACTIVITY_OPEN
662 || transit == TRANSIT_ACTIVITY_CLOSE
663 || transit == TRANSIT_ACTIVITY_RELAUNCH)) {
664 // only activity-level transitions will be within-task.
665 return false;
666 }
667 // check that all components are in the task.
668 for (AppWindowToken activity : mDisplayContent.mOpeningApps) {
669 Task activityTask = activity.getTask();
670 if (activityTask != task) {
671 return false;
672 }
673 }
674 for (AppWindowToken activity : mDisplayContent.mClosingApps) {
675 if (activity.getTask() != task) {
676 return false;
677 }
678 }
679 return true;
680 }
681
lumark588a3e82018-07-20 18:53:54 +0800682 private boolean canBeWallpaperTarget(ArraySet<AppWindowToken> apps) {
683 for (int i = apps.size() - 1; i >= 0; i--) {
684 if (apps.valueAt(i).windowsCanBeWallpaperTarget()) {
685 return true;
686 }
687 }
688 return false;
689 }
690
691 /**
692 * Finds the top app in a list of apps, using its {@link AppWindowToken#getPrefixOrderIndex} to
693 * compare z-order.
694 *
695 * @param apps The list of apps to search.
696 * @param ignoreHidden If set to true, ignores apps that are {@link AppWindowToken#isHidden}.
697 * @return The top {@link AppWindowToken}.
698 */
699 private AppWindowToken getTopApp(ArraySet<AppWindowToken> apps, boolean ignoreHidden) {
700 int topPrefixOrderIndex = Integer.MIN_VALUE;
701 AppWindowToken topApp = null;
702 for (int i = apps.size() - 1; i >= 0; i--) {
703 final AppWindowToken app = apps.valueAt(i);
704 if (ignoreHidden && app.isHidden()) {
705 continue;
706 }
707 final int prefixOrderIndex = app.getPrefixOrderIndex();
708 if (prefixOrderIndex > topPrefixOrderIndex) {
709 topPrefixOrderIndex = prefixOrderIndex;
710 topApp = app;
711 }
712 }
713 return topApp;
714 }
715
716 private void processApplicationsAnimatingInPlace(int transit) {
717 if (transit == TRANSIT_TASK_IN_PLACE) {
718 // Find the focused window
719 final WindowState win = mDisplayContent.findFocusedWindow();
720 if (win != null) {
721 final AppWindowToken wtoken = win.mAppToken;
722 if (DEBUG_APP_TRANSITIONS)
723 Slog.v(TAG, "Now animating app in place " + wtoken);
724 wtoken.cancelAnimation();
725 wtoken.applyAnimationLocked(null, transit, false, false);
726 wtoken.updateReportedVisibilityLocked();
727 wtoken.showAllWindowsLocked();
728 }
729 }
730 }
731}