blob: 94a47dd2aa601f6e86f0f749591f0722fd51f96a [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;
22import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE;
23import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
24import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
25import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
26import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
27import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
28import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
29import static android.view.WindowManager.TRANSIT_NONE;
30import static android.view.WindowManager.TRANSIT_TASK_CLOSE;
31import static android.view.WindowManager.TRANSIT_TASK_IN_PLACE;
32import static android.view.WindowManager.TRANSIT_TASK_OPEN;
33import static android.view.WindowManager.TRANSIT_TASK_TO_BACK;
34import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
35import static android.view.WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE;
36import static android.view.WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_OPEN;
37import static android.view.WindowManager.TRANSIT_WALLPAPER_CLOSE;
38import static android.view.WindowManager.TRANSIT_WALLPAPER_INTRA_CLOSE;
39import static android.view.WindowManager.TRANSIT_WALLPAPER_INTRA_OPEN;
40import static android.view.WindowManager.TRANSIT_WALLPAPER_OPEN;
41
42import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
43import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
44import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_SNAPSHOT;
45import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_SPLASH_SCREEN;
46import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_WINDOWS_DRAWN;
47import static com.android.server.wm.AppTransition.isKeyguardGoingAwayTransit;
48import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
49import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
50import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
51import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
52import static com.android.server.wm.WindowManagerService.H.NOTIFY_APP_TRANSITION_STARTING;
53
54import android.app.WindowConfiguration;
55import 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;
80
81 private final SparseIntArray mTempTransitionReasons = new SparseIntArray();
82
83 AppTransitionController(WindowManagerService service, DisplayContent displayContent) {
84 mService = service;
85 mDisplayContent = displayContent;
86 mWallpaperControllerLocked = new WallpaperController(mService);
87 }
88
89 /**
90 * Handle application transition for given display.
91 */
92 void handleAppTransitionReady() {
93 final int appsCount = mDisplayContent.mOpeningApps.size();
94 if (!transitionGoodToGo(appsCount, mTempTransitionReasons)) {
95 return;
96 }
97 Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "AppTransitionReady");
98
99 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
100 int transit = mDisplayContent.mAppTransition.getAppTransition();
101 if (mDisplayContent.mSkipAppTransitionAnimation && !isKeyguardGoingAwayTransit(transit)) {
102 transit = WindowManager.TRANSIT_UNSET;
103 }
104 mDisplayContent.mSkipAppTransitionAnimation = false;
105 mDisplayContent.mNoAnimationNotifyOnTransitionFinished.clear();
106
107 mDisplayContent.mAppTransition.removeAppTransitionTimeoutCallbacks();
108
109 mService.mRoot.mWallpaperMayChange = false;
110
111 int i;
112 for (i = 0; i < appsCount; i++) {
113 final AppWindowToken wtoken = mDisplayContent.mOpeningApps.valueAt(i);
114 // Clearing the mAnimatingExit flag before entering animation. It's set to true if app
115 // window is removed, or window relayout to invisible. This also affects window
116 // visibility. We need to clear it *before* maybeUpdateTransitToWallpaper() as the
117 // transition selection depends on wallpaper target visibility.
118 wtoken.clearAnimatingFlags();
119 }
120
121 // Adjust wallpaper before we pull the lower/upper target, since pending changes
122 // (like the clearAnimatingFlags() above) might affect wallpaper target result.
123 // Or, the opening app window should be a wallpaper target.
124 mWallpaperControllerLocked.adjustWallpaperWindowsForAppTransitionIfNeeded(mDisplayContent,
125 mDisplayContent.mOpeningApps);
126
127 // Determine if closing and opening app token sets are wallpaper targets, in which case
128 // special animations are needed.
129 final boolean hasWallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget() != null;
130 final boolean openingAppHasWallpaper = canBeWallpaperTarget(mDisplayContent.mOpeningApps)
131 && hasWallpaperTarget;
132 final boolean closingAppHasWallpaper = canBeWallpaperTarget(mDisplayContent.mClosingApps)
133 && hasWallpaperTarget;
134
135 transit = maybeUpdateTransitToTranslucentAnim(transit);
136 transit = maybeUpdateTransitToWallpaper(transit, openingAppHasWallpaper,
137 closingAppHasWallpaper);
138
139 // Find the layout params of the top-most application window in the tokens, which is
140 // what will control the animation theme. If all closing windows are obscured, then there is
141 // no need to do an animation. This is the case, for example, when this transition is being
142 // done behind a dream window.
143 final ArraySet<Integer> activityTypes = collectActivityTypes(mDisplayContent.mOpeningApps,
144 mDisplayContent.mClosingApps);
145 final boolean allowAnimations = mService.mPolicy.allowAppAnimationsLw();
146 final AppWindowToken animLpToken = allowAnimations
147 ? findAnimLayoutParamsToken(transit, activityTypes)
148 : null;
149 final AppWindowToken topOpeningApp = allowAnimations
150 ? getTopApp(mDisplayContent.mOpeningApps, false /* ignoreHidden */)
151 : null;
152 final AppWindowToken topClosingApp = allowAnimations
153 ? getTopApp(mDisplayContent.mClosingApps, false /* ignoreHidden */)
154 : null;
155 final WindowManager.LayoutParams animLp = getAnimLp(animLpToken);
156 overrideWithRemoteAnimationIfSet(animLpToken, transit, activityTypes);
157
158 final boolean voiceInteraction = containsVoiceInteraction(mDisplayContent.mOpeningApps)
159 || containsVoiceInteraction(mDisplayContent.mOpeningApps);
160
161 final int layoutRedo;
162 mService.mSurfaceAnimationRunner.deferStartingAnimations();
163 try {
164 processApplicationsAnimatingInPlace(transit);
165
166 handleClosingApps(transit, animLp, voiceInteraction);
167 handleOpeningApps(transit, animLp, voiceInteraction);
168
169 mDisplayContent.mAppTransition.setLastAppTransition(transit, topOpeningApp,
170 topClosingApp);
171
172 final int flags = mDisplayContent.mAppTransition.getTransitFlags();
173 layoutRedo = mDisplayContent.mAppTransition.goodToGo(transit, topOpeningApp,
174 topClosingApp, mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps);
175 handleNonAppWindowsInTransition(transit, flags);
176 mDisplayContent.mAppTransition.postAnimationCallback();
177 mDisplayContent.mAppTransition.clear();
178 } finally {
179 mService.mSurfaceAnimationRunner.continueStartingAnimations();
180 }
181
182 mService.mTaskSnapshotController.onTransitionStarting(mDisplayContent);
183
184 mDisplayContent.mOpeningApps.clear();
185 mDisplayContent.mClosingApps.clear();
186 mDisplayContent.mUnknownAppVisibilityController.clear();
187
188 // This has changed the visibility of windows, so perform
189 // a new layout to get them all up-to-date.
190 mDisplayContent.setLayoutNeeded();
191
192 mDisplayContent.computeImeTarget(true /* updateImeTarget */);
193
194 mService.mH.obtainMessage(NOTIFY_APP_TRANSITION_STARTING,
195 mTempTransitionReasons.clone()).sendToTarget();
196
197 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
198
199 mDisplayContent.pendingLayoutChanges |=
200 layoutRedo | FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG;
201 }
202
203 private static WindowManager.LayoutParams getAnimLp(AppWindowToken wtoken) {
204 final WindowState mainWindow = wtoken != null ? wtoken.findMainWindow() : null;
205 return mainWindow != null ? mainWindow.mAttrs : null;
206 }
207
208 /**
209 * Overrides the pending transition with the remote animation defined for the transition in the
210 * set of defined remote animations in the app window token.
211 */
212 private void overrideWithRemoteAnimationIfSet(AppWindowToken animLpToken, int transit,
213 ArraySet<Integer> activityTypes) {
214 if (transit == TRANSIT_CRASHING_ACTIVITY_CLOSE) {
215 // The crash transition has higher priority than any involved remote animations.
216 return;
217 }
218 if (animLpToken == null) {
219 return;
220 }
221 final RemoteAnimationDefinition definition = animLpToken.getRemoteAnimationDefinition();
222 if (definition == null) {
223 return;
224 }
225 final RemoteAnimationAdapter adapter = definition.getAdapter(transit, activityTypes);
226 if (adapter != null) {
227 animLpToken.getDisplayContent().mAppTransition.overridePendingAppTransitionRemote(
228 adapter);
229 }
230 }
231
232 /**
233 * @return The window token that determines the animation theme.
234 */
235 private AppWindowToken findAnimLayoutParamsToken(@WindowManager.TransitionType int transit,
236 ArraySet<Integer> activityTypes) {
237 AppWindowToken result;
238 final ArraySet<AppWindowToken> closingApps = mDisplayContent.mClosingApps;
239 final ArraySet<AppWindowToken> openingApps = mDisplayContent.mOpeningApps;
240
241 // Remote animations always win, but fullscreen tokens override non-fullscreen tokens.
242 result = lookForHighestTokenWithFilter(closingApps, openingApps,
243 w -> w.getRemoteAnimationDefinition() != null
244 && w.getRemoteAnimationDefinition().hasTransition(transit, activityTypes));
245 if (result != null) {
246 return result;
247 }
248 result = lookForHighestTokenWithFilter(closingApps, openingApps,
249 w -> w.fillsParent() && w.findMainWindow() != null);
250 if (result != null) {
251 return result;
252 }
253 return lookForHighestTokenWithFilter(closingApps, openingApps,
254 w -> w.findMainWindow() != null);
255 }
256
257 /**
258 * @return The set of {@link WindowConfiguration.ActivityType}s contained in the set of apps in
259 * {@code array1} and {@code array2}.
260 */
261 private static ArraySet<Integer> collectActivityTypes(ArraySet<AppWindowToken> array1,
262 ArraySet<AppWindowToken> array2) {
263 final ArraySet<Integer> result = new ArraySet<>();
264 for (int i = array1.size() - 1; i >= 0; i--) {
265 result.add(array1.valueAt(i).getActivityType());
266 }
267 for (int i = array2.size() - 1; i >= 0; i--) {
268 result.add(array2.valueAt(i).getActivityType());
269 }
270 return result;
271 }
272
273 private static AppWindowToken lookForHighestTokenWithFilter(ArraySet<AppWindowToken> array1,
274 ArraySet<AppWindowToken> array2, Predicate<AppWindowToken> filter) {
275 final int array1count = array1.size();
276 final int count = array1count + array2.size();
277 int bestPrefixOrderIndex = Integer.MIN_VALUE;
278 AppWindowToken bestToken = null;
279 for (int i = 0; i < count; i++) {
280 final AppWindowToken wtoken = i < array1count
281 ? array1.valueAt(i)
282 : array2.valueAt(i - array1count);
283 final int prefixOrderIndex = wtoken.getPrefixOrderIndex();
284 if (filter.test(wtoken) && prefixOrderIndex > bestPrefixOrderIndex) {
285 bestPrefixOrderIndex = prefixOrderIndex;
286 bestToken = wtoken;
287 }
288 }
289 return bestToken;
290 }
291
292 private boolean containsVoiceInteraction(ArraySet<AppWindowToken> apps) {
293 for (int i = apps.size() - 1; i >= 0; i--) {
294 if (apps.valueAt(i).mVoiceInteraction) {
295 return true;
296 }
297 }
298 return false;
299 }
300
301 private void handleOpeningApps(int transit, LayoutParams animLp, boolean voiceInteraction) {
302 final ArraySet<AppWindowToken> openingApps = mDisplayContent.mOpeningApps;
303 final int appsCount = openingApps.size();
304 for (int i = 0; i < appsCount; i++) {
305 AppWindowToken wtoken = openingApps.valueAt(i);
306 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken);
307
308 if (!wtoken.setVisibility(animLp, true, transit, false, voiceInteraction)) {
309 // This token isn't going to be animating. Add it to the list of tokens to
310 // be notified of app transition complete since the notification will not be
311 // sent be the app window animator.
312 mDisplayContent.mNoAnimationNotifyOnTransitionFinished.add(wtoken.token);
313 }
314 wtoken.updateReportedVisibilityLocked();
315 wtoken.waitingToShow = false;
316 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
317 ">>> OPEN TRANSACTION handleAppTransitionReady()");
318 mService.openSurfaceTransaction();
319 try {
320 wtoken.showAllWindowsLocked();
321 } finally {
322 mService.closeSurfaceTransaction("handleAppTransitionReady");
323 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
324 "<<< CLOSE TRANSACTION handleAppTransitionReady()");
325 }
326
327 if (mDisplayContent.mAppTransition.isNextAppTransitionThumbnailUp()) {
328 wtoken.attachThumbnailAnimation();
329 } else if (mDisplayContent.mAppTransition.isNextAppTransitionOpenCrossProfileApps()) {
330 wtoken.attachCrossProfileAppsThumbnailAnimation();
331 }
332 }
333 }
334
335 private void handleClosingApps(int transit, LayoutParams animLp, boolean voiceInteraction) {
336 final ArraySet<AppWindowToken> closingApps = mDisplayContent.mClosingApps;
337 final int appsCount = closingApps.size();
338 for (int i = 0; i < appsCount; i++) {
339 AppWindowToken wtoken = closingApps.valueAt(i);
340
341 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now closing app " + wtoken);
342 // TODO: Do we need to add to mNoAnimationNotifyOnTransitionFinished like above if not
343 // animating?
344 wtoken.setVisibility(animLp, false, transit, false, voiceInteraction);
345 wtoken.updateReportedVisibilityLocked();
346 // Force the allDrawn flag, because we want to start
347 // this guy's animations regardless of whether it's
348 // gotten drawn.
349 wtoken.allDrawn = true;
350 wtoken.deferClearAllDrawn = false;
351 // Ensure that apps that are mid-starting are also scheduled to have their
352 // starting windows removed after the animation is complete
353 if (wtoken.startingWindow != null && !wtoken.startingWindow.mAnimatingExit
354 && wtoken.getController() != null) {
355 wtoken.getController().removeStartingWindow();
356 }
357
358 if (mDisplayContent.mAppTransition.isNextAppTransitionThumbnailDown()) {
359 wtoken.attachThumbnailAnimation();
360 }
361 }
362 }
363
364 private void handleNonAppWindowsInTransition(int transit, int flags) {
365 if (transit == TRANSIT_KEYGUARD_GOING_AWAY) {
366 if ((flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0
367 && (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION) == 0) {
368 Animation anim = mService.mPolicy.createKeyguardWallpaperExit(
369 (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0);
370 if (anim != null) {
371 mDisplayContent.mWallpaperController.startWallpaperAnimation(anim);
372 }
373 }
374 }
375 if (transit == TRANSIT_KEYGUARD_GOING_AWAY
376 || transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER) {
377 mDisplayContent.startKeyguardExitOnNonAppWindows(
378 transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER,
379 (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0);
380 }
381 }
382
383 private boolean transitionGoodToGo(int appsCount, SparseIntArray outReasons) {
384 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
385 "Checking " + appsCount + " opening apps (frozen="
386 + mService.mDisplayFrozen + " timeout="
387 + mDisplayContent.mAppTransition.isTimeout() + ")...");
388 final ScreenRotationAnimation screenRotationAnimation =
389 mService.mAnimator.getScreenRotationAnimationLocked(
390 Display.DEFAULT_DISPLAY);
391
392 outReasons.clear();
393 if (!mDisplayContent.mAppTransition.isTimeout()) {
394 // Imagine the case where we are changing orientation due to an app transition, but a
395 // previous orientation change is still in progress. We won't process the orientation
396 // change for our transition because we need to wait for the rotation animation to
397 // finish.
398 // If we start the app transition at this point, we will interrupt it halfway with a
399 // new rotation animation after the old one finally finishes. It's better to defer the
400 // app transition.
401 if (screenRotationAnimation != null && screenRotationAnimation.isAnimating() &&
402 mService.getDefaultDisplayContentLocked().rotationNeedsUpdate()) {
403 if (DEBUG_APP_TRANSITIONS) {
404 Slog.v(TAG, "Delaying app transition for screen rotation animation to finish");
405 }
406 return false;
407 }
408 for (int i = 0; i < appsCount; i++) {
409 AppWindowToken wtoken = mDisplayContent.mOpeningApps.valueAt(i);
410 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
411 "Check opening app=" + wtoken + ": allDrawn="
412 + wtoken.allDrawn + " startingDisplayed="
413 + wtoken.startingDisplayed + " startingMoved="
414 + wtoken.startingMoved + " isRelaunching()="
415 + wtoken.isRelaunching() + " startingWindow="
416 + wtoken.startingWindow);
417
418
419 final boolean allDrawn = wtoken.allDrawn && !wtoken.isRelaunching();
420 if (!allDrawn && !wtoken.startingDisplayed && !wtoken.startingMoved) {
421 return false;
422 }
423 final int windowingMode = wtoken.getWindowingMode();
424 if (allDrawn) {
425 outReasons.put(windowingMode, APP_TRANSITION_WINDOWS_DRAWN);
426 } else {
427 outReasons.put(windowingMode,
428 wtoken.startingData instanceof SplashScreenStartingData
429 ? APP_TRANSITION_SPLASH_SCREEN
430 : APP_TRANSITION_SNAPSHOT);
431 }
432 }
433
434 // We also need to wait for the specs to be fetched, if needed.
435 if (mDisplayContent.mAppTransition.isFetchingAppTransitionsSpecs()) {
436 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "isFetchingAppTransitionSpecs=true");
437 return false;
438 }
439
440 if (!mDisplayContent.mUnknownAppVisibilityController.allResolved()) {
441 if (DEBUG_APP_TRANSITIONS) {
442 Slog.v(TAG, "unknownApps is not empty: "
443 + mDisplayContent.mUnknownAppVisibilityController.getDebugMessage());
444 }
445 return false;
446 }
447
448 // If the wallpaper is visible, we need to check it's ready too.
449 boolean wallpaperReady = !mWallpaperControllerLocked.isWallpaperVisible() ||
450 mWallpaperControllerLocked.wallpaperTransitionReady();
451 if (wallpaperReady) {
452 return true;
453 }
454 return false;
455 }
456 return true;
457 }
458
459 private int maybeUpdateTransitToWallpaper(int transit, boolean openingAppHasWallpaper,
460 boolean closingAppHasWallpaper) {
461 // Given no app transition pass it through instead of a wallpaper transition.
462 // Never convert the crashing transition.
463 // Never update the transition for the wallpaper if we are just docking from recents
464 if (transit == TRANSIT_NONE || transit == TRANSIT_CRASHING_ACTIVITY_CLOSE
465 || transit == TRANSIT_DOCK_TASK_FROM_RECENTS) {
466 return transit;
467 }
468
469 final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget();
470 final boolean showWallpaper = wallpaperTarget != null
471 && (wallpaperTarget.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0;
472 // If wallpaper is animating or wallpaperTarget doesn't have SHOW_WALLPAPER flag set,
473 // don't consider upgrading to wallpaper transition.
474 final WindowState oldWallpaper =
475 (mWallpaperControllerLocked.isWallpaperTargetAnimating() || !showWallpaper)
476 ? null
477 : wallpaperTarget;
478 final ArraySet<AppWindowToken> openingApps = mDisplayContent.mOpeningApps;
479 final ArraySet<AppWindowToken> closingApps = mDisplayContent.mClosingApps;
480 final AppWindowToken topOpeningApp = getTopApp(mDisplayContent.mOpeningApps,
481 false /* ignoreHidden */);
482 final AppWindowToken topClosingApp = getTopApp(mDisplayContent.mClosingApps,
483 true /* ignoreHidden */);
484
485 boolean openingCanBeWallpaperTarget = canBeWallpaperTarget(openingApps);
486 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
487 "New wallpaper target=" + wallpaperTarget
488 + ", oldWallpaper=" + oldWallpaper
489 + ", openingApps=" + openingApps
490 + ", closingApps=" + closingApps);
491
492 if (openingCanBeWallpaperTarget && transit == TRANSIT_KEYGUARD_GOING_AWAY) {
493 transit = TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
494 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
495 "New transit: " + AppTransition.appTransitionToString(transit));
496 }
497 // We never want to change from a Keyguard transit to a non-Keyguard transit, as our logic
498 // relies on the fact that we always execute a Keyguard transition after preparing one.
499 else if (!isKeyguardGoingAwayTransit(transit)) {
500 if (closingAppHasWallpaper && openingAppHasWallpaper) {
501 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Wallpaper animation!");
502 switch (transit) {
503 case TRANSIT_ACTIVITY_OPEN:
504 case TRANSIT_TASK_OPEN:
505 case TRANSIT_TASK_TO_FRONT:
506 transit = TRANSIT_WALLPAPER_INTRA_OPEN;
507 break;
508 case TRANSIT_ACTIVITY_CLOSE:
509 case TRANSIT_TASK_CLOSE:
510 case TRANSIT_TASK_TO_BACK:
511 transit = TRANSIT_WALLPAPER_INTRA_CLOSE;
512 break;
513 }
514 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
515 "New transit: " + AppTransition.appTransitionToString(transit));
516 } else if (oldWallpaper != null && !mDisplayContent.mOpeningApps.isEmpty()
517 && !openingApps.contains(oldWallpaper.mAppToken)
518 && closingApps.contains(oldWallpaper.mAppToken)
519 && topClosingApp == oldWallpaper.mAppToken) {
520 // We are transitioning from an activity with a wallpaper to one without.
521 transit = TRANSIT_WALLPAPER_CLOSE;
522 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit away from wallpaper: "
523 + AppTransition.appTransitionToString(transit));
524 } else if (wallpaperTarget != null && wallpaperTarget.isVisibleLw()
525 && openingApps.contains(wallpaperTarget.mAppToken)
526 && topOpeningApp == wallpaperTarget.mAppToken
527 && transit != TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE) {
528 // We are transitioning from an activity without
529 // a wallpaper to now showing the wallpaper
530 transit = TRANSIT_WALLPAPER_OPEN;
531 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit into wallpaper: "
532 + AppTransition.appTransitionToString(transit));
533 }
534 }
535 return transit;
536 }
537
538 /**
539 * There are cases where we open/close a new task/activity, but in reality only a translucent
540 * activity on top of existing activities is opening/closing. For that one, we have a different
541 * animation because non of the task/activity animations actually work well with translucent
542 * apps.
543 *
544 * @param transit The current transition type.
545 * @return The current transition type or
546 * {@link WindowManager#TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE}/
547 * {@link WindowManager#TRANSIT_TRANSLUCENT_ACTIVITY_OPEN} if appropriate for the
548 * situation.
549 */
550 @VisibleForTesting
551 int maybeUpdateTransitToTranslucentAnim(int transit) {
552 final boolean taskOrActivity = AppTransition.isTaskTransit(transit)
553 || AppTransition.isActivityTransit(transit);
554 boolean allOpeningVisible = true;
555 boolean allTranslucentOpeningApps = !mDisplayContent.mOpeningApps.isEmpty();
556 for (int i = mDisplayContent.mOpeningApps.size() - 1; i >= 0; i--) {
557 final AppWindowToken token = mDisplayContent.mOpeningApps.valueAt(i);
558 if (!token.isVisible()) {
559 allOpeningVisible = false;
560 if (token.fillsParent()) {
561 allTranslucentOpeningApps = false;
562 }
563 }
564 }
565 boolean allTranslucentClosingApps = !mDisplayContent.mClosingApps.isEmpty();
566 for (int i = mDisplayContent.mClosingApps.size() - 1; i >= 0; i--) {
567 if (mDisplayContent.mClosingApps.valueAt(i).fillsParent()) {
568 allTranslucentClosingApps = false;
569 break;
570 }
571 }
572
573 if (taskOrActivity && allTranslucentClosingApps && allOpeningVisible) {
574 return TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE;
575 }
576 if (taskOrActivity && allTranslucentOpeningApps && mDisplayContent.mClosingApps.isEmpty()) {
577 return TRANSIT_TRANSLUCENT_ACTIVITY_OPEN;
578 }
579 return transit;
580 }
581
582 private boolean canBeWallpaperTarget(ArraySet<AppWindowToken> apps) {
583 for (int i = apps.size() - 1; i >= 0; i--) {
584 if (apps.valueAt(i).windowsCanBeWallpaperTarget()) {
585 return true;
586 }
587 }
588 return false;
589 }
590
591 /**
592 * Finds the top app in a list of apps, using its {@link AppWindowToken#getPrefixOrderIndex} to
593 * compare z-order.
594 *
595 * @param apps The list of apps to search.
596 * @param ignoreHidden If set to true, ignores apps that are {@link AppWindowToken#isHidden}.
597 * @return The top {@link AppWindowToken}.
598 */
599 private AppWindowToken getTopApp(ArraySet<AppWindowToken> apps, boolean ignoreHidden) {
600 int topPrefixOrderIndex = Integer.MIN_VALUE;
601 AppWindowToken topApp = null;
602 for (int i = apps.size() - 1; i >= 0; i--) {
603 final AppWindowToken app = apps.valueAt(i);
604 if (ignoreHidden && app.isHidden()) {
605 continue;
606 }
607 final int prefixOrderIndex = app.getPrefixOrderIndex();
608 if (prefixOrderIndex > topPrefixOrderIndex) {
609 topPrefixOrderIndex = prefixOrderIndex;
610 topApp = app;
611 }
612 }
613 return topApp;
614 }
615
616 private void processApplicationsAnimatingInPlace(int transit) {
617 if (transit == TRANSIT_TASK_IN_PLACE) {
618 // Find the focused window
619 final WindowState win = mDisplayContent.findFocusedWindow();
620 if (win != null) {
621 final AppWindowToken wtoken = win.mAppToken;
622 if (DEBUG_APP_TRANSITIONS)
623 Slog.v(TAG, "Now animating app in place " + wtoken);
624 wtoken.cancelAnimation();
625 wtoken.applyAnimationLocked(null, transit, false, false);
626 wtoken.updateReportedVisibilityLocked();
627 wtoken.showAllWindowsLocked();
628 }
629 }
630 }
631}