blob: c9f985fc68cbd660bf260f277e36dac7718acb0d [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
lumark588a3e82018-07-20 18:53:54 +080054import android.os.Trace;
55import android.util.ArraySet;
56import android.util.Slog;
57import android.util.SparseIntArray;
58import android.view.Display;
59import android.view.RemoteAnimationAdapter;
60import android.view.RemoteAnimationDefinition;
61import android.view.WindowManager;
62import android.view.WindowManager.LayoutParams;
63import android.view.animation.Animation;
64
65import com.android.internal.annotations.VisibleForTesting;
66
67import java.util.function.Predicate;
68
69
70/**
71 * Checks for app transition readiness, resolves animation attributes and performs visibility
72 * change for apps that animate as part of an app transition.
73 */
74public class AppTransitionController {
75 private static final String TAG = TAG_WITH_CLASS_NAME ? "AppTransitionController" : TAG_WM;
76 private final WindowManagerService mService;
77 private final DisplayContent mDisplayContent;
78 private final WallpaperController mWallpaperControllerLocked;
79
80 private final SparseIntArray mTempTransitionReasons = new SparseIntArray();
81
82 AppTransitionController(WindowManagerService service, DisplayContent displayContent) {
83 mService = service;
84 mDisplayContent = displayContent;
wilsonshihc32538e2018-11-07 17:27:34 +080085 mWallpaperControllerLocked = mDisplayContent.mWallpaperController;
lumark588a3e82018-07-20 18:53:54 +080086 }
87
88 /**
89 * Handle application transition for given display.
90 */
91 void handleAppTransitionReady() {
Evan Rosky2289ba12018-11-19 18:28:18 -080092 mTempTransitionReasons.clear();
93 if (!transitionGoodToGo(mDisplayContent.mOpeningApps, mTempTransitionReasons)
94 || !transitionGoodToGo(mDisplayContent.mChangingApps, mTempTransitionReasons)) {
lumark588a3e82018-07-20 18:53:54 +080095 return;
96 }
97 Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "AppTransitionReady");
98
99 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
Tiger Huang7c610aa2018-10-27 00:01:01 +0800100 final AppTransition appTransition = mDisplayContent.mAppTransition;
101 int transit = appTransition.getAppTransition();
lumark588a3e82018-07-20 18:53:54 +0800102 if (mDisplayContent.mSkipAppTransitionAnimation && !isKeyguardGoingAwayTransit(transit)) {
103 transit = WindowManager.TRANSIT_UNSET;
104 }
105 mDisplayContent.mSkipAppTransitionAnimation = false;
106 mDisplayContent.mNoAnimationNotifyOnTransitionFinished.clear();
107
Tiger Huang7c610aa2018-10-27 00:01:01 +0800108 appTransition.removeAppTransitionTimeoutCallbacks();
lumark588a3e82018-07-20 18:53:54 +0800109
wilsonshihc32538e2018-11-07 17:27:34 +0800110 mDisplayContent.mWallpaperMayChange = false;
lumark588a3e82018-07-20 18:53:54 +0800111
Evan Rosky2289ba12018-11-19 18:28:18 -0800112 int appCount = mDisplayContent.mOpeningApps.size();
113 for (int i = 0; i < appCount; ++i) {
lumark588a3e82018-07-20 18:53:54 +0800114 // 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.
Evan Rosky2289ba12018-11-19 18:28:18 -0800118 mDisplayContent.mOpeningApps.valueAtUnchecked(i).clearAnimatingFlags();
119 }
120 appCount = mDisplayContent.mChangingApps.size();
121 for (int i = 0; i < appCount; ++i) {
122 // Clearing for same reason as above.
123 mDisplayContent.mChangingApps.valueAtUnchecked(i).clearAnimatingFlags();
lumark588a3e82018-07-20 18:53:54 +0800124 }
125
126 // Adjust wallpaper before we pull the lower/upper target, since pending changes
127 // (like the clearAnimatingFlags() above) might affect wallpaper target result.
128 // Or, the opening app window should be a wallpaper target.
wilsonshihc32538e2018-11-07 17:27:34 +0800129 mWallpaperControllerLocked.adjustWallpaperWindowsForAppTransitionIfNeeded(
Evan Rosky2289ba12018-11-19 18:28:18 -0800130 mDisplayContent.mOpeningApps, mDisplayContent.mChangingApps);
lumark588a3e82018-07-20 18:53:54 +0800131
132 // Determine if closing and opening app token sets are wallpaper targets, in which case
133 // special animations are needed.
134 final boolean hasWallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget() != null;
135 final boolean openingAppHasWallpaper = canBeWallpaperTarget(mDisplayContent.mOpeningApps)
136 && hasWallpaperTarget;
137 final boolean closingAppHasWallpaper = canBeWallpaperTarget(mDisplayContent.mClosingApps)
138 && hasWallpaperTarget;
139
140 transit = maybeUpdateTransitToTranslucentAnim(transit);
141 transit = maybeUpdateTransitToWallpaper(transit, openingAppHasWallpaper,
142 closingAppHasWallpaper);
143
144 // Find the layout params of the top-most application window in the tokens, which is
145 // what will control the animation theme. If all closing windows are obscured, then there is
146 // no need to do an animation. This is the case, for example, when this transition is being
147 // done behind a dream window.
148 final ArraySet<Integer> activityTypes = collectActivityTypes(mDisplayContent.mOpeningApps,
Evan Rosky2289ba12018-11-19 18:28:18 -0800149 mDisplayContent.mClosingApps, mDisplayContent.mChangingApps);
Tiger Huang7c610aa2018-10-27 00:01:01 +0800150 final boolean allowAnimations = mDisplayContent.getDisplayPolicy().allowAppAnimationsLw();
lumark588a3e82018-07-20 18:53:54 +0800151 final AppWindowToken animLpToken = allowAnimations
152 ? findAnimLayoutParamsToken(transit, activityTypes)
153 : null;
154 final AppWindowToken topOpeningApp = allowAnimations
155 ? getTopApp(mDisplayContent.mOpeningApps, false /* ignoreHidden */)
156 : null;
157 final AppWindowToken topClosingApp = allowAnimations
158 ? getTopApp(mDisplayContent.mClosingApps, false /* ignoreHidden */)
159 : null;
Evan Rosky2289ba12018-11-19 18:28:18 -0800160 final AppWindowToken topChangingApp = allowAnimations
161 ? getTopApp(mDisplayContent.mChangingApps, false /* ignoreHidden */)
162 : null;
lumark588a3e82018-07-20 18:53:54 +0800163 final WindowManager.LayoutParams animLp = getAnimLp(animLpToken);
164 overrideWithRemoteAnimationIfSet(animLpToken, transit, activityTypes);
165
166 final boolean voiceInteraction = containsVoiceInteraction(mDisplayContent.mOpeningApps)
Evan Rosky2289ba12018-11-19 18:28:18 -0800167 || containsVoiceInteraction(mDisplayContent.mOpeningApps)
168 || containsVoiceInteraction(mDisplayContent.mChangingApps);
lumark588a3e82018-07-20 18:53:54 +0800169
170 final int layoutRedo;
171 mService.mSurfaceAnimationRunner.deferStartingAnimations();
172 try {
173 processApplicationsAnimatingInPlace(transit);
174
175 handleClosingApps(transit, animLp, voiceInteraction);
176 handleOpeningApps(transit, animLp, voiceInteraction);
Evan Rosky2289ba12018-11-19 18:28:18 -0800177 handleChangingApps(transit, animLp, voiceInteraction);
lumark588a3e82018-07-20 18:53:54 +0800178
Tiger Huang7c610aa2018-10-27 00:01:01 +0800179 appTransition.setLastAppTransition(transit, topOpeningApp,
Evan Rosky2289ba12018-11-19 18:28:18 -0800180 topClosingApp, topChangingApp);
lumark588a3e82018-07-20 18:53:54 +0800181
Tiger Huang7c610aa2018-10-27 00:01:01 +0800182 final int flags = appTransition.getTransitFlags();
183 layoutRedo = appTransition.goodToGo(transit, topOpeningApp,
Evan Rosky2289ba12018-11-19 18:28:18 -0800184 mDisplayContent.mOpeningApps);
lumark588a3e82018-07-20 18:53:54 +0800185 handleNonAppWindowsInTransition(transit, flags);
Tiger Huang7c610aa2018-10-27 00:01:01 +0800186 appTransition.postAnimationCallback();
187 appTransition.clear();
lumark588a3e82018-07-20 18:53:54 +0800188 } finally {
189 mService.mSurfaceAnimationRunner.continueStartingAnimations();
190 }
191
192 mService.mTaskSnapshotController.onTransitionStarting(mDisplayContent);
193
194 mDisplayContent.mOpeningApps.clear();
195 mDisplayContent.mClosingApps.clear();
Evan Rosky2289ba12018-11-19 18:28:18 -0800196 mDisplayContent.mChangingApps.clear();
lumark588a3e82018-07-20 18:53:54 +0800197 mDisplayContent.mUnknownAppVisibilityController.clear();
198
199 // This has changed the visibility of windows, so perform
200 // a new layout to get them all up-to-date.
201 mDisplayContent.setLayoutNeeded();
202
203 mDisplayContent.computeImeTarget(true /* updateImeTarget */);
204
205 mService.mH.obtainMessage(NOTIFY_APP_TRANSITION_STARTING,
206 mTempTransitionReasons.clone()).sendToTarget();
207
208 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
209
210 mDisplayContent.pendingLayoutChanges |=
211 layoutRedo | FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG;
212 }
213
214 private static WindowManager.LayoutParams getAnimLp(AppWindowToken wtoken) {
215 final WindowState mainWindow = wtoken != null ? wtoken.findMainWindow() : null;
216 return mainWindow != null ? mainWindow.mAttrs : null;
217 }
218
219 /**
220 * Overrides the pending transition with the remote animation defined for the transition in the
221 * set of defined remote animations in the app window token.
222 */
223 private void overrideWithRemoteAnimationIfSet(AppWindowToken animLpToken, int transit,
224 ArraySet<Integer> activityTypes) {
225 if (transit == TRANSIT_CRASHING_ACTIVITY_CLOSE) {
226 // The crash transition has higher priority than any involved remote animations.
227 return;
228 }
229 if (animLpToken == null) {
230 return;
231 }
232 final RemoteAnimationDefinition definition = animLpToken.getRemoteAnimationDefinition();
233 if (definition == null) {
234 return;
235 }
236 final RemoteAnimationAdapter adapter = definition.getAdapter(transit, activityTypes);
237 if (adapter != null) {
238 animLpToken.getDisplayContent().mAppTransition.overridePendingAppTransitionRemote(
239 adapter);
240 }
241 }
242
243 /**
244 * @return The window token that determines the animation theme.
245 */
246 private AppWindowToken findAnimLayoutParamsToken(@WindowManager.TransitionType int transit,
247 ArraySet<Integer> activityTypes) {
248 AppWindowToken result;
249 final ArraySet<AppWindowToken> closingApps = mDisplayContent.mClosingApps;
250 final ArraySet<AppWindowToken> openingApps = mDisplayContent.mOpeningApps;
Evan Rosky2289ba12018-11-19 18:28:18 -0800251 final ArraySet<AppWindowToken> changingApps = mDisplayContent.mChangingApps;
lumark588a3e82018-07-20 18:53:54 +0800252
253 // Remote animations always win, but fullscreen tokens override non-fullscreen tokens.
Evan Rosky2289ba12018-11-19 18:28:18 -0800254 result = lookForHighestTokenWithFilter(closingApps, openingApps, changingApps,
lumark588a3e82018-07-20 18:53:54 +0800255 w -> w.getRemoteAnimationDefinition() != null
256 && w.getRemoteAnimationDefinition().hasTransition(transit, activityTypes));
257 if (result != null) {
258 return result;
259 }
Evan Rosky2289ba12018-11-19 18:28:18 -0800260 result = lookForHighestTokenWithFilter(closingApps, openingApps, changingApps,
lumark588a3e82018-07-20 18:53:54 +0800261 w -> w.fillsParent() && w.findMainWindow() != null);
262 if (result != null) {
263 return result;
264 }
Evan Rosky2289ba12018-11-19 18:28:18 -0800265 return lookForHighestTokenWithFilter(closingApps, openingApps, changingApps,
lumark588a3e82018-07-20 18:53:54 +0800266 w -> w.findMainWindow() != null);
267 }
268
269 /**
Tiger Huang7c610aa2018-10-27 00:01:01 +0800270 * @return The set of {@link android.app.WindowConfiguration.ActivityType}s contained in the set
Evan Rosky2289ba12018-11-19 18:28:18 -0800271 * of apps in {@code array1}, {@code array2}, and {@code array3}.
lumark588a3e82018-07-20 18:53:54 +0800272 */
273 private static ArraySet<Integer> collectActivityTypes(ArraySet<AppWindowToken> array1,
Evan Rosky2289ba12018-11-19 18:28:18 -0800274 ArraySet<AppWindowToken> array2, ArraySet<AppWindowToken> array3) {
lumark588a3e82018-07-20 18:53:54 +0800275 final ArraySet<Integer> result = new ArraySet<>();
276 for (int i = array1.size() - 1; i >= 0; i--) {
277 result.add(array1.valueAt(i).getActivityType());
278 }
279 for (int i = array2.size() - 1; i >= 0; i--) {
280 result.add(array2.valueAt(i).getActivityType());
281 }
Evan Rosky2289ba12018-11-19 18:28:18 -0800282 for (int i = array3.size() - 1; i >= 0; i--) {
283 result.add(array3.valueAt(i).getActivityType());
284 }
lumark588a3e82018-07-20 18:53:54 +0800285 return result;
286 }
287
288 private static AppWindowToken lookForHighestTokenWithFilter(ArraySet<AppWindowToken> array1,
Evan Rosky2289ba12018-11-19 18:28:18 -0800289 ArraySet<AppWindowToken> array2, ArraySet<AppWindowToken> array3,
290 Predicate<AppWindowToken> filter) {
291 final int array2base = array1.size();
292 final int array3base = array2.size() + array2base;
293 final int count = array3base + array3.size();
lumark588a3e82018-07-20 18:53:54 +0800294 int bestPrefixOrderIndex = Integer.MIN_VALUE;
295 AppWindowToken bestToken = null;
296 for (int i = 0; i < count; i++) {
Evan Rosky2289ba12018-11-19 18:28:18 -0800297 final AppWindowToken wtoken = i < array2base
lumark588a3e82018-07-20 18:53:54 +0800298 ? array1.valueAt(i)
Evan Rosky2289ba12018-11-19 18:28:18 -0800299 : (i < array3base
300 ? array2.valueAt(i - array2base)
301 : array3.valueAt(i - array3base));
lumark588a3e82018-07-20 18:53:54 +0800302 final int prefixOrderIndex = wtoken.getPrefixOrderIndex();
303 if (filter.test(wtoken) && prefixOrderIndex > bestPrefixOrderIndex) {
304 bestPrefixOrderIndex = prefixOrderIndex;
305 bestToken = wtoken;
306 }
307 }
308 return bestToken;
309 }
310
311 private boolean containsVoiceInteraction(ArraySet<AppWindowToken> apps) {
312 for (int i = apps.size() - 1; i >= 0; i--) {
313 if (apps.valueAt(i).mVoiceInteraction) {
314 return true;
315 }
316 }
317 return false;
318 }
319
320 private void handleOpeningApps(int transit, LayoutParams animLp, boolean voiceInteraction) {
321 final ArraySet<AppWindowToken> openingApps = mDisplayContent.mOpeningApps;
322 final int appsCount = openingApps.size();
323 for (int i = 0; i < appsCount; i++) {
324 AppWindowToken wtoken = openingApps.valueAt(i);
325 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken);
326
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800327 if (!wtoken.commitVisibility(animLp, true, transit, false, voiceInteraction)) {
lumark588a3e82018-07-20 18:53:54 +0800328 // This token isn't going to be animating. Add it to the list of tokens to
329 // be notified of app transition complete since the notification will not be
330 // sent be the app window animator.
331 mDisplayContent.mNoAnimationNotifyOnTransitionFinished.add(wtoken.token);
332 }
333 wtoken.updateReportedVisibilityLocked();
334 wtoken.waitingToShow = false;
335 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
336 ">>> OPEN TRANSACTION handleAppTransitionReady()");
337 mService.openSurfaceTransaction();
338 try {
339 wtoken.showAllWindowsLocked();
340 } finally {
341 mService.closeSurfaceTransaction("handleAppTransitionReady");
342 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
343 "<<< CLOSE TRANSACTION handleAppTransitionReady()");
344 }
345
346 if (mDisplayContent.mAppTransition.isNextAppTransitionThumbnailUp()) {
347 wtoken.attachThumbnailAnimation();
348 } else if (mDisplayContent.mAppTransition.isNextAppTransitionOpenCrossProfileApps()) {
349 wtoken.attachCrossProfileAppsThumbnailAnimation();
350 }
351 }
352 }
353
354 private void handleClosingApps(int transit, LayoutParams animLp, boolean voiceInteraction) {
355 final ArraySet<AppWindowToken> closingApps = mDisplayContent.mClosingApps;
356 final int appsCount = closingApps.size();
357 for (int i = 0; i < appsCount; i++) {
358 AppWindowToken wtoken = closingApps.valueAt(i);
359
360 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now closing app " + wtoken);
361 // TODO: Do we need to add to mNoAnimationNotifyOnTransitionFinished like above if not
362 // animating?
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800363 wtoken.commitVisibility(animLp, false, transit, false, voiceInteraction);
lumark588a3e82018-07-20 18:53:54 +0800364 wtoken.updateReportedVisibilityLocked();
365 // Force the allDrawn flag, because we want to start
366 // this guy's animations regardless of whether it's
367 // gotten drawn.
368 wtoken.allDrawn = true;
369 wtoken.deferClearAllDrawn = false;
370 // Ensure that apps that are mid-starting are also scheduled to have their
371 // starting windows removed after the animation is complete
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800372 if (wtoken.startingWindow != null && !wtoken.startingWindow.mAnimatingExit) {
373 wtoken.removeStartingWindow();
lumark588a3e82018-07-20 18:53:54 +0800374 }
375
376 if (mDisplayContent.mAppTransition.isNextAppTransitionThumbnailDown()) {
377 wtoken.attachThumbnailAnimation();
378 }
379 }
380 }
381
Evan Rosky2289ba12018-11-19 18:28:18 -0800382 private void handleChangingApps(int transit, LayoutParams animLp, boolean voiceInteraction) {
383 final ArraySet<AppWindowToken> apps = mDisplayContent.mChangingApps;
384 final int appsCount = apps.size();
385 for (int i = 0; i < appsCount; i++) {
386 AppWindowToken wtoken = apps.valueAt(i);
387 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now changing app" + wtoken);
388 wtoken.cancelAnimationOnly();
389 wtoken.applyAnimationLocked(null, transit, true, false);
390 wtoken.updateReportedVisibilityLocked();
391 mService.openSurfaceTransaction();
392 try {
393 wtoken.showAllWindowsLocked();
394 } finally {
395 mService.closeSurfaceTransaction("handleChangingApps");
396 }
397 }
398 }
399
lumark588a3e82018-07-20 18:53:54 +0800400 private void handleNonAppWindowsInTransition(int transit, int flags) {
401 if (transit == TRANSIT_KEYGUARD_GOING_AWAY) {
402 if ((flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0
403 && (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION) == 0) {
404 Animation anim = mService.mPolicy.createKeyguardWallpaperExit(
405 (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0);
406 if (anim != null) {
407 mDisplayContent.mWallpaperController.startWallpaperAnimation(anim);
408 }
409 }
410 }
411 if (transit == TRANSIT_KEYGUARD_GOING_AWAY
412 || transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER) {
413 mDisplayContent.startKeyguardExitOnNonAppWindows(
414 transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER,
415 (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0);
416 }
417 }
418
Evan Rosky2289ba12018-11-19 18:28:18 -0800419 private boolean transitionGoodToGo(ArraySet<AppWindowToken> apps, SparseIntArray outReasons) {
lumark588a3e82018-07-20 18:53:54 +0800420 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
Evan Rosky2289ba12018-11-19 18:28:18 -0800421 "Checking " + apps.size() + " opening apps (frozen="
lumark588a3e82018-07-20 18:53:54 +0800422 + mService.mDisplayFrozen + " timeout="
423 + mDisplayContent.mAppTransition.isTimeout() + ")...");
424 final ScreenRotationAnimation screenRotationAnimation =
425 mService.mAnimator.getScreenRotationAnimationLocked(
426 Display.DEFAULT_DISPLAY);
427
lumark588a3e82018-07-20 18:53:54 +0800428 if (!mDisplayContent.mAppTransition.isTimeout()) {
429 // Imagine the case where we are changing orientation due to an app transition, but a
430 // previous orientation change is still in progress. We won't process the orientation
431 // change for our transition because we need to wait for the rotation animation to
432 // finish.
433 // If we start the app transition at this point, we will interrupt it halfway with a
434 // new rotation animation after the old one finally finishes. It's better to defer the
435 // app transition.
436 if (screenRotationAnimation != null && screenRotationAnimation.isAnimating() &&
437 mService.getDefaultDisplayContentLocked().rotationNeedsUpdate()) {
438 if (DEBUG_APP_TRANSITIONS) {
439 Slog.v(TAG, "Delaying app transition for screen rotation animation to finish");
440 }
441 return false;
442 }
Evan Rosky2289ba12018-11-19 18:28:18 -0800443 for (int i = 0; i < apps.size(); i++) {
444 AppWindowToken wtoken = apps.valueAt(i);
lumark588a3e82018-07-20 18:53:54 +0800445 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
446 "Check opening app=" + wtoken + ": allDrawn="
447 + wtoken.allDrawn + " startingDisplayed="
448 + wtoken.startingDisplayed + " startingMoved="
449 + wtoken.startingMoved + " isRelaunching()="
450 + wtoken.isRelaunching() + " startingWindow="
451 + wtoken.startingWindow);
452
453
454 final boolean allDrawn = wtoken.allDrawn && !wtoken.isRelaunching();
455 if (!allDrawn && !wtoken.startingDisplayed && !wtoken.startingMoved) {
456 return false;
457 }
458 final int windowingMode = wtoken.getWindowingMode();
459 if (allDrawn) {
460 outReasons.put(windowingMode, APP_TRANSITION_WINDOWS_DRAWN);
461 } else {
462 outReasons.put(windowingMode,
463 wtoken.startingData instanceof SplashScreenStartingData
464 ? APP_TRANSITION_SPLASH_SCREEN
465 : APP_TRANSITION_SNAPSHOT);
466 }
467 }
468
469 // We also need to wait for the specs to be fetched, if needed.
470 if (mDisplayContent.mAppTransition.isFetchingAppTransitionsSpecs()) {
471 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "isFetchingAppTransitionSpecs=true");
472 return false;
473 }
474
475 if (!mDisplayContent.mUnknownAppVisibilityController.allResolved()) {
476 if (DEBUG_APP_TRANSITIONS) {
477 Slog.v(TAG, "unknownApps is not empty: "
478 + mDisplayContent.mUnknownAppVisibilityController.getDebugMessage());
479 }
480 return false;
481 }
482
483 // If the wallpaper is visible, we need to check it's ready too.
484 boolean wallpaperReady = !mWallpaperControllerLocked.isWallpaperVisible() ||
485 mWallpaperControllerLocked.wallpaperTransitionReady();
486 if (wallpaperReady) {
487 return true;
488 }
489 return false;
490 }
491 return true;
492 }
493
494 private int maybeUpdateTransitToWallpaper(int transit, boolean openingAppHasWallpaper,
495 boolean closingAppHasWallpaper) {
496 // Given no app transition pass it through instead of a wallpaper transition.
497 // Never convert the crashing transition.
498 // Never update the transition for the wallpaper if we are just docking from recents
499 if (transit == TRANSIT_NONE || transit == TRANSIT_CRASHING_ACTIVITY_CLOSE
500 || transit == TRANSIT_DOCK_TASK_FROM_RECENTS) {
501 return transit;
502 }
503
504 final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget();
505 final boolean showWallpaper = wallpaperTarget != null
506 && (wallpaperTarget.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0;
507 // If wallpaper is animating or wallpaperTarget doesn't have SHOW_WALLPAPER flag set,
508 // don't consider upgrading to wallpaper transition.
509 final WindowState oldWallpaper =
510 (mWallpaperControllerLocked.isWallpaperTargetAnimating() || !showWallpaper)
511 ? null
512 : wallpaperTarget;
513 final ArraySet<AppWindowToken> openingApps = mDisplayContent.mOpeningApps;
514 final ArraySet<AppWindowToken> closingApps = mDisplayContent.mClosingApps;
515 final AppWindowToken topOpeningApp = getTopApp(mDisplayContent.mOpeningApps,
516 false /* ignoreHidden */);
517 final AppWindowToken topClosingApp = getTopApp(mDisplayContent.mClosingApps,
518 true /* ignoreHidden */);
519
520 boolean openingCanBeWallpaperTarget = canBeWallpaperTarget(openingApps);
521 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
522 "New wallpaper target=" + wallpaperTarget
523 + ", oldWallpaper=" + oldWallpaper
524 + ", openingApps=" + openingApps
525 + ", closingApps=" + closingApps);
526
527 if (openingCanBeWallpaperTarget && transit == TRANSIT_KEYGUARD_GOING_AWAY) {
528 transit = TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
529 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
530 "New transit: " + AppTransition.appTransitionToString(transit));
531 }
532 // We never want to change from a Keyguard transit to a non-Keyguard transit, as our logic
533 // relies on the fact that we always execute a Keyguard transition after preparing one.
534 else if (!isKeyguardGoingAwayTransit(transit)) {
535 if (closingAppHasWallpaper && openingAppHasWallpaper) {
536 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Wallpaper animation!");
537 switch (transit) {
538 case TRANSIT_ACTIVITY_OPEN:
539 case TRANSIT_TASK_OPEN:
540 case TRANSIT_TASK_TO_FRONT:
541 transit = TRANSIT_WALLPAPER_INTRA_OPEN;
542 break;
543 case TRANSIT_ACTIVITY_CLOSE:
544 case TRANSIT_TASK_CLOSE:
545 case TRANSIT_TASK_TO_BACK:
546 transit = TRANSIT_WALLPAPER_INTRA_CLOSE;
547 break;
548 }
549 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
550 "New transit: " + AppTransition.appTransitionToString(transit));
551 } else if (oldWallpaper != null && !mDisplayContent.mOpeningApps.isEmpty()
552 && !openingApps.contains(oldWallpaper.mAppToken)
553 && closingApps.contains(oldWallpaper.mAppToken)
554 && topClosingApp == oldWallpaper.mAppToken) {
555 // We are transitioning from an activity with a wallpaper to one without.
556 transit = TRANSIT_WALLPAPER_CLOSE;
557 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit away from wallpaper: "
558 + AppTransition.appTransitionToString(transit));
559 } else if (wallpaperTarget != null && wallpaperTarget.isVisibleLw()
560 && openingApps.contains(wallpaperTarget.mAppToken)
561 && topOpeningApp == wallpaperTarget.mAppToken
562 && transit != TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE) {
563 // We are transitioning from an activity without
564 // a wallpaper to now showing the wallpaper
565 transit = TRANSIT_WALLPAPER_OPEN;
566 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit into wallpaper: "
567 + AppTransition.appTransitionToString(transit));
568 }
569 }
570 return transit;
571 }
572
573 /**
574 * There are cases where we open/close a new task/activity, but in reality only a translucent
575 * activity on top of existing activities is opening/closing. For that one, we have a different
576 * animation because non of the task/activity animations actually work well with translucent
577 * apps.
578 *
579 * @param transit The current transition type.
580 * @return The current transition type or
581 * {@link WindowManager#TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE}/
582 * {@link WindowManager#TRANSIT_TRANSLUCENT_ACTIVITY_OPEN} if appropriate for the
583 * situation.
584 */
585 @VisibleForTesting
586 int maybeUpdateTransitToTranslucentAnim(int transit) {
587 final boolean taskOrActivity = AppTransition.isTaskTransit(transit)
588 || AppTransition.isActivityTransit(transit);
589 boolean allOpeningVisible = true;
590 boolean allTranslucentOpeningApps = !mDisplayContent.mOpeningApps.isEmpty();
591 for (int i = mDisplayContent.mOpeningApps.size() - 1; i >= 0; i--) {
592 final AppWindowToken token = mDisplayContent.mOpeningApps.valueAt(i);
593 if (!token.isVisible()) {
594 allOpeningVisible = false;
595 if (token.fillsParent()) {
596 allTranslucentOpeningApps = false;
597 }
598 }
599 }
600 boolean allTranslucentClosingApps = !mDisplayContent.mClosingApps.isEmpty();
601 for (int i = mDisplayContent.mClosingApps.size() - 1; i >= 0; i--) {
602 if (mDisplayContent.mClosingApps.valueAt(i).fillsParent()) {
603 allTranslucentClosingApps = false;
604 break;
605 }
606 }
607
608 if (taskOrActivity && allTranslucentClosingApps && allOpeningVisible) {
609 return TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE;
610 }
611 if (taskOrActivity && allTranslucentOpeningApps && mDisplayContent.mClosingApps.isEmpty()) {
612 return TRANSIT_TRANSLUCENT_ACTIVITY_OPEN;
613 }
614 return transit;
615 }
616
617 private boolean canBeWallpaperTarget(ArraySet<AppWindowToken> apps) {
618 for (int i = apps.size() - 1; i >= 0; i--) {
619 if (apps.valueAt(i).windowsCanBeWallpaperTarget()) {
620 return true;
621 }
622 }
623 return false;
624 }
625
626 /**
627 * Finds the top app in a list of apps, using its {@link AppWindowToken#getPrefixOrderIndex} to
628 * compare z-order.
629 *
630 * @param apps The list of apps to search.
631 * @param ignoreHidden If set to true, ignores apps that are {@link AppWindowToken#isHidden}.
632 * @return The top {@link AppWindowToken}.
633 */
634 private AppWindowToken getTopApp(ArraySet<AppWindowToken> apps, boolean ignoreHidden) {
635 int topPrefixOrderIndex = Integer.MIN_VALUE;
636 AppWindowToken topApp = null;
637 for (int i = apps.size() - 1; i >= 0; i--) {
638 final AppWindowToken app = apps.valueAt(i);
639 if (ignoreHidden && app.isHidden()) {
640 continue;
641 }
642 final int prefixOrderIndex = app.getPrefixOrderIndex();
643 if (prefixOrderIndex > topPrefixOrderIndex) {
644 topPrefixOrderIndex = prefixOrderIndex;
645 topApp = app;
646 }
647 }
648 return topApp;
649 }
650
651 private void processApplicationsAnimatingInPlace(int transit) {
652 if (transit == TRANSIT_TASK_IN_PLACE) {
653 // Find the focused window
654 final WindowState win = mDisplayContent.findFocusedWindow();
655 if (win != null) {
656 final AppWindowToken wtoken = win.mAppToken;
657 if (DEBUG_APP_TRANSITIONS)
658 Slog.v(TAG, "Now animating app in place " + wtoken);
659 wtoken.cancelAnimation();
660 wtoken.applyAnimationLocked(null, transit, false, false);
661 wtoken.updateReportedVisibilityLocked();
662 wtoken.showAllWindowsLocked();
663 }
664 }
665 }
666}