blob: d4e95cfb8025c5095a8b62f61f6ad1eb8e470963 [file] [log] [blame]
lumark588a3e82018-07-20 18:53:54 +08001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
17package com.android.server.wm;
18
19import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
20import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE;
21import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
Evan Rosky7735d352019-03-18 17:27:27 -070022import static android.view.WindowManager.TRANSIT_ACTIVITY_RELAUNCH;
lumark588a3e82018-07-20 18:53:54 +080023import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE;
24import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
25import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
Issei Suzuki5609ccb2019-06-13 15:04:08 +020026import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION;
lumark588a3e82018-07-20 18:53:54 +080027import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
28import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
29import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
30import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
31import static android.view.WindowManager.TRANSIT_NONE;
Issei Suzukicac2a502019-04-16 16:52:50 +020032import static android.view.WindowManager.TRANSIT_SHOW_SINGLE_TASK_DISPLAY;
lumark588a3e82018-07-20 18:53:54 +080033import static android.view.WindowManager.TRANSIT_TASK_CLOSE;
34import static android.view.WindowManager.TRANSIT_TASK_IN_PLACE;
35import static android.view.WindowManager.TRANSIT_TASK_OPEN;
36import static android.view.WindowManager.TRANSIT_TASK_TO_BACK;
37import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
38import static android.view.WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE;
39import static android.view.WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_OPEN;
40import static android.view.WindowManager.TRANSIT_WALLPAPER_CLOSE;
41import static android.view.WindowManager.TRANSIT_WALLPAPER_INTRA_CLOSE;
42import static android.view.WindowManager.TRANSIT_WALLPAPER_INTRA_OPEN;
43import static android.view.WindowManager.TRANSIT_WALLPAPER_OPEN;
44
45import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
46import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
47import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_SNAPSHOT;
48import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_SPLASH_SCREEN;
49import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_WINDOWS_DRAWN;
50import static com.android.server.wm.AppTransition.isKeyguardGoingAwayTransit;
51import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
52import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
53import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
54import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
lumark588a3e82018-07-20 18:53:54 +080055
Yunfan Chencafc7062019-01-22 17:21:32 +090056import android.os.SystemClock;
lumark588a3e82018-07-20 18:53:54 +080057import android.os.Trace;
58import android.util.ArraySet;
59import android.util.Slog;
60import android.util.SparseIntArray;
61import android.view.Display;
62import android.view.RemoteAnimationAdapter;
63import android.view.RemoteAnimationDefinition;
64import android.view.WindowManager;
65import android.view.WindowManager.LayoutParams;
66import android.view.animation.Animation;
67
68import com.android.internal.annotations.VisibleForTesting;
69
70import java.util.function.Predicate;
71
72
73/**
74 * Checks for app transition readiness, resolves animation attributes and performs visibility
75 * change for apps that animate as part of an app transition.
76 */
77public class AppTransitionController {
78 private static final String TAG = TAG_WITH_CLASS_NAME ? "AppTransitionController" : TAG_WM;
79 private final WindowManagerService mService;
80 private final DisplayContent mDisplayContent;
81 private final WallpaperController mWallpaperControllerLocked;
Evan Rosky966759f2019-01-15 10:33:58 -080082 private RemoteAnimationDefinition mRemoteAnimationDefinition = null;
lumark588a3e82018-07-20 18:53:54 +080083
84 private final SparseIntArray mTempTransitionReasons = new SparseIntArray();
85
86 AppTransitionController(WindowManagerService service, DisplayContent displayContent) {
87 mService = service;
88 mDisplayContent = displayContent;
wilsonshihc32538e2018-11-07 17:27:34 +080089 mWallpaperControllerLocked = mDisplayContent.mWallpaperController;
lumark588a3e82018-07-20 18:53:54 +080090 }
91
Evan Rosky966759f2019-01-15 10:33:58 -080092 void registerRemoteAnimations(RemoteAnimationDefinition definition) {
93 mRemoteAnimationDefinition = definition;
94 }
95
lumark588a3e82018-07-20 18:53:54 +080096 /**
97 * Handle application transition for given display.
98 */
99 void handleAppTransitionReady() {
Evan Rosky2289ba12018-11-19 18:28:18 -0800100 mTempTransitionReasons.clear();
101 if (!transitionGoodToGo(mDisplayContent.mOpeningApps, mTempTransitionReasons)
102 || !transitionGoodToGo(mDisplayContent.mChangingApps, mTempTransitionReasons)) {
lumark588a3e82018-07-20 18:53:54 +0800103 return;
104 }
105 Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "AppTransitionReady");
106
107 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
Tiger Huang7c610aa2018-10-27 00:01:01 +0800108 final AppTransition appTransition = mDisplayContent.mAppTransition;
109 int transit = appTransition.getAppTransition();
lumark588a3e82018-07-20 18:53:54 +0800110 if (mDisplayContent.mSkipAppTransitionAnimation && !isKeyguardGoingAwayTransit(transit)) {
111 transit = WindowManager.TRANSIT_UNSET;
112 }
113 mDisplayContent.mSkipAppTransitionAnimation = false;
114 mDisplayContent.mNoAnimationNotifyOnTransitionFinished.clear();
115
Tiger Huang7c610aa2018-10-27 00:01:01 +0800116 appTransition.removeAppTransitionTimeoutCallbacks();
lumark588a3e82018-07-20 18:53:54 +0800117
wilsonshihc32538e2018-11-07 17:27:34 +0800118 mDisplayContent.mWallpaperMayChange = false;
lumark588a3e82018-07-20 18:53:54 +0800119
Evan Rosky2289ba12018-11-19 18:28:18 -0800120 int appCount = mDisplayContent.mOpeningApps.size();
121 for (int i = 0; i < appCount; ++i) {
lumark588a3e82018-07-20 18:53:54 +0800122 // Clearing the mAnimatingExit flag before entering animation. It's set to true if app
123 // window is removed, or window relayout to invisible. This also affects window
124 // visibility. We need to clear it *before* maybeUpdateTransitToWallpaper() as the
125 // transition selection depends on wallpaper target visibility.
Evan Rosky2289ba12018-11-19 18:28:18 -0800126 mDisplayContent.mOpeningApps.valueAtUnchecked(i).clearAnimatingFlags();
127 }
128 appCount = mDisplayContent.mChangingApps.size();
129 for (int i = 0; i < appCount; ++i) {
130 // Clearing for same reason as above.
131 mDisplayContent.mChangingApps.valueAtUnchecked(i).clearAnimatingFlags();
lumark588a3e82018-07-20 18:53:54 +0800132 }
133
134 // Adjust wallpaper before we pull the lower/upper target, since pending changes
135 // (like the clearAnimatingFlags() above) might affect wallpaper target result.
136 // Or, the opening app window should be a wallpaper target.
wilsonshihc32538e2018-11-07 17:27:34 +0800137 mWallpaperControllerLocked.adjustWallpaperWindowsForAppTransitionIfNeeded(
Evan Rosky2289ba12018-11-19 18:28:18 -0800138 mDisplayContent.mOpeningApps, mDisplayContent.mChangingApps);
lumark588a3e82018-07-20 18:53:54 +0800139
140 // Determine if closing and opening app token sets are wallpaper targets, in which case
141 // special animations are needed.
142 final boolean hasWallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget() != null;
143 final boolean openingAppHasWallpaper = canBeWallpaperTarget(mDisplayContent.mOpeningApps)
144 && hasWallpaperTarget;
145 final boolean closingAppHasWallpaper = canBeWallpaperTarget(mDisplayContent.mClosingApps)
146 && hasWallpaperTarget;
147
148 transit = maybeUpdateTransitToTranslucentAnim(transit);
149 transit = maybeUpdateTransitToWallpaper(transit, openingAppHasWallpaper,
150 closingAppHasWallpaper);
151
152 // Find the layout params of the top-most application window in the tokens, which is
153 // what will control the animation theme. If all closing windows are obscured, then there is
154 // no need to do an animation. This is the case, for example, when this transition is being
155 // done behind a dream window.
156 final ArraySet<Integer> activityTypes = collectActivityTypes(mDisplayContent.mOpeningApps,
Evan Rosky2289ba12018-11-19 18:28:18 -0800157 mDisplayContent.mClosingApps, mDisplayContent.mChangingApps);
Tiger Huang7c610aa2018-10-27 00:01:01 +0800158 final boolean allowAnimations = mDisplayContent.getDisplayPolicy().allowAppAnimationsLw();
lumark588a3e82018-07-20 18:53:54 +0800159 final AppWindowToken animLpToken = allowAnimations
160 ? findAnimLayoutParamsToken(transit, activityTypes)
161 : null;
162 final AppWindowToken topOpeningApp = allowAnimations
163 ? getTopApp(mDisplayContent.mOpeningApps, false /* ignoreHidden */)
164 : null;
165 final AppWindowToken topClosingApp = allowAnimations
166 ? getTopApp(mDisplayContent.mClosingApps, false /* ignoreHidden */)
167 : null;
Evan Rosky2289ba12018-11-19 18:28:18 -0800168 final AppWindowToken topChangingApp = allowAnimations
169 ? getTopApp(mDisplayContent.mChangingApps, false /* ignoreHidden */)
170 : null;
lumark588a3e82018-07-20 18:53:54 +0800171 final WindowManager.LayoutParams animLp = getAnimLp(animLpToken);
172 overrideWithRemoteAnimationIfSet(animLpToken, transit, activityTypes);
173
174 final boolean voiceInteraction = containsVoiceInteraction(mDisplayContent.mOpeningApps)
Evan Rosky2289ba12018-11-19 18:28:18 -0800175 || containsVoiceInteraction(mDisplayContent.mOpeningApps)
176 || containsVoiceInteraction(mDisplayContent.mChangingApps);
lumark588a3e82018-07-20 18:53:54 +0800177
178 final int layoutRedo;
179 mService.mSurfaceAnimationRunner.deferStartingAnimations();
180 try {
181 processApplicationsAnimatingInPlace(transit);
182
183 handleClosingApps(transit, animLp, voiceInteraction);
184 handleOpeningApps(transit, animLp, voiceInteraction);
Evan Rosky2289ba12018-11-19 18:28:18 -0800185 handleChangingApps(transit, animLp, voiceInteraction);
lumark588a3e82018-07-20 18:53:54 +0800186
Tiger Huang7c610aa2018-10-27 00:01:01 +0800187 appTransition.setLastAppTransition(transit, topOpeningApp,
Evan Rosky2289ba12018-11-19 18:28:18 -0800188 topClosingApp, topChangingApp);
lumark588a3e82018-07-20 18:53:54 +0800189
Tiger Huang7c610aa2018-10-27 00:01:01 +0800190 final int flags = appTransition.getTransitFlags();
191 layoutRedo = appTransition.goodToGo(transit, topOpeningApp,
Evan Rosky2289ba12018-11-19 18:28:18 -0800192 mDisplayContent.mOpeningApps);
lumark588a3e82018-07-20 18:53:54 +0800193 handleNonAppWindowsInTransition(transit, flags);
Tiger Huang7c610aa2018-10-27 00:01:01 +0800194 appTransition.postAnimationCallback();
195 appTransition.clear();
lumark588a3e82018-07-20 18:53:54 +0800196 } finally {
197 mService.mSurfaceAnimationRunner.continueStartingAnimations();
198 }
199
200 mService.mTaskSnapshotController.onTransitionStarting(mDisplayContent);
201
202 mDisplayContent.mOpeningApps.clear();
203 mDisplayContent.mClosingApps.clear();
Evan Rosky2289ba12018-11-19 18:28:18 -0800204 mDisplayContent.mChangingApps.clear();
lumark588a3e82018-07-20 18:53:54 +0800205 mDisplayContent.mUnknownAppVisibilityController.clear();
206
207 // This has changed the visibility of windows, so perform
208 // a new layout to get them all up-to-date.
209 mDisplayContent.setLayoutNeeded();
210
211 mDisplayContent.computeImeTarget(true /* updateImeTarget */);
212
Yunfan Chencafc7062019-01-22 17:21:32 +0900213 mService.mAtmInternal.notifyAppTransitionStarting(mTempTransitionReasons.clone(),
214 SystemClock.uptimeMillis());
lumark588a3e82018-07-20 18:53:54 +0800215
Issei Suzukicac2a502019-04-16 16:52:50 +0200216 if (transit == TRANSIT_SHOW_SINGLE_TASK_DISPLAY) {
217 mService.mAnimator.addAfterPrepareSurfacesRunnable(() -> {
218 mService.mAtmInternal.notifySingleTaskDisplayDrawn(mDisplayContent.getDisplayId());
219 });
220 }
221
lumark588a3e82018-07-20 18:53:54 +0800222 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
223
224 mDisplayContent.pendingLayoutChanges |=
225 layoutRedo | FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG;
226 }
227
228 private static WindowManager.LayoutParams getAnimLp(AppWindowToken wtoken) {
229 final WindowState mainWindow = wtoken != null ? wtoken.findMainWindow() : null;
230 return mainWindow != null ? mainWindow.mAttrs : null;
231 }
232
Evan Rosky966759f2019-01-15 10:33:58 -0800233 RemoteAnimationAdapter getRemoteAnimationOverride(AppWindowToken animLpToken, int transit,
234 ArraySet<Integer> activityTypes) {
235 final RemoteAnimationDefinition definition = animLpToken.getRemoteAnimationDefinition();
236 if (definition != null) {
237 final RemoteAnimationAdapter adapter = definition.getAdapter(transit, activityTypes);
238 if (adapter != null) {
239 return adapter;
240 }
241 }
242 if (mRemoteAnimationDefinition == null) {
243 return null;
244 }
245 return mRemoteAnimationDefinition.getAdapter(transit, activityTypes);
246 }
247
lumark588a3e82018-07-20 18:53:54 +0800248 /**
249 * Overrides the pending transition with the remote animation defined for the transition in the
250 * set of defined remote animations in the app window token.
251 */
252 private void overrideWithRemoteAnimationIfSet(AppWindowToken animLpToken, int transit,
253 ArraySet<Integer> activityTypes) {
254 if (transit == TRANSIT_CRASHING_ACTIVITY_CLOSE) {
255 // The crash transition has higher priority than any involved remote animations.
256 return;
257 }
258 if (animLpToken == null) {
259 return;
260 }
Evan Rosky966759f2019-01-15 10:33:58 -0800261 final RemoteAnimationAdapter adapter =
262 getRemoteAnimationOverride(animLpToken, transit, activityTypes);
lumark588a3e82018-07-20 18:53:54 +0800263 if (adapter != null) {
264 animLpToken.getDisplayContent().mAppTransition.overridePendingAppTransitionRemote(
265 adapter);
266 }
267 }
268
269 /**
270 * @return The window token that determines the animation theme.
271 */
272 private AppWindowToken findAnimLayoutParamsToken(@WindowManager.TransitionType int transit,
273 ArraySet<Integer> activityTypes) {
274 AppWindowToken result;
275 final ArraySet<AppWindowToken> closingApps = mDisplayContent.mClosingApps;
276 final ArraySet<AppWindowToken> openingApps = mDisplayContent.mOpeningApps;
Evan Rosky2289ba12018-11-19 18:28:18 -0800277 final ArraySet<AppWindowToken> changingApps = mDisplayContent.mChangingApps;
lumark588a3e82018-07-20 18:53:54 +0800278
279 // Remote animations always win, but fullscreen tokens override non-fullscreen tokens.
Evan Rosky2289ba12018-11-19 18:28:18 -0800280 result = lookForHighestTokenWithFilter(closingApps, openingApps, changingApps,
lumark588a3e82018-07-20 18:53:54 +0800281 w -> w.getRemoteAnimationDefinition() != null
282 && w.getRemoteAnimationDefinition().hasTransition(transit, activityTypes));
283 if (result != null) {
284 return result;
285 }
Evan Rosky2289ba12018-11-19 18:28:18 -0800286 result = lookForHighestTokenWithFilter(closingApps, openingApps, changingApps,
lumark588a3e82018-07-20 18:53:54 +0800287 w -> w.fillsParent() && w.findMainWindow() != null);
288 if (result != null) {
289 return result;
290 }
Evan Rosky2289ba12018-11-19 18:28:18 -0800291 return lookForHighestTokenWithFilter(closingApps, openingApps, changingApps,
lumark588a3e82018-07-20 18:53:54 +0800292 w -> w.findMainWindow() != null);
293 }
294
295 /**
Tiger Huang7c610aa2018-10-27 00:01:01 +0800296 * @return The set of {@link android.app.WindowConfiguration.ActivityType}s contained in the set
Evan Rosky2289ba12018-11-19 18:28:18 -0800297 * of apps in {@code array1}, {@code array2}, and {@code array3}.
lumark588a3e82018-07-20 18:53:54 +0800298 */
299 private static ArraySet<Integer> collectActivityTypes(ArraySet<AppWindowToken> array1,
Evan Rosky2289ba12018-11-19 18:28:18 -0800300 ArraySet<AppWindowToken> array2, ArraySet<AppWindowToken> array3) {
lumark588a3e82018-07-20 18:53:54 +0800301 final ArraySet<Integer> result = new ArraySet<>();
302 for (int i = array1.size() - 1; i >= 0; i--) {
303 result.add(array1.valueAt(i).getActivityType());
304 }
305 for (int i = array2.size() - 1; i >= 0; i--) {
306 result.add(array2.valueAt(i).getActivityType());
307 }
Evan Rosky2289ba12018-11-19 18:28:18 -0800308 for (int i = array3.size() - 1; i >= 0; i--) {
309 result.add(array3.valueAt(i).getActivityType());
310 }
lumark588a3e82018-07-20 18:53:54 +0800311 return result;
312 }
313
314 private static AppWindowToken lookForHighestTokenWithFilter(ArraySet<AppWindowToken> array1,
Evan Rosky2289ba12018-11-19 18:28:18 -0800315 ArraySet<AppWindowToken> array2, ArraySet<AppWindowToken> array3,
316 Predicate<AppWindowToken> filter) {
317 final int array2base = array1.size();
318 final int array3base = array2.size() + array2base;
319 final int count = array3base + array3.size();
lumark588a3e82018-07-20 18:53:54 +0800320 int bestPrefixOrderIndex = Integer.MIN_VALUE;
321 AppWindowToken bestToken = null;
322 for (int i = 0; i < count; i++) {
Evan Rosky2289ba12018-11-19 18:28:18 -0800323 final AppWindowToken wtoken = i < array2base
lumark588a3e82018-07-20 18:53:54 +0800324 ? array1.valueAt(i)
Evan Rosky2289ba12018-11-19 18:28:18 -0800325 : (i < array3base
326 ? array2.valueAt(i - array2base)
327 : array3.valueAt(i - array3base));
lumark588a3e82018-07-20 18:53:54 +0800328 final int prefixOrderIndex = wtoken.getPrefixOrderIndex();
329 if (filter.test(wtoken) && prefixOrderIndex > bestPrefixOrderIndex) {
330 bestPrefixOrderIndex = prefixOrderIndex;
331 bestToken = wtoken;
332 }
333 }
334 return bestToken;
335 }
336
337 private boolean containsVoiceInteraction(ArraySet<AppWindowToken> apps) {
338 for (int i = apps.size() - 1; i >= 0; i--) {
339 if (apps.valueAt(i).mVoiceInteraction) {
340 return true;
341 }
342 }
343 return false;
344 }
345
346 private void handleOpeningApps(int transit, LayoutParams animLp, boolean voiceInteraction) {
347 final ArraySet<AppWindowToken> openingApps = mDisplayContent.mOpeningApps;
348 final int appsCount = openingApps.size();
349 for (int i = 0; i < appsCount; i++) {
350 AppWindowToken wtoken = openingApps.valueAt(i);
351 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken);
352
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800353 if (!wtoken.commitVisibility(animLp, true, transit, false, voiceInteraction)) {
lumark588a3e82018-07-20 18:53:54 +0800354 // This token isn't going to be animating. Add it to the list of tokens to
355 // be notified of app transition complete since the notification will not be
356 // sent be the app window animator.
357 mDisplayContent.mNoAnimationNotifyOnTransitionFinished.add(wtoken.token);
358 }
359 wtoken.updateReportedVisibilityLocked();
360 wtoken.waitingToShow = false;
361 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
362 ">>> OPEN TRANSACTION handleAppTransitionReady()");
363 mService.openSurfaceTransaction();
364 try {
365 wtoken.showAllWindowsLocked();
366 } finally {
367 mService.closeSurfaceTransaction("handleAppTransitionReady");
368 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
369 "<<< CLOSE TRANSACTION handleAppTransitionReady()");
370 }
371
372 if (mDisplayContent.mAppTransition.isNextAppTransitionThumbnailUp()) {
373 wtoken.attachThumbnailAnimation();
374 } else if (mDisplayContent.mAppTransition.isNextAppTransitionOpenCrossProfileApps()) {
375 wtoken.attachCrossProfileAppsThumbnailAnimation();
376 }
377 }
378 }
379
380 private void handleClosingApps(int transit, LayoutParams animLp, boolean voiceInteraction) {
381 final ArraySet<AppWindowToken> closingApps = mDisplayContent.mClosingApps;
382 final int appsCount = closingApps.size();
383 for (int i = 0; i < appsCount; i++) {
384 AppWindowToken wtoken = closingApps.valueAt(i);
385
386 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now closing app " + wtoken);
387 // TODO: Do we need to add to mNoAnimationNotifyOnTransitionFinished like above if not
388 // animating?
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800389 wtoken.commitVisibility(animLp, false, transit, false, voiceInteraction);
lumark588a3e82018-07-20 18:53:54 +0800390 wtoken.updateReportedVisibilityLocked();
391 // Force the allDrawn flag, because we want to start
392 // this guy's animations regardless of whether it's
393 // gotten drawn.
394 wtoken.allDrawn = true;
395 wtoken.deferClearAllDrawn = false;
396 // Ensure that apps that are mid-starting are also scheduled to have their
397 // starting windows removed after the animation is complete
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800398 if (wtoken.startingWindow != null && !wtoken.startingWindow.mAnimatingExit) {
399 wtoken.removeStartingWindow();
lumark588a3e82018-07-20 18:53:54 +0800400 }
401
402 if (mDisplayContent.mAppTransition.isNextAppTransitionThumbnailDown()) {
403 wtoken.attachThumbnailAnimation();
404 }
405 }
406 }
407
Evan Rosky2289ba12018-11-19 18:28:18 -0800408 private void handleChangingApps(int transit, LayoutParams animLp, boolean voiceInteraction) {
409 final ArraySet<AppWindowToken> apps = mDisplayContent.mChangingApps;
410 final int appsCount = apps.size();
411 for (int i = 0; i < appsCount; i++) {
412 AppWindowToken wtoken = apps.valueAt(i);
413 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now changing app" + wtoken);
414 wtoken.cancelAnimationOnly();
415 wtoken.applyAnimationLocked(null, transit, true, false);
416 wtoken.updateReportedVisibilityLocked();
417 mService.openSurfaceTransaction();
418 try {
419 wtoken.showAllWindowsLocked();
420 } finally {
421 mService.closeSurfaceTransaction("handleChangingApps");
422 }
423 }
424 }
425
lumark588a3e82018-07-20 18:53:54 +0800426 private void handleNonAppWindowsInTransition(int transit, int flags) {
427 if (transit == TRANSIT_KEYGUARD_GOING_AWAY) {
428 if ((flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0
Issei Suzuki5609ccb2019-06-13 15:04:08 +0200429 && (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION) == 0
430 && (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION) == 0) {
lumark588a3e82018-07-20 18:53:54 +0800431 Animation anim = mService.mPolicy.createKeyguardWallpaperExit(
432 (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0);
433 if (anim != null) {
434 mDisplayContent.mWallpaperController.startWallpaperAnimation(anim);
435 }
436 }
437 }
438 if (transit == TRANSIT_KEYGUARD_GOING_AWAY
439 || transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER) {
440 mDisplayContent.startKeyguardExitOnNonAppWindows(
441 transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER,
Issei Suzuki5609ccb2019-06-13 15:04:08 +0200442 (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0,
443 (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION) != 0);
lumark588a3e82018-07-20 18:53:54 +0800444 }
445 }
446
Evan Rosky2289ba12018-11-19 18:28:18 -0800447 private boolean transitionGoodToGo(ArraySet<AppWindowToken> apps, SparseIntArray outReasons) {
lumark588a3e82018-07-20 18:53:54 +0800448 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
Evan Rosky2289ba12018-11-19 18:28:18 -0800449 "Checking " + apps.size() + " opening apps (frozen="
lumark588a3e82018-07-20 18:53:54 +0800450 + mService.mDisplayFrozen + " timeout="
451 + mDisplayContent.mAppTransition.isTimeout() + ")...");
452 final ScreenRotationAnimation screenRotationAnimation =
453 mService.mAnimator.getScreenRotationAnimationLocked(
454 Display.DEFAULT_DISPLAY);
455
lumark588a3e82018-07-20 18:53:54 +0800456 if (!mDisplayContent.mAppTransition.isTimeout()) {
457 // Imagine the case where we are changing orientation due to an app transition, but a
458 // previous orientation change is still in progress. We won't process the orientation
459 // change for our transition because we need to wait for the rotation animation to
460 // finish.
461 // If we start the app transition at this point, we will interrupt it halfway with a
462 // new rotation animation after the old one finally finishes. It's better to defer the
463 // app transition.
464 if (screenRotationAnimation != null && screenRotationAnimation.isAnimating() &&
465 mService.getDefaultDisplayContentLocked().rotationNeedsUpdate()) {
466 if (DEBUG_APP_TRANSITIONS) {
467 Slog.v(TAG, "Delaying app transition for screen rotation animation to finish");
468 }
469 return false;
470 }
Evan Rosky2289ba12018-11-19 18:28:18 -0800471 for (int i = 0; i < apps.size(); i++) {
472 AppWindowToken wtoken = apps.valueAt(i);
lumark588a3e82018-07-20 18:53:54 +0800473 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
474 "Check opening app=" + wtoken + ": allDrawn="
475 + wtoken.allDrawn + " startingDisplayed="
476 + wtoken.startingDisplayed + " startingMoved="
477 + wtoken.startingMoved + " isRelaunching()="
478 + wtoken.isRelaunching() + " startingWindow="
479 + wtoken.startingWindow);
480
481
482 final boolean allDrawn = wtoken.allDrawn && !wtoken.isRelaunching();
483 if (!allDrawn && !wtoken.startingDisplayed && !wtoken.startingMoved) {
484 return false;
485 }
486 final int windowingMode = wtoken.getWindowingMode();
487 if (allDrawn) {
488 outReasons.put(windowingMode, APP_TRANSITION_WINDOWS_DRAWN);
489 } else {
490 outReasons.put(windowingMode,
chaviwa8f07a72019-05-01 16:25:39 -0700491 wtoken.mStartingData instanceof SplashScreenStartingData
lumark588a3e82018-07-20 18:53:54 +0800492 ? APP_TRANSITION_SPLASH_SCREEN
493 : APP_TRANSITION_SNAPSHOT);
494 }
495 }
496
497 // We also need to wait for the specs to be fetched, if needed.
498 if (mDisplayContent.mAppTransition.isFetchingAppTransitionsSpecs()) {
499 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "isFetchingAppTransitionSpecs=true");
500 return false;
501 }
502
503 if (!mDisplayContent.mUnknownAppVisibilityController.allResolved()) {
504 if (DEBUG_APP_TRANSITIONS) {
505 Slog.v(TAG, "unknownApps is not empty: "
506 + mDisplayContent.mUnknownAppVisibilityController.getDebugMessage());
507 }
508 return false;
509 }
510
511 // If the wallpaper is visible, we need to check it's ready too.
512 boolean wallpaperReady = !mWallpaperControllerLocked.isWallpaperVisible() ||
513 mWallpaperControllerLocked.wallpaperTransitionReady();
514 if (wallpaperReady) {
515 return true;
516 }
517 return false;
518 }
519 return true;
520 }
521
522 private int maybeUpdateTransitToWallpaper(int transit, boolean openingAppHasWallpaper,
523 boolean closingAppHasWallpaper) {
524 // Given no app transition pass it through instead of a wallpaper transition.
525 // Never convert the crashing transition.
526 // Never update the transition for the wallpaper if we are just docking from recents
Evan Roskyec9488c2019-03-01 19:32:12 -0800527 // Never convert a change transition since the top activity isn't changing and will likely
528 // still be above an opening wallpaper.
lumark588a3e82018-07-20 18:53:54 +0800529 if (transit == TRANSIT_NONE || transit == TRANSIT_CRASHING_ACTIVITY_CLOSE
Evan Roskyec9488c2019-03-01 19:32:12 -0800530 || transit == TRANSIT_DOCK_TASK_FROM_RECENTS
531 || AppTransition.isChangeTransit(transit)) {
lumark588a3e82018-07-20 18:53:54 +0800532 return transit;
533 }
534
535 final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget();
536 final boolean showWallpaper = wallpaperTarget != null
537 && (wallpaperTarget.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0;
538 // If wallpaper is animating or wallpaperTarget doesn't have SHOW_WALLPAPER flag set,
539 // don't consider upgrading to wallpaper transition.
540 final WindowState oldWallpaper =
541 (mWallpaperControllerLocked.isWallpaperTargetAnimating() || !showWallpaper)
542 ? null
543 : wallpaperTarget;
544 final ArraySet<AppWindowToken> openingApps = mDisplayContent.mOpeningApps;
545 final ArraySet<AppWindowToken> closingApps = mDisplayContent.mClosingApps;
546 final AppWindowToken topOpeningApp = getTopApp(mDisplayContent.mOpeningApps,
547 false /* ignoreHidden */);
548 final AppWindowToken topClosingApp = getTopApp(mDisplayContent.mClosingApps,
549 true /* ignoreHidden */);
550
551 boolean openingCanBeWallpaperTarget = canBeWallpaperTarget(openingApps);
552 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
553 "New wallpaper target=" + wallpaperTarget
554 + ", oldWallpaper=" + oldWallpaper
555 + ", openingApps=" + openingApps
556 + ", closingApps=" + closingApps);
557
558 if (openingCanBeWallpaperTarget && transit == TRANSIT_KEYGUARD_GOING_AWAY) {
559 transit = TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
560 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
561 "New transit: " + AppTransition.appTransitionToString(transit));
562 }
563 // We never want to change from a Keyguard transit to a non-Keyguard transit, as our logic
564 // relies on the fact that we always execute a Keyguard transition after preparing one.
565 else if (!isKeyguardGoingAwayTransit(transit)) {
566 if (closingAppHasWallpaper && openingAppHasWallpaper) {
567 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Wallpaper animation!");
568 switch (transit) {
569 case TRANSIT_ACTIVITY_OPEN:
570 case TRANSIT_TASK_OPEN:
571 case TRANSIT_TASK_TO_FRONT:
572 transit = TRANSIT_WALLPAPER_INTRA_OPEN;
573 break;
574 case TRANSIT_ACTIVITY_CLOSE:
575 case TRANSIT_TASK_CLOSE:
576 case TRANSIT_TASK_TO_BACK:
577 transit = TRANSIT_WALLPAPER_INTRA_CLOSE;
578 break;
579 }
580 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
581 "New transit: " + AppTransition.appTransitionToString(transit));
582 } else if (oldWallpaper != null && !mDisplayContent.mOpeningApps.isEmpty()
583 && !openingApps.contains(oldWallpaper.mAppToken)
584 && closingApps.contains(oldWallpaper.mAppToken)
585 && topClosingApp == oldWallpaper.mAppToken) {
586 // We are transitioning from an activity with a wallpaper to one without.
587 transit = TRANSIT_WALLPAPER_CLOSE;
588 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit away from wallpaper: "
589 + AppTransition.appTransitionToString(transit));
590 } else if (wallpaperTarget != null && wallpaperTarget.isVisibleLw()
591 && openingApps.contains(wallpaperTarget.mAppToken)
592 && topOpeningApp == wallpaperTarget.mAppToken
593 && transit != TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE) {
594 // We are transitioning from an activity without
595 // a wallpaper to now showing the wallpaper
596 transit = TRANSIT_WALLPAPER_OPEN;
597 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit into wallpaper: "
598 + AppTransition.appTransitionToString(transit));
599 }
600 }
601 return transit;
602 }
603
604 /**
605 * There are cases where we open/close a new task/activity, but in reality only a translucent
606 * activity on top of existing activities is opening/closing. For that one, we have a different
607 * animation because non of the task/activity animations actually work well with translucent
608 * apps.
609 *
610 * @param transit The current transition type.
611 * @return The current transition type or
612 * {@link WindowManager#TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE}/
613 * {@link WindowManager#TRANSIT_TRANSLUCENT_ACTIVITY_OPEN} if appropriate for the
614 * situation.
615 */
616 @VisibleForTesting
617 int maybeUpdateTransitToTranslucentAnim(int transit) {
Evan Roskyec9488c2019-03-01 19:32:12 -0800618 if (AppTransition.isChangeTransit(transit)) {
619 // There's no special animation to handle change animations with translucent apps
620 return transit;
621 }
lumark588a3e82018-07-20 18:53:54 +0800622 final boolean taskOrActivity = AppTransition.isTaskTransit(transit)
623 || AppTransition.isActivityTransit(transit);
624 boolean allOpeningVisible = true;
625 boolean allTranslucentOpeningApps = !mDisplayContent.mOpeningApps.isEmpty();
626 for (int i = mDisplayContent.mOpeningApps.size() - 1; i >= 0; i--) {
627 final AppWindowToken token = mDisplayContent.mOpeningApps.valueAt(i);
628 if (!token.isVisible()) {
629 allOpeningVisible = false;
630 if (token.fillsParent()) {
631 allTranslucentOpeningApps = false;
632 }
633 }
634 }
635 boolean allTranslucentClosingApps = !mDisplayContent.mClosingApps.isEmpty();
636 for (int i = mDisplayContent.mClosingApps.size() - 1; i >= 0; i--) {
637 if (mDisplayContent.mClosingApps.valueAt(i).fillsParent()) {
638 allTranslucentClosingApps = false;
639 break;
640 }
641 }
642
643 if (taskOrActivity && allTranslucentClosingApps && allOpeningVisible) {
644 return TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE;
645 }
646 if (taskOrActivity && allTranslucentOpeningApps && mDisplayContent.mClosingApps.isEmpty()) {
647 return TRANSIT_TRANSLUCENT_ACTIVITY_OPEN;
648 }
649 return transit;
650 }
651
Evan Rosky7735d352019-03-18 17:27:27 -0700652 /**
653 * Identifies whether the current transition occurs within a single task or not. This is used
654 * to determine whether animations should be clipped to the task bounds instead of stack bounds.
655 */
656 @VisibleForTesting
657 boolean isTransitWithinTask(int transit, Task task) {
658 if (task == null
659 || !mDisplayContent.mChangingApps.isEmpty()) {
660 // if there is no task, then we can't constrain to the task.
661 // if anything is changing, it can animate outside its task.
662 return false;
663 }
664 if (!(transit == TRANSIT_ACTIVITY_OPEN
665 || transit == TRANSIT_ACTIVITY_CLOSE
666 || transit == TRANSIT_ACTIVITY_RELAUNCH)) {
667 // only activity-level transitions will be within-task.
668 return false;
669 }
670 // check that all components are in the task.
671 for (AppWindowToken activity : mDisplayContent.mOpeningApps) {
672 Task activityTask = activity.getTask();
673 if (activityTask != task) {
674 return false;
675 }
676 }
677 for (AppWindowToken activity : mDisplayContent.mClosingApps) {
678 if (activity.getTask() != task) {
679 return false;
680 }
681 }
682 return true;
683 }
684
lumark588a3e82018-07-20 18:53:54 +0800685 private boolean canBeWallpaperTarget(ArraySet<AppWindowToken> apps) {
686 for (int i = apps.size() - 1; i >= 0; i--) {
687 if (apps.valueAt(i).windowsCanBeWallpaperTarget()) {
688 return true;
689 }
690 }
691 return false;
692 }
693
694 /**
695 * Finds the top app in a list of apps, using its {@link AppWindowToken#getPrefixOrderIndex} to
696 * compare z-order.
697 *
698 * @param apps The list of apps to search.
699 * @param ignoreHidden If set to true, ignores apps that are {@link AppWindowToken#isHidden}.
700 * @return The top {@link AppWindowToken}.
701 */
702 private AppWindowToken getTopApp(ArraySet<AppWindowToken> apps, boolean ignoreHidden) {
703 int topPrefixOrderIndex = Integer.MIN_VALUE;
704 AppWindowToken topApp = null;
705 for (int i = apps.size() - 1; i >= 0; i--) {
706 final AppWindowToken app = apps.valueAt(i);
707 if (ignoreHidden && app.isHidden()) {
708 continue;
709 }
710 final int prefixOrderIndex = app.getPrefixOrderIndex();
711 if (prefixOrderIndex > topPrefixOrderIndex) {
712 topPrefixOrderIndex = prefixOrderIndex;
713 topApp = app;
714 }
715 }
716 return topApp;
717 }
718
719 private void processApplicationsAnimatingInPlace(int transit) {
720 if (transit == TRANSIT_TASK_IN_PLACE) {
721 // Find the focused window
722 final WindowState win = mDisplayContent.findFocusedWindow();
723 if (win != null) {
724 final AppWindowToken wtoken = win.mAppToken;
725 if (DEBUG_APP_TRANSITIONS)
726 Slog.v(TAG, "Now animating app in place " + wtoken);
727 wtoken.cancelAnimation();
728 wtoken.applyAnimationLocked(null, transit, false, false);
729 wtoken.updateReportedVisibilityLocked();
730 wtoken.showAllWindowsLocked();
731 }
732 }
733 }
734}