blob: 3bda0c25a6b058efc958c1d81e74fc32a33d2de5 [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;
lumark588a3e82018-07-20 18:53:54 +080034import static android.view.WindowManager.TRANSIT_TASK_OPEN;
35import static android.view.WindowManager.TRANSIT_TASK_TO_BACK;
36import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
37import static android.view.WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE;
38import static android.view.WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_OPEN;
39import static android.view.WindowManager.TRANSIT_WALLPAPER_CLOSE;
40import static android.view.WindowManager.TRANSIT_WALLPAPER_INTRA_CLOSE;
41import static android.view.WindowManager.TRANSIT_WALLPAPER_INTRA_OPEN;
42import static android.view.WindowManager.TRANSIT_WALLPAPER_OPEN;
43
44import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
45import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
46import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_SNAPSHOT;
47import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_SPLASH_SCREEN;
48import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_WINDOWS_DRAWN;
49import static com.android.server.wm.AppTransition.isKeyguardGoingAwayTransit;
Adrian Roosb125e0b2019-10-02 14:55:14 +020050import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
lumark588a3e82018-07-20 18:53:54 +080051import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
52import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
53import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
lumark588a3e82018-07-20 18:53:54 +080054
Yunfan Chencafc7062019-01-22 17:21:32 +090055import android.os.SystemClock;
lumark588a3e82018-07-20 18:53:54 +080056import android.os.Trace;
57import android.util.ArraySet;
58import android.util.Slog;
59import android.util.SparseIntArray;
60import android.view.Display;
61import android.view.RemoteAnimationAdapter;
62import android.view.RemoteAnimationDefinition;
63import android.view.WindowManager;
64import android.view.WindowManager.LayoutParams;
65import android.view.animation.Animation;
66
67import com.android.internal.annotations.VisibleForTesting;
Adrian Roosb125e0b2019-10-02 14:55:14 +020068import com.android.server.protolog.common.ProtoLog;
lumark588a3e82018-07-20 18:53:54 +080069
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
Adrian Roosb125e0b2019-10-02 14:55:14 +0200107 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "**** 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();
Garfield Tane8d84ab2019-10-11 09:49:40 -0700159 final ActivityRecord animLpActivity = allowAnimations
lumark588a3e82018-07-20 18:53:54 +0800160 ? findAnimLayoutParamsToken(transit, activityTypes)
161 : null;
Garfield Tane8d84ab2019-10-11 09:49:40 -0700162 final ActivityRecord topOpeningApp = allowAnimations
lumark588a3e82018-07-20 18:53:54 +0800163 ? getTopApp(mDisplayContent.mOpeningApps, false /* ignoreHidden */)
164 : null;
Garfield Tane8d84ab2019-10-11 09:49:40 -0700165 final ActivityRecord topClosingApp = allowAnimations
lumark588a3e82018-07-20 18:53:54 +0800166 ? getTopApp(mDisplayContent.mClosingApps, false /* ignoreHidden */)
167 : null;
Garfield Tane8d84ab2019-10-11 09:49:40 -0700168 final ActivityRecord topChangingApp = allowAnimations
Evan Rosky2289ba12018-11-19 18:28:18 -0800169 ? getTopApp(mDisplayContent.mChangingApps, false /* ignoreHidden */)
170 : null;
Garfield Tane8d84ab2019-10-11 09:49:40 -0700171 final WindowManager.LayoutParams animLp = getAnimLp(animLpActivity);
172 overrideWithRemoteAnimationIfSet(animLpActivity, transit, activityTypes);
lumark588a3e82018-07-20 18:53:54 +0800173
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 {
lumark588a3e82018-07-20 18:53:54 +0800181 handleClosingApps(transit, animLp, voiceInteraction);
182 handleOpeningApps(transit, animLp, voiceInteraction);
Evan Rosky2289ba12018-11-19 18:28:18 -0800183 handleChangingApps(transit, animLp, voiceInteraction);
lumark588a3e82018-07-20 18:53:54 +0800184
Tiger Huang7c610aa2018-10-27 00:01:01 +0800185 appTransition.setLastAppTransition(transit, topOpeningApp,
Evan Rosky2289ba12018-11-19 18:28:18 -0800186 topClosingApp, topChangingApp);
lumark588a3e82018-07-20 18:53:54 +0800187
Tiger Huang7c610aa2018-10-27 00:01:01 +0800188 final int flags = appTransition.getTransitFlags();
189 layoutRedo = appTransition.goodToGo(transit, topOpeningApp,
Evan Rosky2289ba12018-11-19 18:28:18 -0800190 mDisplayContent.mOpeningApps);
lumark588a3e82018-07-20 18:53:54 +0800191 handleNonAppWindowsInTransition(transit, flags);
Tiger Huang7c610aa2018-10-27 00:01:01 +0800192 appTransition.postAnimationCallback();
193 appTransition.clear();
lumark588a3e82018-07-20 18:53:54 +0800194 } finally {
195 mService.mSurfaceAnimationRunner.continueStartingAnimations();
196 }
197
198 mService.mTaskSnapshotController.onTransitionStarting(mDisplayContent);
199
200 mDisplayContent.mOpeningApps.clear();
201 mDisplayContent.mClosingApps.clear();
Evan Rosky2289ba12018-11-19 18:28:18 -0800202 mDisplayContent.mChangingApps.clear();
lumark588a3e82018-07-20 18:53:54 +0800203 mDisplayContent.mUnknownAppVisibilityController.clear();
204
205 // This has changed the visibility of windows, so perform
206 // a new layout to get them all up-to-date.
207 mDisplayContent.setLayoutNeeded();
208
209 mDisplayContent.computeImeTarget(true /* updateImeTarget */);
210
Yunfan Chencafc7062019-01-22 17:21:32 +0900211 mService.mAtmInternal.notifyAppTransitionStarting(mTempTransitionReasons.clone(),
Yan Wangd47f90b2019-10-03 19:17:15 -0700212 SystemClock.elapsedRealtimeNanos());
lumark588a3e82018-07-20 18:53:54 +0800213
Issei Suzukicac2a502019-04-16 16:52:50 +0200214 if (transit == TRANSIT_SHOW_SINGLE_TASK_DISPLAY) {
215 mService.mAnimator.addAfterPrepareSurfacesRunnable(() -> {
216 mService.mAtmInternal.notifySingleTaskDisplayDrawn(mDisplayContent.getDisplayId());
217 });
218 }
219
lumark588a3e82018-07-20 18:53:54 +0800220 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
221
222 mDisplayContent.pendingLayoutChanges |=
223 layoutRedo | FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG;
224 }
225
Garfield Tane8d84ab2019-10-11 09:49:40 -0700226 private static WindowManager.LayoutParams getAnimLp(ActivityRecord activity) {
227 final WindowState mainWindow = activity != null ? activity.findMainWindow() : null;
lumark588a3e82018-07-20 18:53:54 +0800228 return mainWindow != null ? mainWindow.mAttrs : null;
229 }
230
Garfield Tane8d84ab2019-10-11 09:49:40 -0700231 RemoteAnimationAdapter getRemoteAnimationOverride(ActivityRecord animLpActivity, int transit,
Evan Rosky966759f2019-01-15 10:33:58 -0800232 ArraySet<Integer> activityTypes) {
Garfield Tane8d84ab2019-10-11 09:49:40 -0700233 final RemoteAnimationDefinition definition = animLpActivity.getRemoteAnimationDefinition();
Evan Rosky966759f2019-01-15 10:33:58 -0800234 if (definition != null) {
235 final RemoteAnimationAdapter adapter = definition.getAdapter(transit, activityTypes);
236 if (adapter != null) {
237 return adapter;
238 }
239 }
240 if (mRemoteAnimationDefinition == null) {
241 return null;
242 }
243 return mRemoteAnimationDefinition.getAdapter(transit, activityTypes);
244 }
245
lumark588a3e82018-07-20 18:53:54 +0800246 /**
247 * Overrides the pending transition with the remote animation defined for the transition in the
248 * set of defined remote animations in the app window token.
249 */
Garfield Tane8d84ab2019-10-11 09:49:40 -0700250 private void overrideWithRemoteAnimationIfSet(ActivityRecord animLpActivity, int transit,
lumark588a3e82018-07-20 18:53:54 +0800251 ArraySet<Integer> activityTypes) {
252 if (transit == TRANSIT_CRASHING_ACTIVITY_CLOSE) {
253 // The crash transition has higher priority than any involved remote animations.
254 return;
255 }
Garfield Tane8d84ab2019-10-11 09:49:40 -0700256 if (animLpActivity == null) {
lumark588a3e82018-07-20 18:53:54 +0800257 return;
258 }
Evan Rosky966759f2019-01-15 10:33:58 -0800259 final RemoteAnimationAdapter adapter =
Garfield Tane8d84ab2019-10-11 09:49:40 -0700260 getRemoteAnimationOverride(animLpActivity, transit, activityTypes);
lumark588a3e82018-07-20 18:53:54 +0800261 if (adapter != null) {
Garfield Tane8d84ab2019-10-11 09:49:40 -0700262 animLpActivity.getDisplayContent().mAppTransition.overridePendingAppTransitionRemote(
lumark588a3e82018-07-20 18:53:54 +0800263 adapter);
264 }
265 }
266
267 /**
268 * @return The window token that determines the animation theme.
269 */
Garfield Tane8d84ab2019-10-11 09:49:40 -0700270 private ActivityRecord findAnimLayoutParamsToken(@WindowManager.TransitionType int transit,
lumark588a3e82018-07-20 18:53:54 +0800271 ArraySet<Integer> activityTypes) {
Garfield Tane8d84ab2019-10-11 09:49:40 -0700272 ActivityRecord result;
273 final ArraySet<ActivityRecord> closingApps = mDisplayContent.mClosingApps;
274 final ArraySet<ActivityRecord> openingApps = mDisplayContent.mOpeningApps;
275 final ArraySet<ActivityRecord> changingApps = mDisplayContent.mChangingApps;
lumark588a3e82018-07-20 18:53:54 +0800276
277 // Remote animations always win, but fullscreen tokens override non-fullscreen tokens.
Evan Rosky2289ba12018-11-19 18:28:18 -0800278 result = lookForHighestTokenWithFilter(closingApps, openingApps, changingApps,
lumark588a3e82018-07-20 18:53:54 +0800279 w -> w.getRemoteAnimationDefinition() != null
280 && w.getRemoteAnimationDefinition().hasTransition(transit, activityTypes));
281 if (result != null) {
282 return result;
283 }
Evan Rosky2289ba12018-11-19 18:28:18 -0800284 result = lookForHighestTokenWithFilter(closingApps, openingApps, changingApps,
lumark588a3e82018-07-20 18:53:54 +0800285 w -> w.fillsParent() && w.findMainWindow() != null);
286 if (result != null) {
287 return result;
288 }
Evan Rosky2289ba12018-11-19 18:28:18 -0800289 return lookForHighestTokenWithFilter(closingApps, openingApps, changingApps,
lumark588a3e82018-07-20 18:53:54 +0800290 w -> w.findMainWindow() != null);
291 }
292
293 /**
Tiger Huang7c610aa2018-10-27 00:01:01 +0800294 * @return The set of {@link android.app.WindowConfiguration.ActivityType}s contained in the set
Evan Rosky2289ba12018-11-19 18:28:18 -0800295 * of apps in {@code array1}, {@code array2}, and {@code array3}.
lumark588a3e82018-07-20 18:53:54 +0800296 */
Garfield Tane8d84ab2019-10-11 09:49:40 -0700297 private static ArraySet<Integer> collectActivityTypes(ArraySet<ActivityRecord> array1,
298 ArraySet<ActivityRecord> array2, ArraySet<ActivityRecord> array3) {
lumark588a3e82018-07-20 18:53:54 +0800299 final ArraySet<Integer> result = new ArraySet<>();
300 for (int i = array1.size() - 1; i >= 0; i--) {
301 result.add(array1.valueAt(i).getActivityType());
302 }
303 for (int i = array2.size() - 1; i >= 0; i--) {
304 result.add(array2.valueAt(i).getActivityType());
305 }
Evan Rosky2289ba12018-11-19 18:28:18 -0800306 for (int i = array3.size() - 1; i >= 0; i--) {
307 result.add(array3.valueAt(i).getActivityType());
308 }
lumark588a3e82018-07-20 18:53:54 +0800309 return result;
310 }
311
Garfield Tane8d84ab2019-10-11 09:49:40 -0700312 private static ActivityRecord lookForHighestTokenWithFilter(ArraySet<ActivityRecord> array1,
313 ArraySet<ActivityRecord> array2, ArraySet<ActivityRecord> array3,
314 Predicate<ActivityRecord> filter) {
Evan Rosky2289ba12018-11-19 18:28:18 -0800315 final int array2base = array1.size();
316 final int array3base = array2.size() + array2base;
317 final int count = array3base + array3.size();
lumark588a3e82018-07-20 18:53:54 +0800318 int bestPrefixOrderIndex = Integer.MIN_VALUE;
Garfield Tane8d84ab2019-10-11 09:49:40 -0700319 ActivityRecord bestToken = null;
lumark588a3e82018-07-20 18:53:54 +0800320 for (int i = 0; i < count; i++) {
Garfield Tane8d84ab2019-10-11 09:49:40 -0700321 final ActivityRecord wtoken = i < array2base
lumark588a3e82018-07-20 18:53:54 +0800322 ? array1.valueAt(i)
Evan Rosky2289ba12018-11-19 18:28:18 -0800323 : (i < array3base
324 ? array2.valueAt(i - array2base)
325 : array3.valueAt(i - array3base));
lumark588a3e82018-07-20 18:53:54 +0800326 final int prefixOrderIndex = wtoken.getPrefixOrderIndex();
327 if (filter.test(wtoken) && prefixOrderIndex > bestPrefixOrderIndex) {
328 bestPrefixOrderIndex = prefixOrderIndex;
329 bestToken = wtoken;
330 }
331 }
332 return bestToken;
333 }
334
Garfield Tane8d84ab2019-10-11 09:49:40 -0700335 private boolean containsVoiceInteraction(ArraySet<ActivityRecord> apps) {
lumark588a3e82018-07-20 18:53:54 +0800336 for (int i = apps.size() - 1; i >= 0; i--) {
337 if (apps.valueAt(i).mVoiceInteraction) {
338 return true;
339 }
340 }
341 return false;
342 }
343
344 private void handleOpeningApps(int transit, LayoutParams animLp, boolean voiceInteraction) {
Garfield Tane8d84ab2019-10-11 09:49:40 -0700345 final ArraySet<ActivityRecord> openingApps = mDisplayContent.mOpeningApps;
lumark588a3e82018-07-20 18:53:54 +0800346 final int appsCount = openingApps.size();
347 for (int i = 0; i < appsCount; i++) {
Garfield Tane8d84ab2019-10-11 09:49:40 -0700348 ActivityRecord wtoken = openingApps.valueAt(i);
Adrian Roosb125e0b2019-10-02 14:55:14 +0200349 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now opening app %s", wtoken);
lumark588a3e82018-07-20 18:53:54 +0800350
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800351 if (!wtoken.commitVisibility(animLp, true, transit, false, voiceInteraction)) {
lumark588a3e82018-07-20 18:53:54 +0800352 // This token isn't going to be animating. Add it to the list of tokens to
353 // be notified of app transition complete since the notification will not be
354 // sent be the app window animator.
355 mDisplayContent.mNoAnimationNotifyOnTransitionFinished.add(wtoken.token);
356 }
357 wtoken.updateReportedVisibilityLocked();
358 wtoken.waitingToShow = false;
359 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
360 ">>> OPEN TRANSACTION handleAppTransitionReady()");
361 mService.openSurfaceTransaction();
362 try {
363 wtoken.showAllWindowsLocked();
364 } finally {
365 mService.closeSurfaceTransaction("handleAppTransitionReady");
366 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
367 "<<< CLOSE TRANSACTION handleAppTransitionReady()");
368 }
369
370 if (mDisplayContent.mAppTransition.isNextAppTransitionThumbnailUp()) {
371 wtoken.attachThumbnailAnimation();
372 } else if (mDisplayContent.mAppTransition.isNextAppTransitionOpenCrossProfileApps()) {
373 wtoken.attachCrossProfileAppsThumbnailAnimation();
374 }
375 }
376 }
377
378 private void handleClosingApps(int transit, LayoutParams animLp, boolean voiceInteraction) {
Garfield Tane8d84ab2019-10-11 09:49:40 -0700379 final ArraySet<ActivityRecord> closingApps = mDisplayContent.mClosingApps;
lumark588a3e82018-07-20 18:53:54 +0800380 final int appsCount = closingApps.size();
381 for (int i = 0; i < appsCount; i++) {
Garfield Tane8d84ab2019-10-11 09:49:40 -0700382 ActivityRecord wtoken = closingApps.valueAt(i);
lumark588a3e82018-07-20 18:53:54 +0800383
Adrian Roosb125e0b2019-10-02 14:55:14 +0200384 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now closing app %s", wtoken);
lumark588a3e82018-07-20 18:53:54 +0800385 // TODO: Do we need to add to mNoAnimationNotifyOnTransitionFinished like above if not
386 // animating?
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800387 wtoken.commitVisibility(animLp, false, transit, false, voiceInteraction);
lumark588a3e82018-07-20 18:53:54 +0800388 wtoken.updateReportedVisibilityLocked();
389 // Force the allDrawn flag, because we want to start
390 // this guy's animations regardless of whether it's
391 // gotten drawn.
392 wtoken.allDrawn = true;
393 wtoken.deferClearAllDrawn = false;
394 // Ensure that apps that are mid-starting are also scheduled to have their
395 // starting windows removed after the animation is complete
Yunfan Chen1ee84ea2018-11-13 16:03:37 -0800396 if (wtoken.startingWindow != null && !wtoken.startingWindow.mAnimatingExit) {
397 wtoken.removeStartingWindow();
lumark588a3e82018-07-20 18:53:54 +0800398 }
399
400 if (mDisplayContent.mAppTransition.isNextAppTransitionThumbnailDown()) {
401 wtoken.attachThumbnailAnimation();
402 }
403 }
404 }
405
Evan Rosky2289ba12018-11-19 18:28:18 -0800406 private void handleChangingApps(int transit, LayoutParams animLp, boolean voiceInteraction) {
Garfield Tane8d84ab2019-10-11 09:49:40 -0700407 final ArraySet<ActivityRecord> apps = mDisplayContent.mChangingApps;
Evan Rosky2289ba12018-11-19 18:28:18 -0800408 final int appsCount = apps.size();
409 for (int i = 0; i < appsCount; i++) {
Garfield Tane8d84ab2019-10-11 09:49:40 -0700410 ActivityRecord activity = apps.valueAt(i);
411 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Now changing app %s", activity);
412 activity.cancelAnimationOnly();
413 activity.applyAnimationLocked(null, transit, true, false);
414 activity.updateReportedVisibilityLocked();
Evan Rosky2289ba12018-11-19 18:28:18 -0800415 mService.openSurfaceTransaction();
416 try {
Garfield Tane8d84ab2019-10-11 09:49:40 -0700417 activity.showAllWindowsLocked();
Evan Rosky2289ba12018-11-19 18:28:18 -0800418 } finally {
419 mService.closeSurfaceTransaction("handleChangingApps");
420 }
421 }
422 }
423
lumark588a3e82018-07-20 18:53:54 +0800424 private void handleNonAppWindowsInTransition(int transit, int flags) {
425 if (transit == TRANSIT_KEYGUARD_GOING_AWAY) {
426 if ((flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0
Issei Suzuki5609ccb2019-06-13 15:04:08 +0200427 && (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION) == 0
428 && (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION) == 0) {
lumark588a3e82018-07-20 18:53:54 +0800429 Animation anim = mService.mPolicy.createKeyguardWallpaperExit(
430 (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0);
431 if (anim != null) {
432 mDisplayContent.mWallpaperController.startWallpaperAnimation(anim);
433 }
434 }
435 }
436 if (transit == TRANSIT_KEYGUARD_GOING_AWAY
437 || transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER) {
438 mDisplayContent.startKeyguardExitOnNonAppWindows(
439 transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER,
Issei Suzuki5609ccb2019-06-13 15:04:08 +0200440 (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0,
441 (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION) != 0);
lumark588a3e82018-07-20 18:53:54 +0800442 }
443 }
444
Garfield Tane8d84ab2019-10-11 09:49:40 -0700445 private boolean transitionGoodToGo(ArraySet<ActivityRecord> apps, SparseIntArray outReasons) {
Adrian Roosb125e0b2019-10-02 14:55:14 +0200446 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
447 "Checking %d opening apps (frozen=%b timeout=%b)...", apps.size(),
448 mService.mDisplayFrozen, mDisplayContent.mAppTransition.isTimeout());
Vadim Caenb3715832019-08-13 17:06:38 +0200449
450 final ScreenRotationAnimation screenRotationAnimation = mService.mRoot.getDisplayContent(
451 Display.DEFAULT_DISPLAY).getRotationAnimation();
lumark588a3e82018-07-20 18:53:54 +0800452
lumark588a3e82018-07-20 18:53:54 +0800453 if (!mDisplayContent.mAppTransition.isTimeout()) {
454 // Imagine the case where we are changing orientation due to an app transition, but a
455 // previous orientation change is still in progress. We won't process the orientation
456 // change for our transition because we need to wait for the rotation animation to
457 // finish.
458 // If we start the app transition at this point, we will interrupt it halfway with a
459 // new rotation animation after the old one finally finishes. It's better to defer the
460 // app transition.
461 if (screenRotationAnimation != null && screenRotationAnimation.isAnimating() &&
Riddle Hsuccf09402019-08-13 00:33:06 +0800462 mDisplayContent.getDisplayRotation().needsUpdate()) {
Adrian Roosb125e0b2019-10-02 14:55:14 +0200463 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
464 "Delaying app transition for screen rotation animation to finish");
lumark588a3e82018-07-20 18:53:54 +0800465 return false;
466 }
Evan Rosky2289ba12018-11-19 18:28:18 -0800467 for (int i = 0; i < apps.size(); i++) {
Garfield Tane8d84ab2019-10-11 09:49:40 -0700468 ActivityRecord activity = apps.valueAt(i);
Adrian Roosb125e0b2019-10-02 14:55:14 +0200469 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
470 "Check opening app=%s: allDrawn=%b startingDisplayed=%b "
471 + "startingMoved=%b isRelaunching()=%b startingWindow=%s",
Garfield Tane8d84ab2019-10-11 09:49:40 -0700472 activity, activity.allDrawn, activity.startingDisplayed,
473 activity.startingMoved, activity.isRelaunching(),
474 activity.startingWindow);
lumark588a3e82018-07-20 18:53:54 +0800475
476
Garfield Tane8d84ab2019-10-11 09:49:40 -0700477 final boolean allDrawn = activity.allDrawn && !activity.isRelaunching();
478 if (!allDrawn && !activity.startingDisplayed && !activity.startingMoved) {
lumark588a3e82018-07-20 18:53:54 +0800479 return false;
480 }
Garfield Tane8d84ab2019-10-11 09:49:40 -0700481 final int windowingMode = activity.getWindowingMode();
lumark588a3e82018-07-20 18:53:54 +0800482 if (allDrawn) {
483 outReasons.put(windowingMode, APP_TRANSITION_WINDOWS_DRAWN);
484 } else {
485 outReasons.put(windowingMode,
Garfield Tane8d84ab2019-10-11 09:49:40 -0700486 activity.mStartingData instanceof SplashScreenStartingData
lumark588a3e82018-07-20 18:53:54 +0800487 ? APP_TRANSITION_SPLASH_SCREEN
488 : APP_TRANSITION_SNAPSHOT);
489 }
490 }
491
492 // We also need to wait for the specs to be fetched, if needed.
493 if (mDisplayContent.mAppTransition.isFetchingAppTransitionsSpecs()) {
Adrian Roosb125e0b2019-10-02 14:55:14 +0200494 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "isFetchingAppTransitionSpecs=true");
lumark588a3e82018-07-20 18:53:54 +0800495 return false;
496 }
497
498 if (!mDisplayContent.mUnknownAppVisibilityController.allResolved()) {
Adrian Roosb125e0b2019-10-02 14:55:14 +0200499 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "unknownApps is not empty: %s",
500 mDisplayContent.mUnknownAppVisibilityController.getDebugMessage());
lumark588a3e82018-07-20 18:53:54 +0800501 return false;
502 }
503
504 // If the wallpaper is visible, we need to check it's ready too.
505 boolean wallpaperReady = !mWallpaperControllerLocked.isWallpaperVisible() ||
506 mWallpaperControllerLocked.wallpaperTransitionReady();
507 if (wallpaperReady) {
508 return true;
509 }
510 return false;
511 }
512 return true;
513 }
514
515 private int maybeUpdateTransitToWallpaper(int transit, boolean openingAppHasWallpaper,
516 boolean closingAppHasWallpaper) {
517 // Given no app transition pass it through instead of a wallpaper transition.
518 // Never convert the crashing transition.
519 // Never update the transition for the wallpaper if we are just docking from recents
Evan Roskyec9488c2019-03-01 19:32:12 -0800520 // Never convert a change transition since the top activity isn't changing and will likely
521 // still be above an opening wallpaper.
lumark588a3e82018-07-20 18:53:54 +0800522 if (transit == TRANSIT_NONE || transit == TRANSIT_CRASHING_ACTIVITY_CLOSE
Evan Roskyec9488c2019-03-01 19:32:12 -0800523 || transit == TRANSIT_DOCK_TASK_FROM_RECENTS
524 || AppTransition.isChangeTransit(transit)) {
lumark588a3e82018-07-20 18:53:54 +0800525 return transit;
526 }
527
528 final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget();
529 final boolean showWallpaper = wallpaperTarget != null
530 && (wallpaperTarget.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0;
531 // If wallpaper is animating or wallpaperTarget doesn't have SHOW_WALLPAPER flag set,
532 // don't consider upgrading to wallpaper transition.
533 final WindowState oldWallpaper =
534 (mWallpaperControllerLocked.isWallpaperTargetAnimating() || !showWallpaper)
535 ? null
536 : wallpaperTarget;
Garfield Tane8d84ab2019-10-11 09:49:40 -0700537 final ArraySet<ActivityRecord> openingApps = mDisplayContent.mOpeningApps;
538 final ArraySet<ActivityRecord> closingApps = mDisplayContent.mClosingApps;
539 final ActivityRecord topOpeningApp = getTopApp(mDisplayContent.mOpeningApps,
lumark588a3e82018-07-20 18:53:54 +0800540 false /* ignoreHidden */);
Garfield Tane8d84ab2019-10-11 09:49:40 -0700541 final ActivityRecord topClosingApp = getTopApp(mDisplayContent.mClosingApps,
lumark588a3e82018-07-20 18:53:54 +0800542 true /* ignoreHidden */);
543
544 boolean openingCanBeWallpaperTarget = canBeWallpaperTarget(openingApps);
Adrian Roosb125e0b2019-10-02 14:55:14 +0200545 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
546 "New wallpaper target=%s, oldWallpaper=%s, openingApps=%s, closingApps=%s",
547 wallpaperTarget, oldWallpaper, openingApps, closingApps);
lumark588a3e82018-07-20 18:53:54 +0800548
549 if (openingCanBeWallpaperTarget && transit == TRANSIT_KEYGUARD_GOING_AWAY) {
550 transit = TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
Adrian Roosb125e0b2019-10-02 14:55:14 +0200551 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
552 "New transit: %s", AppTransition.appTransitionToString(transit));
lumark588a3e82018-07-20 18:53:54 +0800553 }
554 // We never want to change from a Keyguard transit to a non-Keyguard transit, as our logic
555 // relies on the fact that we always execute a Keyguard transition after preparing one.
556 else if (!isKeyguardGoingAwayTransit(transit)) {
557 if (closingAppHasWallpaper && openingAppHasWallpaper) {
Adrian Roosb125e0b2019-10-02 14:55:14 +0200558 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Wallpaper animation!");
lumark588a3e82018-07-20 18:53:54 +0800559 switch (transit) {
560 case TRANSIT_ACTIVITY_OPEN:
561 case TRANSIT_TASK_OPEN:
562 case TRANSIT_TASK_TO_FRONT:
563 transit = TRANSIT_WALLPAPER_INTRA_OPEN;
564 break;
565 case TRANSIT_ACTIVITY_CLOSE:
566 case TRANSIT_TASK_CLOSE:
567 case TRANSIT_TASK_TO_BACK:
568 transit = TRANSIT_WALLPAPER_INTRA_CLOSE;
569 break;
570 }
Adrian Roosb125e0b2019-10-02 14:55:14 +0200571 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
572 "New transit: %s", AppTransition.appTransitionToString(transit));
lumark588a3e82018-07-20 18:53:54 +0800573 } else if (oldWallpaper != null && !mDisplayContent.mOpeningApps.isEmpty()
Garfield Tane8d84ab2019-10-11 09:49:40 -0700574 && !openingApps.contains(oldWallpaper.mActivityRecord)
575 && closingApps.contains(oldWallpaper.mActivityRecord)
576 && topClosingApp == oldWallpaper.mActivityRecord) {
lumark588a3e82018-07-20 18:53:54 +0800577 // We are transitioning from an activity with a wallpaper to one without.
578 transit = TRANSIT_WALLPAPER_CLOSE;
Adrian Roosb125e0b2019-10-02 14:55:14 +0200579 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
580 "New transit away from wallpaper: %s",
581 AppTransition.appTransitionToString(transit));
lumark588a3e82018-07-20 18:53:54 +0800582 } else if (wallpaperTarget != null && wallpaperTarget.isVisibleLw()
Garfield Tane8d84ab2019-10-11 09:49:40 -0700583 && openingApps.contains(wallpaperTarget.mActivityRecord)
584 && topOpeningApp == wallpaperTarget.mActivityRecord
lumark588a3e82018-07-20 18:53:54 +0800585 && transit != TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE) {
586 // We are transitioning from an activity without
587 // a wallpaper to now showing the wallpaper
588 transit = TRANSIT_WALLPAPER_OPEN;
Adrian Roosb125e0b2019-10-02 14:55:14 +0200589 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "New transit into wallpaper: %s",
590 AppTransition.appTransitionToString(transit));
lumark588a3e82018-07-20 18:53:54 +0800591 }
592 }
593 return transit;
594 }
595
596 /**
597 * There are cases where we open/close a new task/activity, but in reality only a translucent
598 * activity on top of existing activities is opening/closing. For that one, we have a different
599 * animation because non of the task/activity animations actually work well with translucent
600 * apps.
601 *
602 * @param transit The current transition type.
603 * @return The current transition type or
604 * {@link WindowManager#TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE}/
605 * {@link WindowManager#TRANSIT_TRANSLUCENT_ACTIVITY_OPEN} if appropriate for the
606 * situation.
607 */
608 @VisibleForTesting
609 int maybeUpdateTransitToTranslucentAnim(int transit) {
Evan Roskyec9488c2019-03-01 19:32:12 -0800610 if (AppTransition.isChangeTransit(transit)) {
611 // There's no special animation to handle change animations with translucent apps
612 return transit;
613 }
lumark588a3e82018-07-20 18:53:54 +0800614 final boolean taskOrActivity = AppTransition.isTaskTransit(transit)
615 || AppTransition.isActivityTransit(transit);
616 boolean allOpeningVisible = true;
617 boolean allTranslucentOpeningApps = !mDisplayContent.mOpeningApps.isEmpty();
618 for (int i = mDisplayContent.mOpeningApps.size() - 1; i >= 0; i--) {
Garfield Tane8d84ab2019-10-11 09:49:40 -0700619 final ActivityRecord activity = mDisplayContent.mOpeningApps.valueAt(i);
620 if (!activity.isVisible()) {
lumark588a3e82018-07-20 18:53:54 +0800621 allOpeningVisible = false;
Garfield Tane8d84ab2019-10-11 09:49:40 -0700622 if (activity.fillsParent()) {
lumark588a3e82018-07-20 18:53:54 +0800623 allTranslucentOpeningApps = false;
624 }
625 }
626 }
627 boolean allTranslucentClosingApps = !mDisplayContent.mClosingApps.isEmpty();
628 for (int i = mDisplayContent.mClosingApps.size() - 1; i >= 0; i--) {
629 if (mDisplayContent.mClosingApps.valueAt(i).fillsParent()) {
630 allTranslucentClosingApps = false;
631 break;
632 }
633 }
634
635 if (taskOrActivity && allTranslucentClosingApps && allOpeningVisible) {
636 return TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE;
637 }
638 if (taskOrActivity && allTranslucentOpeningApps && mDisplayContent.mClosingApps.isEmpty()) {
639 return TRANSIT_TRANSLUCENT_ACTIVITY_OPEN;
640 }
641 return transit;
642 }
643
Evan Rosky7735d352019-03-18 17:27:27 -0700644 /**
645 * Identifies whether the current transition occurs within a single task or not. This is used
646 * to determine whether animations should be clipped to the task bounds instead of stack bounds.
647 */
648 @VisibleForTesting
649 boolean isTransitWithinTask(int transit, Task task) {
650 if (task == null
651 || !mDisplayContent.mChangingApps.isEmpty()) {
652 // if there is no task, then we can't constrain to the task.
653 // if anything is changing, it can animate outside its task.
654 return false;
655 }
656 if (!(transit == TRANSIT_ACTIVITY_OPEN
657 || transit == TRANSIT_ACTIVITY_CLOSE
658 || transit == TRANSIT_ACTIVITY_RELAUNCH)) {
659 // only activity-level transitions will be within-task.
660 return false;
661 }
662 // check that all components are in the task.
Garfield Tane8d84ab2019-10-11 09:49:40 -0700663 for (ActivityRecord activity : mDisplayContent.mOpeningApps) {
Evan Rosky7735d352019-03-18 17:27:27 -0700664 Task activityTask = activity.getTask();
665 if (activityTask != task) {
666 return false;
667 }
668 }
Garfield Tane8d84ab2019-10-11 09:49:40 -0700669 for (ActivityRecord activity : mDisplayContent.mClosingApps) {
Evan Rosky7735d352019-03-18 17:27:27 -0700670 if (activity.getTask() != task) {
671 return false;
672 }
673 }
674 return true;
675 }
676
Garfield Tane8d84ab2019-10-11 09:49:40 -0700677 private boolean canBeWallpaperTarget(ArraySet<ActivityRecord> apps) {
lumark588a3e82018-07-20 18:53:54 +0800678 for (int i = apps.size() - 1; i >= 0; i--) {
679 if (apps.valueAt(i).windowsCanBeWallpaperTarget()) {
680 return true;
681 }
682 }
683 return false;
684 }
685
686 /**
Garfield Tane8d84ab2019-10-11 09:49:40 -0700687 * Finds the top app in a list of apps, using its {@link ActivityRecord#getPrefixOrderIndex} to
lumark588a3e82018-07-20 18:53:54 +0800688 * compare z-order.
689 *
690 * @param apps The list of apps to search.
Garfield Tane8d84ab2019-10-11 09:49:40 -0700691 * @param ignoreHidden If set to true, ignores apps that are {@link ActivityRecord#isHidden}.
692 * @return The top {@link ActivityRecord}.
lumark588a3e82018-07-20 18:53:54 +0800693 */
Garfield Tane8d84ab2019-10-11 09:49:40 -0700694 private ActivityRecord getTopApp(ArraySet<ActivityRecord> apps, boolean ignoreHidden) {
lumark588a3e82018-07-20 18:53:54 +0800695 int topPrefixOrderIndex = Integer.MIN_VALUE;
Garfield Tane8d84ab2019-10-11 09:49:40 -0700696 ActivityRecord topApp = null;
lumark588a3e82018-07-20 18:53:54 +0800697 for (int i = apps.size() - 1; i >= 0; i--) {
Garfield Tane8d84ab2019-10-11 09:49:40 -0700698 final ActivityRecord app = apps.valueAt(i);
lumark588a3e82018-07-20 18:53:54 +0800699 if (ignoreHidden && app.isHidden()) {
700 continue;
701 }
702 final int prefixOrderIndex = app.getPrefixOrderIndex();
703 if (prefixOrderIndex > topPrefixOrderIndex) {
704 topPrefixOrderIndex = prefixOrderIndex;
705 topApp = app;
706 }
707 }
708 return topApp;
709 }
lumark588a3e82018-07-20 18:53:54 +0800710}