blob: f63269571fc0245bff828f1cac04222bd33c68c0 [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;
lumark588a3e82018-07-20 18:53:54 +080052
Yunfan Chencafc7062019-01-22 17:21:32 +090053import android.os.SystemClock;
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;
Evan Rosky966759f2019-01-15 10:33:58 -080079 private RemoteAnimationDefinition mRemoteAnimationDefinition = null;
lumark588a3e82018-07-20 18:53:54 +080080
81 private final SparseIntArray mTempTransitionReasons = new SparseIntArray();
82
83 AppTransitionController(WindowManagerService service, DisplayContent displayContent) {
84 mService = service;
85 mDisplayContent = displayContent;
wilsonshihc32538e2018-11-07 17:27:34 +080086 mWallpaperControllerLocked = mDisplayContent.mWallpaperController;
lumark588a3e82018-07-20 18:53:54 +080087 }
88
Evan Rosky966759f2019-01-15 10:33:58 -080089 void registerRemoteAnimations(RemoteAnimationDefinition definition) {
90 mRemoteAnimationDefinition = definition;
91 }
92
lumark588a3e82018-07-20 18:53:54 +080093 /**
94 * Handle application transition for given display.
95 */
96 void handleAppTransitionReady() {
Evan Rosky2289ba12018-11-19 18:28:18 -080097 mTempTransitionReasons.clear();
98 if (!transitionGoodToGo(mDisplayContent.mOpeningApps, mTempTransitionReasons)
99 || !transitionGoodToGo(mDisplayContent.mChangingApps, mTempTransitionReasons)) {
lumark588a3e82018-07-20 18:53:54 +0800100 return;
101 }
102 Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "AppTransitionReady");
103
104 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
Tiger Huang7c610aa2018-10-27 00:01:01 +0800105 final AppTransition appTransition = mDisplayContent.mAppTransition;
106 int transit = appTransition.getAppTransition();
lumark588a3e82018-07-20 18:53:54 +0800107 if (mDisplayContent.mSkipAppTransitionAnimation && !isKeyguardGoingAwayTransit(transit)) {
108 transit = WindowManager.TRANSIT_UNSET;
109 }
110 mDisplayContent.mSkipAppTransitionAnimation = false;
111 mDisplayContent.mNoAnimationNotifyOnTransitionFinished.clear();
112
Tiger Huang7c610aa2018-10-27 00:01:01 +0800113 appTransition.removeAppTransitionTimeoutCallbacks();
lumark588a3e82018-07-20 18:53:54 +0800114
wilsonshihc32538e2018-11-07 17:27:34 +0800115 mDisplayContent.mWallpaperMayChange = false;
lumark588a3e82018-07-20 18:53:54 +0800116
Evan Rosky2289ba12018-11-19 18:28:18 -0800117 int appCount = mDisplayContent.mOpeningApps.size();
118 for (int i = 0; i < appCount; ++i) {
lumark588a3e82018-07-20 18:53:54 +0800119 // Clearing the mAnimatingExit flag before entering animation. It's set to true if app
120 // window is removed, or window relayout to invisible. This also affects window
121 // visibility. We need to clear it *before* maybeUpdateTransitToWallpaper() as the
122 // transition selection depends on wallpaper target visibility.
Evan Rosky2289ba12018-11-19 18:28:18 -0800123 mDisplayContent.mOpeningApps.valueAtUnchecked(i).clearAnimatingFlags();
124 }
125 appCount = mDisplayContent.mChangingApps.size();
126 for (int i = 0; i < appCount; ++i) {
127 // Clearing for same reason as above.
128 mDisplayContent.mChangingApps.valueAtUnchecked(i).clearAnimatingFlags();
lumark588a3e82018-07-20 18:53:54 +0800129 }
130
131 // Adjust wallpaper before we pull the lower/upper target, since pending changes
132 // (like the clearAnimatingFlags() above) might affect wallpaper target result.
133 // Or, the opening app window should be a wallpaper target.
wilsonshihc32538e2018-11-07 17:27:34 +0800134 mWallpaperControllerLocked.adjustWallpaperWindowsForAppTransitionIfNeeded(
Evan Rosky2289ba12018-11-19 18:28:18 -0800135 mDisplayContent.mOpeningApps, mDisplayContent.mChangingApps);
lumark588a3e82018-07-20 18:53:54 +0800136
137 // Determine if closing and opening app token sets are wallpaper targets, in which case
138 // special animations are needed.
139 final boolean hasWallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget() != null;
140 final boolean openingAppHasWallpaper = canBeWallpaperTarget(mDisplayContent.mOpeningApps)
141 && hasWallpaperTarget;
142 final boolean closingAppHasWallpaper = canBeWallpaperTarget(mDisplayContent.mClosingApps)
143 && hasWallpaperTarget;
144
145 transit = maybeUpdateTransitToTranslucentAnim(transit);
146 transit = maybeUpdateTransitToWallpaper(transit, openingAppHasWallpaper,
147 closingAppHasWallpaper);
148
149 // Find the layout params of the top-most application window in the tokens, which is
150 // what will control the animation theme. If all closing windows are obscured, then there is
151 // no need to do an animation. This is the case, for example, when this transition is being
152 // done behind a dream window.
153 final ArraySet<Integer> activityTypes = collectActivityTypes(mDisplayContent.mOpeningApps,
Evan Rosky2289ba12018-11-19 18:28:18 -0800154 mDisplayContent.mClosingApps, mDisplayContent.mChangingApps);
Tiger Huang7c610aa2018-10-27 00:01:01 +0800155 final boolean allowAnimations = mDisplayContent.getDisplayPolicy().allowAppAnimationsLw();
lumark588a3e82018-07-20 18:53:54 +0800156 final AppWindowToken animLpToken = allowAnimations
157 ? findAnimLayoutParamsToken(transit, activityTypes)
158 : null;
159 final AppWindowToken topOpeningApp = allowAnimations
160 ? getTopApp(mDisplayContent.mOpeningApps, false /* ignoreHidden */)
161 : null;
162 final AppWindowToken topClosingApp = allowAnimations
163 ? getTopApp(mDisplayContent.mClosingApps, false /* ignoreHidden */)
164 : null;
Evan Rosky2289ba12018-11-19 18:28:18 -0800165 final AppWindowToken topChangingApp = allowAnimations
166 ? getTopApp(mDisplayContent.mChangingApps, false /* ignoreHidden */)
167 : null;
lumark588a3e82018-07-20 18:53:54 +0800168 final WindowManager.LayoutParams animLp = getAnimLp(animLpToken);
169 overrideWithRemoteAnimationIfSet(animLpToken, transit, activityTypes);
170
171 final boolean voiceInteraction = containsVoiceInteraction(mDisplayContent.mOpeningApps)
Evan Rosky2289ba12018-11-19 18:28:18 -0800172 || containsVoiceInteraction(mDisplayContent.mOpeningApps)
173 || containsVoiceInteraction(mDisplayContent.mChangingApps);
lumark588a3e82018-07-20 18:53:54 +0800174
175 final int layoutRedo;
176 mService.mSurfaceAnimationRunner.deferStartingAnimations();
177 try {
178 processApplicationsAnimatingInPlace(transit);
179
180 handleClosingApps(transit, animLp, voiceInteraction);
181 handleOpeningApps(transit, animLp, voiceInteraction);
Evan Rosky2289ba12018-11-19 18:28:18 -0800182 handleChangingApps(transit, animLp, voiceInteraction);
lumark588a3e82018-07-20 18:53:54 +0800183
Tiger Huang7c610aa2018-10-27 00:01:01 +0800184 appTransition.setLastAppTransition(transit, topOpeningApp,
Evan Rosky2289ba12018-11-19 18:28:18 -0800185 topClosingApp, topChangingApp);
lumark588a3e82018-07-20 18:53:54 +0800186
Tiger Huang7c610aa2018-10-27 00:01:01 +0800187 final int flags = appTransition.getTransitFlags();
188 layoutRedo = appTransition.goodToGo(transit, topOpeningApp,
Evan Rosky2289ba12018-11-19 18:28:18 -0800189 mDisplayContent.mOpeningApps);
lumark588a3e82018-07-20 18:53:54 +0800190 handleNonAppWindowsInTransition(transit, flags);
Tiger Huang7c610aa2018-10-27 00:01:01 +0800191 appTransition.postAnimationCallback();
192 appTransition.clear();
lumark588a3e82018-07-20 18:53:54 +0800193 } finally {
194 mService.mSurfaceAnimationRunner.continueStartingAnimations();
195 }
196
197 mService.mTaskSnapshotController.onTransitionStarting(mDisplayContent);
198
199 mDisplayContent.mOpeningApps.clear();
200 mDisplayContent.mClosingApps.clear();
Evan Rosky2289ba12018-11-19 18:28:18 -0800201 mDisplayContent.mChangingApps.clear();
lumark588a3e82018-07-20 18:53:54 +0800202 mDisplayContent.mUnknownAppVisibilityController.clear();
203
204 // This has changed the visibility of windows, so perform
205 // a new layout to get them all up-to-date.
206 mDisplayContent.setLayoutNeeded();
207
208 mDisplayContent.computeImeTarget(true /* updateImeTarget */);
209
Yunfan Chencafc7062019-01-22 17:21:32 +0900210 mService.mAtmInternal.notifyAppTransitionStarting(mTempTransitionReasons.clone(),
211 SystemClock.uptimeMillis());
lumark588a3e82018-07-20 18:53:54 +0800212
213 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
214
215 mDisplayContent.pendingLayoutChanges |=
216 layoutRedo | FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG;
217 }
218
219 private static WindowManager.LayoutParams getAnimLp(AppWindowToken wtoken) {
220 final WindowState mainWindow = wtoken != null ? wtoken.findMainWindow() : null;
221 return mainWindow != null ? mainWindow.mAttrs : null;
222 }
223
Evan Rosky966759f2019-01-15 10:33:58 -0800224 RemoteAnimationAdapter getRemoteAnimationOverride(AppWindowToken animLpToken, int transit,
225 ArraySet<Integer> activityTypes) {
226 final RemoteAnimationDefinition definition = animLpToken.getRemoteAnimationDefinition();
227 if (definition != null) {
228 final RemoteAnimationAdapter adapter = definition.getAdapter(transit, activityTypes);
229 if (adapter != null) {
230 return adapter;
231 }
232 }
233 if (mRemoteAnimationDefinition == null) {
234 return null;
235 }
236 return mRemoteAnimationDefinition.getAdapter(transit, activityTypes);
237 }
238
lumark588a3e82018-07-20 18:53:54 +0800239 /**
240 * Overrides the pending transition with the remote animation defined for the transition in the
241 * set of defined remote animations in the app window token.
242 */
243 private void overrideWithRemoteAnimationIfSet(AppWindowToken animLpToken, int transit,
244 ArraySet<Integer> activityTypes) {
245 if (transit == TRANSIT_CRASHING_ACTIVITY_CLOSE) {
246 // The crash transition has higher priority than any involved remote animations.
247 return;
248 }
249 if (animLpToken == null) {
250 return;
251 }
Evan Rosky966759f2019-01-15 10:33:58 -0800252 final RemoteAnimationAdapter adapter =
253 getRemoteAnimationOverride(animLpToken, transit, activityTypes);
lumark588a3e82018-07-20 18:53:54 +0800254 if (adapter != null) {
255 animLpToken.getDisplayContent().mAppTransition.overridePendingAppTransitionRemote(
256 adapter);
257 }
258 }
259
260 /**
261 * @return The window token that determines the animation theme.
262 */
263 private AppWindowToken findAnimLayoutParamsToken(@WindowManager.TransitionType int transit,
264 ArraySet<Integer> activityTypes) {
265 AppWindowToken result;
266 final ArraySet<AppWindowToken> closingApps = mDisplayContent.mClosingApps;
267 final ArraySet<AppWindowToken> openingApps = mDisplayContent.mOpeningApps;
Evan Rosky2289ba12018-11-19 18:28:18 -0800268 final ArraySet<AppWindowToken> changingApps = mDisplayContent.mChangingApps;
lumark588a3e82018-07-20 18:53:54 +0800269
270 // Remote animations always win, but fullscreen tokens override non-fullscreen tokens.
Evan Rosky2289ba12018-11-19 18:28:18 -0800271 result = lookForHighestTokenWithFilter(closingApps, openingApps, changingApps,
lumark588a3e82018-07-20 18:53:54 +0800272 w -> w.getRemoteAnimationDefinition() != null
273 && w.getRemoteAnimationDefinition().hasTransition(transit, activityTypes));
274 if (result != null) {
275 return result;
276 }
Evan Rosky2289ba12018-11-19 18:28:18 -0800277 result = lookForHighestTokenWithFilter(closingApps, openingApps, changingApps,
lumark588a3e82018-07-20 18:53:54 +0800278 w -> w.fillsParent() && w.findMainWindow() != null);
279 if (result != null) {
280 return result;
281 }
Evan Rosky2289ba12018-11-19 18:28:18 -0800282 return lookForHighestTokenWithFilter(closingApps, openingApps, changingApps,
lumark588a3e82018-07-20 18:53:54 +0800283 w -> w.findMainWindow() != null);
284 }
285
286 /**
Tiger Huang7c610aa2018-10-27 00:01:01 +0800287 * @return The set of {@link android.app.WindowConfiguration.ActivityType}s contained in the set
Evan Rosky2289ba12018-11-19 18:28:18 -0800288 * of apps in {@code array1}, {@code array2}, and {@code array3}.
lumark588a3e82018-07-20 18:53:54 +0800289 */
290 private static ArraySet<Integer> collectActivityTypes(ArraySet<AppWindowToken> array1,
Evan Rosky2289ba12018-11-19 18:28:18 -0800291 ArraySet<AppWindowToken> array2, ArraySet<AppWindowToken> array3) {
lumark588a3e82018-07-20 18:53:54 +0800292 final ArraySet<Integer> result = new ArraySet<>();
293 for (int i = array1.size() - 1; i >= 0; i--) {
294 result.add(array1.valueAt(i).getActivityType());
295 }
296 for (int i = array2.size() - 1; i >= 0; i--) {
297 result.add(array2.valueAt(i).getActivityType());
298 }
Evan Rosky2289ba12018-11-19 18:28:18 -0800299 for (int i = array3.size() - 1; i >= 0; i--) {
300 result.add(array3.valueAt(i).getActivityType());
301 }
lumark588a3e82018-07-20 18:53:54 +0800302 return result;
303 }
304
305 private static AppWindowToken lookForHighestTokenWithFilter(ArraySet<AppWindowToken> array1,
Evan Rosky2289ba12018-11-19 18:28:18 -0800306 ArraySet<AppWindowToken> array2, ArraySet<AppWindowToken> array3,
307 Predicate<AppWindowToken> filter) {
308 final int array2base = array1.size();
309 final int array3base = array2.size() + array2base;
310 final int count = array3base + array3.size();
lumark588a3e82018-07-20 18:53:54 +0800311 int bestPrefixOrderIndex = Integer.MIN_VALUE;
312 AppWindowToken bestToken = null;
313 for (int i = 0; i < count; i++) {
Evan Rosky2289ba12018-11-19 18:28:18 -0800314 final AppWindowToken wtoken = i < array2base
lumark588a3e82018-07-20 18:53:54 +0800315 ? array1.valueAt(i)
Evan Rosky2289ba12018-11-19 18:28:18 -0800316 : (i < array3base
317 ? array2.valueAt(i - array2base)
318 : array3.valueAt(i - array3base));
lumark588a3e82018-07-20 18:53:54 +0800319 final int prefixOrderIndex = wtoken.getPrefixOrderIndex();
320 if (filter.test(wtoken) && prefixOrderIndex > bestPrefixOrderIndex) {
321 bestPrefixOrderIndex = prefixOrderIndex;
322 bestToken = wtoken;
323 }
324 }
325 return bestToken;
326 }
327
328 private boolean containsVoiceInteraction(ArraySet<AppWindowToken> apps) {
329 for (int i = apps.size() - 1; i >= 0; i--) {
330 if (apps.valueAt(i).mVoiceInteraction) {
331 return true;
332 }
333 }
334 return false;
335 }
336
337 private void handleOpeningApps(int transit, LayoutParams animLp, boolean voiceInteraction) {
338 final ArraySet<AppWindowToken> openingApps = mDisplayContent.mOpeningApps;
339 final int appsCount = openingApps.size();
340 for (int i = 0; i < appsCount; i++) {
341 AppWindowToken wtoken = openingApps.valueAt(i);
342 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken);
343
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800344 if (!wtoken.commitVisibility(animLp, true, transit, false, voiceInteraction)) {
lumark588a3e82018-07-20 18:53:54 +0800345 // This token isn't going to be animating. Add it to the list of tokens to
346 // be notified of app transition complete since the notification will not be
347 // sent be the app window animator.
348 mDisplayContent.mNoAnimationNotifyOnTransitionFinished.add(wtoken.token);
349 }
350 wtoken.updateReportedVisibilityLocked();
351 wtoken.waitingToShow = false;
352 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
353 ">>> OPEN TRANSACTION handleAppTransitionReady()");
354 mService.openSurfaceTransaction();
355 try {
356 wtoken.showAllWindowsLocked();
357 } finally {
358 mService.closeSurfaceTransaction("handleAppTransitionReady");
359 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
360 "<<< CLOSE TRANSACTION handleAppTransitionReady()");
361 }
362
363 if (mDisplayContent.mAppTransition.isNextAppTransitionThumbnailUp()) {
364 wtoken.attachThumbnailAnimation();
365 } else if (mDisplayContent.mAppTransition.isNextAppTransitionOpenCrossProfileApps()) {
366 wtoken.attachCrossProfileAppsThumbnailAnimation();
367 }
368 }
369 }
370
371 private void handleClosingApps(int transit, LayoutParams animLp, boolean voiceInteraction) {
372 final ArraySet<AppWindowToken> closingApps = mDisplayContent.mClosingApps;
373 final int appsCount = closingApps.size();
374 for (int i = 0; i < appsCount; i++) {
375 AppWindowToken wtoken = closingApps.valueAt(i);
376
377 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now closing app " + wtoken);
378 // TODO: Do we need to add to mNoAnimationNotifyOnTransitionFinished like above if not
379 // animating?
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800380 wtoken.commitVisibility(animLp, false, transit, false, voiceInteraction);
lumark588a3e82018-07-20 18:53:54 +0800381 wtoken.updateReportedVisibilityLocked();
382 // Force the allDrawn flag, because we want to start
383 // this guy's animations regardless of whether it's
384 // gotten drawn.
385 wtoken.allDrawn = true;
386 wtoken.deferClearAllDrawn = false;
387 // Ensure that apps that are mid-starting are also scheduled to have their
388 // starting windows removed after the animation is complete
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800389 if (wtoken.startingWindow != null && !wtoken.startingWindow.mAnimatingExit) {
390 wtoken.removeStartingWindow();
lumark588a3e82018-07-20 18:53:54 +0800391 }
392
393 if (mDisplayContent.mAppTransition.isNextAppTransitionThumbnailDown()) {
394 wtoken.attachThumbnailAnimation();
395 }
396 }
397 }
398
Evan Rosky2289ba12018-11-19 18:28:18 -0800399 private void handleChangingApps(int transit, LayoutParams animLp, boolean voiceInteraction) {
400 final ArraySet<AppWindowToken> apps = mDisplayContent.mChangingApps;
401 final int appsCount = apps.size();
402 for (int i = 0; i < appsCount; i++) {
403 AppWindowToken wtoken = apps.valueAt(i);
404 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now changing app" + wtoken);
405 wtoken.cancelAnimationOnly();
406 wtoken.applyAnimationLocked(null, transit, true, false);
407 wtoken.updateReportedVisibilityLocked();
408 mService.openSurfaceTransaction();
409 try {
410 wtoken.showAllWindowsLocked();
411 } finally {
412 mService.closeSurfaceTransaction("handleChangingApps");
413 }
414 }
415 }
416
lumark588a3e82018-07-20 18:53:54 +0800417 private void handleNonAppWindowsInTransition(int transit, int flags) {
418 if (transit == TRANSIT_KEYGUARD_GOING_AWAY) {
419 if ((flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0
420 && (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION) == 0) {
421 Animation anim = mService.mPolicy.createKeyguardWallpaperExit(
422 (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0);
423 if (anim != null) {
424 mDisplayContent.mWallpaperController.startWallpaperAnimation(anim);
425 }
426 }
427 }
428 if (transit == TRANSIT_KEYGUARD_GOING_AWAY
429 || transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER) {
430 mDisplayContent.startKeyguardExitOnNonAppWindows(
431 transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER,
432 (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0);
433 }
434 }
435
Evan Rosky2289ba12018-11-19 18:28:18 -0800436 private boolean transitionGoodToGo(ArraySet<AppWindowToken> apps, SparseIntArray outReasons) {
lumark588a3e82018-07-20 18:53:54 +0800437 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
Evan Rosky2289ba12018-11-19 18:28:18 -0800438 "Checking " + apps.size() + " opening apps (frozen="
lumark588a3e82018-07-20 18:53:54 +0800439 + mService.mDisplayFrozen + " timeout="
440 + mDisplayContent.mAppTransition.isTimeout() + ")...");
441 final ScreenRotationAnimation screenRotationAnimation =
442 mService.mAnimator.getScreenRotationAnimationLocked(
443 Display.DEFAULT_DISPLAY);
444
lumark588a3e82018-07-20 18:53:54 +0800445 if (!mDisplayContent.mAppTransition.isTimeout()) {
446 // Imagine the case where we are changing orientation due to an app transition, but a
447 // previous orientation change is still in progress. We won't process the orientation
448 // change for our transition because we need to wait for the rotation animation to
449 // finish.
450 // If we start the app transition at this point, we will interrupt it halfway with a
451 // new rotation animation after the old one finally finishes. It's better to defer the
452 // app transition.
453 if (screenRotationAnimation != null && screenRotationAnimation.isAnimating() &&
454 mService.getDefaultDisplayContentLocked().rotationNeedsUpdate()) {
455 if (DEBUG_APP_TRANSITIONS) {
456 Slog.v(TAG, "Delaying app transition for screen rotation animation to finish");
457 }
458 return false;
459 }
Evan Rosky2289ba12018-11-19 18:28:18 -0800460 for (int i = 0; i < apps.size(); i++) {
461 AppWindowToken wtoken = apps.valueAt(i);
lumark588a3e82018-07-20 18:53:54 +0800462 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
463 "Check opening app=" + wtoken + ": allDrawn="
464 + wtoken.allDrawn + " startingDisplayed="
465 + wtoken.startingDisplayed + " startingMoved="
466 + wtoken.startingMoved + " isRelaunching()="
467 + wtoken.isRelaunching() + " startingWindow="
468 + wtoken.startingWindow);
469
470
471 final boolean allDrawn = wtoken.allDrawn && !wtoken.isRelaunching();
472 if (!allDrawn && !wtoken.startingDisplayed && !wtoken.startingMoved) {
473 return false;
474 }
475 final int windowingMode = wtoken.getWindowingMode();
476 if (allDrawn) {
477 outReasons.put(windowingMode, APP_TRANSITION_WINDOWS_DRAWN);
478 } else {
479 outReasons.put(windowingMode,
480 wtoken.startingData instanceof SplashScreenStartingData
481 ? APP_TRANSITION_SPLASH_SCREEN
482 : APP_TRANSITION_SNAPSHOT);
483 }
484 }
485
486 // We also need to wait for the specs to be fetched, if needed.
487 if (mDisplayContent.mAppTransition.isFetchingAppTransitionsSpecs()) {
488 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "isFetchingAppTransitionSpecs=true");
489 return false;
490 }
491
492 if (!mDisplayContent.mUnknownAppVisibilityController.allResolved()) {
493 if (DEBUG_APP_TRANSITIONS) {
494 Slog.v(TAG, "unknownApps is not empty: "
495 + mDisplayContent.mUnknownAppVisibilityController.getDebugMessage());
496 }
497 return false;
498 }
499
500 // If the wallpaper is visible, we need to check it's ready too.
501 boolean wallpaperReady = !mWallpaperControllerLocked.isWallpaperVisible() ||
502 mWallpaperControllerLocked.wallpaperTransitionReady();
503 if (wallpaperReady) {
504 return true;
505 }
506 return false;
507 }
508 return true;
509 }
510
511 private int maybeUpdateTransitToWallpaper(int transit, boolean openingAppHasWallpaper,
512 boolean closingAppHasWallpaper) {
513 // Given no app transition pass it through instead of a wallpaper transition.
514 // Never convert the crashing transition.
515 // Never update the transition for the wallpaper if we are just docking from recents
Evan Roskyec9488c2019-03-01 19:32:12 -0800516 // Never convert a change transition since the top activity isn't changing and will likely
517 // still be above an opening wallpaper.
lumark588a3e82018-07-20 18:53:54 +0800518 if (transit == TRANSIT_NONE || transit == TRANSIT_CRASHING_ACTIVITY_CLOSE
Evan Roskyec9488c2019-03-01 19:32:12 -0800519 || transit == TRANSIT_DOCK_TASK_FROM_RECENTS
520 || AppTransition.isChangeTransit(transit)) {
lumark588a3e82018-07-20 18:53:54 +0800521 return transit;
522 }
523
524 final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget();
525 final boolean showWallpaper = wallpaperTarget != null
526 && (wallpaperTarget.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0;
527 // If wallpaper is animating or wallpaperTarget doesn't have SHOW_WALLPAPER flag set,
528 // don't consider upgrading to wallpaper transition.
529 final WindowState oldWallpaper =
530 (mWallpaperControllerLocked.isWallpaperTargetAnimating() || !showWallpaper)
531 ? null
532 : wallpaperTarget;
533 final ArraySet<AppWindowToken> openingApps = mDisplayContent.mOpeningApps;
534 final ArraySet<AppWindowToken> closingApps = mDisplayContent.mClosingApps;
535 final AppWindowToken topOpeningApp = getTopApp(mDisplayContent.mOpeningApps,
536 false /* ignoreHidden */);
537 final AppWindowToken topClosingApp = getTopApp(mDisplayContent.mClosingApps,
538 true /* ignoreHidden */);
539
540 boolean openingCanBeWallpaperTarget = canBeWallpaperTarget(openingApps);
541 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
542 "New wallpaper target=" + wallpaperTarget
543 + ", oldWallpaper=" + oldWallpaper
544 + ", openingApps=" + openingApps
545 + ", closingApps=" + closingApps);
546
547 if (openingCanBeWallpaperTarget && transit == TRANSIT_KEYGUARD_GOING_AWAY) {
548 transit = TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
549 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
550 "New transit: " + AppTransition.appTransitionToString(transit));
551 }
552 // We never want to change from a Keyguard transit to a non-Keyguard transit, as our logic
553 // relies on the fact that we always execute a Keyguard transition after preparing one.
554 else if (!isKeyguardGoingAwayTransit(transit)) {
555 if (closingAppHasWallpaper && openingAppHasWallpaper) {
556 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Wallpaper animation!");
557 switch (transit) {
558 case TRANSIT_ACTIVITY_OPEN:
559 case TRANSIT_TASK_OPEN:
560 case TRANSIT_TASK_TO_FRONT:
561 transit = TRANSIT_WALLPAPER_INTRA_OPEN;
562 break;
563 case TRANSIT_ACTIVITY_CLOSE:
564 case TRANSIT_TASK_CLOSE:
565 case TRANSIT_TASK_TO_BACK:
566 transit = TRANSIT_WALLPAPER_INTRA_CLOSE;
567 break;
568 }
569 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
570 "New transit: " + AppTransition.appTransitionToString(transit));
571 } else if (oldWallpaper != null && !mDisplayContent.mOpeningApps.isEmpty()
572 && !openingApps.contains(oldWallpaper.mAppToken)
573 && closingApps.contains(oldWallpaper.mAppToken)
574 && topClosingApp == oldWallpaper.mAppToken) {
575 // We are transitioning from an activity with a wallpaper to one without.
576 transit = TRANSIT_WALLPAPER_CLOSE;
577 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit away from wallpaper: "
578 + AppTransition.appTransitionToString(transit));
579 } else if (wallpaperTarget != null && wallpaperTarget.isVisibleLw()
580 && openingApps.contains(wallpaperTarget.mAppToken)
581 && topOpeningApp == wallpaperTarget.mAppToken
582 && transit != TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE) {
583 // We are transitioning from an activity without
584 // a wallpaper to now showing the wallpaper
585 transit = TRANSIT_WALLPAPER_OPEN;
586 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit into wallpaper: "
587 + AppTransition.appTransitionToString(transit));
588 }
589 }
590 return transit;
591 }
592
593 /**
594 * There are cases where we open/close a new task/activity, but in reality only a translucent
595 * activity on top of existing activities is opening/closing. For that one, we have a different
596 * animation because non of the task/activity animations actually work well with translucent
597 * apps.
598 *
599 * @param transit The current transition type.
600 * @return The current transition type or
601 * {@link WindowManager#TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE}/
602 * {@link WindowManager#TRANSIT_TRANSLUCENT_ACTIVITY_OPEN} if appropriate for the
603 * situation.
604 */
605 @VisibleForTesting
606 int maybeUpdateTransitToTranslucentAnim(int transit) {
Evan Roskyec9488c2019-03-01 19:32:12 -0800607 if (AppTransition.isChangeTransit(transit)) {
608 // There's no special animation to handle change animations with translucent apps
609 return transit;
610 }
lumark588a3e82018-07-20 18:53:54 +0800611 final boolean taskOrActivity = AppTransition.isTaskTransit(transit)
612 || AppTransition.isActivityTransit(transit);
613 boolean allOpeningVisible = true;
614 boolean allTranslucentOpeningApps = !mDisplayContent.mOpeningApps.isEmpty();
615 for (int i = mDisplayContent.mOpeningApps.size() - 1; i >= 0; i--) {
616 final AppWindowToken token = mDisplayContent.mOpeningApps.valueAt(i);
617 if (!token.isVisible()) {
618 allOpeningVisible = false;
619 if (token.fillsParent()) {
620 allTranslucentOpeningApps = false;
621 }
622 }
623 }
624 boolean allTranslucentClosingApps = !mDisplayContent.mClosingApps.isEmpty();
625 for (int i = mDisplayContent.mClosingApps.size() - 1; i >= 0; i--) {
626 if (mDisplayContent.mClosingApps.valueAt(i).fillsParent()) {
627 allTranslucentClosingApps = false;
628 break;
629 }
630 }
631
632 if (taskOrActivity && allTranslucentClosingApps && allOpeningVisible) {
633 return TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE;
634 }
635 if (taskOrActivity && allTranslucentOpeningApps && mDisplayContent.mClosingApps.isEmpty()) {
636 return TRANSIT_TRANSLUCENT_ACTIVITY_OPEN;
637 }
638 return transit;
639 }
640
641 private boolean canBeWallpaperTarget(ArraySet<AppWindowToken> apps) {
642 for (int i = apps.size() - 1; i >= 0; i--) {
643 if (apps.valueAt(i).windowsCanBeWallpaperTarget()) {
644 return true;
645 }
646 }
647 return false;
648 }
649
650 /**
651 * Finds the top app in a list of apps, using its {@link AppWindowToken#getPrefixOrderIndex} to
652 * compare z-order.
653 *
654 * @param apps The list of apps to search.
655 * @param ignoreHidden If set to true, ignores apps that are {@link AppWindowToken#isHidden}.
656 * @return The top {@link AppWindowToken}.
657 */
658 private AppWindowToken getTopApp(ArraySet<AppWindowToken> apps, boolean ignoreHidden) {
659 int topPrefixOrderIndex = Integer.MIN_VALUE;
660 AppWindowToken topApp = null;
661 for (int i = apps.size() - 1; i >= 0; i--) {
662 final AppWindowToken app = apps.valueAt(i);
663 if (ignoreHidden && app.isHidden()) {
664 continue;
665 }
666 final int prefixOrderIndex = app.getPrefixOrderIndex();
667 if (prefixOrderIndex > topPrefixOrderIndex) {
668 topPrefixOrderIndex = prefixOrderIndex;
669 topApp = app;
670 }
671 }
672 return topApp;
673 }
674
675 private void processApplicationsAnimatingInPlace(int transit) {
676 if (transit == TRANSIT_TASK_IN_PLACE) {
677 // Find the focused window
678 final WindowState win = mDisplayContent.findFocusedWindow();
679 if (win != null) {
680 final AppWindowToken wtoken = win.mAppToken;
681 if (DEBUG_APP_TRANSITIONS)
682 Slog.v(TAG, "Now animating app in place " + wtoken);
683 wtoken.cancelAnimation();
684 wtoken.applyAnimationLocked(null, transit, false, false);
685 wtoken.updateReportedVisibilityLocked();
686 wtoken.showAllWindowsLocked();
687 }
688 }
689 }
690}