1 
2 package com.android.server.wm;
3 
4 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
5 import static android.app.ActivityManagerInternal.APP_TRANSITION_SAVED_SURFACE;
6 import static android.app.ActivityManagerInternal.APP_TRANSITION_SNAPSHOT;
7 import static android.app.ActivityManagerInternal.APP_TRANSITION_SPLASH_SCREEN;
8 import static android.app.ActivityManagerInternal.APP_TRANSITION_WINDOWS_DRAWN;
9 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
10 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
11 import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_CLOSE;
12 import static com.android.server.wm.AppTransition.TRANSIT_ACTIVITY_OPEN;
13 import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
14 import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
15 import static com.android.server.wm.AppTransition.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
16 import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_GOING_AWAY;
17 import static com.android.server.wm.AppTransition.TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
18 import static com.android.server.wm.AppTransition.TRANSIT_NONE;
19 import static com.android.server.wm.AppTransition.TRANSIT_TASK_CLOSE;
20 import static com.android.server.wm.AppTransition.TRANSIT_TASK_IN_PLACE;
21 import static com.android.server.wm.AppTransition.TRANSIT_TASK_OPEN;
22 import static com.android.server.wm.AppTransition.TRANSIT_TASK_TO_BACK;
23 import static com.android.server.wm.AppTransition.TRANSIT_TASK_TO_FRONT;
24 import static com.android.server.wm.AppTransition.TRANSIT_WALLPAPER_CLOSE;
25 import static com.android.server.wm.AppTransition.TRANSIT_WALLPAPER_INTRA_CLOSE;
26 import static com.android.server.wm.AppTransition.TRANSIT_WALLPAPER_INTRA_OPEN;
27 import static com.android.server.wm.AppTransition.TRANSIT_WALLPAPER_OPEN;
28 import static com.android.server.wm.AppTransition.isKeyguardGoingAwayTransit;
29 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
30 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
31 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
32 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
33 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
34 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
35 import static com.android.server.wm.WindowManagerService.H.NOTIFY_APP_TRANSITION_STARTING;
36 import static com.android.server.wm.WindowManagerService.H.REPORT_WINDOWS_CHANGE;
37 import static com.android.server.wm.WindowManagerService.LAYOUT_REPEAT_THRESHOLD;
38 import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION;
39 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SURFACES;
40 
41 import android.content.res.Configuration;
42 import android.graphics.GraphicBuffer;
43 import android.graphics.PixelFormat;
44 import android.graphics.Rect;
45 import android.os.Binder;
46 import android.os.Debug;
47 import android.os.Trace;
48 import android.util.ArraySet;
49 import android.util.Slog;
50 import android.util.SparseIntArray;
51 import android.view.Display;
52 import android.view.DisplayInfo;
53 import android.view.Surface;
54 import android.view.SurfaceControl;
55 import android.view.WindowManager.LayoutParams;
56 import android.view.animation.Animation;
57 
58 import com.android.server.wm.WindowManagerService.H;
59 
60 import java.io.PrintWriter;
61 import java.util.ArrayList;
62 
63 /**
64  * Positions windows and their surfaces.
65  *
66  * It sets positions of windows by calculating their frames and then applies this by positioning
67  * surfaces according to these frames. Z layer is still assigned withing WindowManagerService.
68  */
69 class WindowSurfacePlacer {
70     private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowSurfacePlacer" : TAG_WM;
71     private final WindowManagerService mService;
72     private final WallpaperController mWallpaperControllerLocked;
73 
74     private boolean mInLayout = false;
75 
76     /** Only do a maximum of 6 repeated layouts. After that quit */
77     private int mLayoutRepeatCount;
78 
79     static final int SET_UPDATE_ROTATION                = 1 << 0;
80     static final int SET_WALLPAPER_MAY_CHANGE           = 1 << 1;
81     static final int SET_FORCE_HIDING_CHANGED           = 1 << 2;
82     static final int SET_ORIENTATION_CHANGE_COMPLETE    = 1 << 3;
83     static final int SET_TURN_ON_SCREEN                 = 1 << 4;
84     static final int SET_WALLPAPER_ACTION_PENDING       = 1 << 5;
85 
86     private final Rect mTmpStartRect = new Rect();
87     private final Rect mTmpContentRect = new Rect();
88 
89     private boolean mTraversalScheduled;
90     private int mDeferDepth = 0;
91 
92     private static final class LayerAndToken {
93         public int layer;
94         public AppWindowToken token;
95     }
96     private final LayerAndToken mTmpLayerAndToken = new LayerAndToken();
97 
98     private final ArrayList<SurfaceControl> mPendingDestroyingSurfaces = new ArrayList<>();
99     private final SparseIntArray mTempTransitionReasons = new SparseIntArray();
100 
101     private final Runnable mPerformSurfacePlacement;
102 
WindowSurfacePlacer(WindowManagerService service)103     public WindowSurfacePlacer(WindowManagerService service) {
104         mService = service;
105         mWallpaperControllerLocked = mService.mRoot.mWallpaperController;
106         mPerformSurfacePlacement = () -> {
107             synchronized (mService.mWindowMap) {
108                 performSurfacePlacement();
109             }
110         };
111     }
112 
113     /**
114      * See {@link WindowManagerService#deferSurfaceLayout()}
115      */
deferLayout()116     void deferLayout() {
117         mDeferDepth++;
118     }
119 
120     /**
121      * See {@link WindowManagerService#continueSurfaceLayout()}
122      */
continueLayout()123     void continueLayout() {
124         mDeferDepth--;
125         if (mDeferDepth <= 0) {
126             performSurfacePlacement();
127         }
128     }
129 
performSurfacePlacement()130     final void performSurfacePlacement() {
131         performSurfacePlacement(false /* force */);
132     }
133 
performSurfacePlacement(boolean force)134     final void performSurfacePlacement(boolean force) {
135         if (mDeferDepth > 0 && !force) {
136             return;
137         }
138         int loopCount = 6;
139         do {
140             mTraversalScheduled = false;
141             performSurfacePlacementLoop();
142             mService.mAnimationHandler.removeCallbacks(mPerformSurfacePlacement);
143             loopCount--;
144         } while (mTraversalScheduled && loopCount > 0);
145         mService.mRoot.mWallpaperActionPending = false;
146     }
147 
performSurfacePlacementLoop()148     private void performSurfacePlacementLoop() {
149         if (mInLayout) {
150             if (DEBUG) {
151                 throw new RuntimeException("Recursive call!");
152             }
153             Slog.w(TAG, "performLayoutAndPlaceSurfacesLocked called while in layout. Callers="
154                     + Debug.getCallers(3));
155             return;
156         }
157 
158         if (mService.mWaitingForConfig) {
159             // Our configuration has changed (most likely rotation), but we
160             // don't yet have the complete configuration to report to
161             // applications.  Don't do any window layout until we have it.
162             return;
163         }
164 
165         if (!mService.mDisplayReady) {
166             // Not yet initialized, nothing to do.
167             return;
168         }
169 
170         Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmLayout");
171         mInLayout = true;
172 
173         boolean recoveringMemory = false;
174         if (!mService.mForceRemoves.isEmpty()) {
175             recoveringMemory = true;
176             // Wait a little bit for things to settle down, and off we go.
177             while (!mService.mForceRemoves.isEmpty()) {
178                 final WindowState ws = mService.mForceRemoves.remove(0);
179                 Slog.i(TAG, "Force removing: " + ws);
180                 ws.removeImmediately();
181             }
182             Slog.w(TAG, "Due to memory failure, waiting a bit for next layout");
183             Object tmp = new Object();
184             synchronized (tmp) {
185                 try {
186                     tmp.wait(250);
187                 } catch (InterruptedException e) {
188                 }
189             }
190         }
191 
192         try {
193             mService.mRoot.performSurfacePlacement(recoveringMemory);
194 
195             mInLayout = false;
196 
197             if (mService.mRoot.isLayoutNeeded()) {
198                 if (++mLayoutRepeatCount < 6) {
199                     requestTraversal();
200                 } else {
201                     Slog.e(TAG, "Performed 6 layouts in a row. Skipping");
202                     mLayoutRepeatCount = 0;
203                 }
204             } else {
205                 mLayoutRepeatCount = 0;
206             }
207 
208             if (mService.mWindowsChanged && !mService.mWindowChangeListeners.isEmpty()) {
209                 mService.mH.removeMessages(REPORT_WINDOWS_CHANGE);
210                 mService.mH.sendEmptyMessage(REPORT_WINDOWS_CHANGE);
211             }
212         } catch (RuntimeException e) {
213             mInLayout = false;
214             Slog.wtf(TAG, "Unhandled exception while laying out windows", e);
215         }
216 
217         Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
218     }
219 
debugLayoutRepeats(final String msg, int pendingLayoutChanges)220     void debugLayoutRepeats(final String msg, int pendingLayoutChanges) {
221         if (mLayoutRepeatCount >= LAYOUT_REPEAT_THRESHOLD) {
222             Slog.v(TAG, "Layouts looping: " + msg +
223                     ", mPendingLayoutChanges = 0x" + Integer.toHexString(pendingLayoutChanges));
224         }
225     }
226 
isInLayout()227     boolean isInLayout() {
228         return mInLayout;
229     }
230 
231     /**
232      * @return bitmap indicating if another pass through layout must be made.
233      */
handleAppTransitionReadyLocked()234     int handleAppTransitionReadyLocked() {
235         int appsCount = mService.mOpeningApps.size();
236         if (!transitionGoodToGo(appsCount)) {
237             return 0;
238         }
239         Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "AppTransitionReady");
240 
241         if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
242         int transit = mService.mAppTransition.getAppTransition();
243         if (mService.mSkipAppTransitionAnimation && !isKeyguardGoingAwayTransit(transit)) {
244             transit = AppTransition.TRANSIT_UNSET;
245         }
246         mService.mSkipAppTransitionAnimation = false;
247         mService.mNoAnimationNotifyOnTransitionFinished.clear();
248 
249         mService.mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
250 
251         final DisplayContent displayContent = mService.getDefaultDisplayContentLocked();
252         // TODO: Don't believe this is really needed...
253         //mService.mWindowsChanged = true;
254 
255         mService.mRoot.mWallpaperMayChange = false;
256 
257         // The top-most window will supply the layout params, and we will determine it below.
258         LayoutParams animLp = null;
259         int bestAnimLayer = -1;
260         boolean fullscreenAnim = false;
261         boolean voiceInteraction = false;
262 
263         int i;
264         for (i = 0; i < appsCount; i++) {
265             final AppWindowToken wtoken = mService.mOpeningApps.valueAt(i);
266             // Clearing the mAnimatingExit flag before entering animation. It's set to true if app
267             // window is removed, or window relayout to invisible. This also affects window
268             // visibility. We need to clear it *before* maybeUpdateTransitToWallpaper() as the
269             // transition selection depends on wallpaper target visibility.
270             wtoken.clearAnimatingFlags();
271 
272         }
273 
274         // Adjust wallpaper before we pull the lower/upper target, since pending changes
275         // (like the clearAnimatingFlags() above) might affect wallpaper target result.
276         // Or, the opening app window should be a wallpaper target.
277         mWallpaperControllerLocked.adjustWallpaperWindowsForAppTransitionIfNeeded(displayContent,
278                 mService.mOpeningApps);
279 
280         final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget();
281         boolean openingAppHasWallpaper = false;
282         boolean closingAppHasWallpaper = false;
283 
284         // Do a first pass through the tokens for two things:
285         // (1) Determine if both the closing and opening app token sets are wallpaper targets, in
286         // which case special animations are needed (since the wallpaper needs to stay static behind
287         // them).
288         // (2) Find the layout params of the top-most application window in the tokens, which is
289         // what will control the animation theme.
290         final int closingAppsCount = mService.mClosingApps.size();
291         appsCount = closingAppsCount + mService.mOpeningApps.size();
292         for (i = 0; i < appsCount; i++) {
293             final AppWindowToken wtoken;
294             if (i < closingAppsCount) {
295                 wtoken = mService.mClosingApps.valueAt(i);
296                 if (wallpaperTarget != null && wtoken.windowsCanBeWallpaperTarget()) {
297                     closingAppHasWallpaper = true;
298                 }
299             } else {
300                 wtoken = mService.mOpeningApps.valueAt(i - closingAppsCount);
301                 if (wallpaperTarget != null && wtoken.windowsCanBeWallpaperTarget()) {
302                     openingAppHasWallpaper = true;
303                 }
304             }
305 
306             voiceInteraction |= wtoken.mVoiceInteraction;
307 
308             if (wtoken.fillsParent()) {
309                 final WindowState ws = wtoken.findMainWindow();
310                 if (ws != null) {
311                     animLp = ws.mAttrs;
312                     bestAnimLayer = ws.mLayer;
313                     fullscreenAnim = true;
314                 }
315             } else if (!fullscreenAnim) {
316                 final WindowState ws = wtoken.findMainWindow();
317                 if (ws != null) {
318                     if (ws.mLayer > bestAnimLayer) {
319                         animLp = ws.mAttrs;
320                         bestAnimLayer = ws.mLayer;
321                     }
322                 }
323             }
324         }
325 
326         transit = maybeUpdateTransitToWallpaper(transit, openingAppHasWallpaper,
327                 closingAppHasWallpaper);
328 
329         // If all closing windows are obscured, then there is no need to do an animation. This is
330         // the case, for example, when this transition is being done behind the lock screen.
331         if (!mService.mPolicy.allowAppAnimationsLw()) {
332             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
333                     "Animations disallowed by keyguard or dream.");
334             animLp = null;
335         }
336 
337         processApplicationsAnimatingInPlace(transit);
338 
339         mTmpLayerAndToken.token = null;
340         handleClosingApps(transit, animLp, voiceInteraction, mTmpLayerAndToken);
341         final AppWindowToken topClosingApp = mTmpLayerAndToken.token;
342         final int topClosingLayer = mTmpLayerAndToken.layer;
343 
344         final AppWindowToken topOpeningApp = handleOpeningApps(transit,
345                 animLp, voiceInteraction, topClosingLayer);
346 
347         mService.mAppTransition.setLastAppTransition(transit, topOpeningApp, topClosingApp);
348 
349         final AppWindowAnimator openingAppAnimator = (topOpeningApp == null) ?  null :
350                 topOpeningApp.mAppAnimator;
351         final AppWindowAnimator closingAppAnimator = (topClosingApp == null) ? null :
352                 topClosingApp.mAppAnimator;
353 
354         final int flags = mService.mAppTransition.getTransitFlags();
355         int layoutRedo = mService.mAppTransition.goodToGo(transit, openingAppAnimator,
356                 closingAppAnimator, mService.mOpeningApps, mService.mClosingApps);
357         handleNonAppWindowsInTransition(transit, flags);
358         mService.mAppTransition.postAnimationCallback();
359         mService.mAppTransition.clear();
360 
361         mService.mTaskSnapshotController.onTransitionStarting();
362 
363         mService.mOpeningApps.clear();
364         mService.mClosingApps.clear();
365         mService.mUnknownAppVisibilityController.clear();
366 
367         // This has changed the visibility of windows, so perform
368         // a new layout to get them all up-to-date.
369         displayContent.setLayoutNeeded();
370 
371         // TODO(multidisplay): IMEs are only supported on the default display.
372         final DisplayContent dc = mService.getDefaultDisplayContentLocked();
373         dc.computeImeTarget(true /* updateImeTarget */);
374         mService.updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
375                 true /*updateInputWindows*/);
376         mService.mFocusMayChange = false;
377 
378         Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
379 
380         return layoutRedo | FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG;
381     }
382 
handleOpeningApps(int transit, LayoutParams animLp, boolean voiceInteraction, int topClosingLayer)383     private AppWindowToken handleOpeningApps(int transit, LayoutParams animLp,
384             boolean voiceInteraction, int topClosingLayer) {
385         AppWindowToken topOpeningApp = null;
386         final int appsCount = mService.mOpeningApps.size();
387         for (int i = 0; i < appsCount; i++) {
388             AppWindowToken wtoken = mService.mOpeningApps.valueAt(i);
389             final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
390             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken);
391 
392             if (!appAnimator.usingTransferredAnimation) {
393                 appAnimator.clearThumbnail();
394                 appAnimator.setNullAnimation();
395             }
396 
397             if (!wtoken.setVisibility(animLp, true, transit, false, voiceInteraction)){
398                 // This token isn't going to be animating. Add it to the list of tokens to
399                 // be notified of app transition complete since the notification will not be
400                 // sent be the app window animator.
401                 mService.mNoAnimationNotifyOnTransitionFinished.add(wtoken.token);
402             }
403             wtoken.updateReportedVisibilityLocked();
404             wtoken.waitingToShow = false;
405             wtoken.setAllAppWinAnimators();
406 
407             if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
408                     ">>> OPEN TRANSACTION handleAppTransitionReadyLocked()");
409             mService.openSurfaceTransaction();
410             try {
411                 mService.mAnimator.orAnimating(appAnimator.showAllWindowsLocked());
412             } finally {
413                 mService.closeSurfaceTransaction();
414                 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
415                         "<<< CLOSE TRANSACTION handleAppTransitionReadyLocked()");
416             }
417             mService.mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
418 
419             int topOpeningLayer = 0;
420             if (animLp != null) {
421                 final int layer = wtoken.getHighestAnimLayer();
422                 if (topOpeningApp == null || layer > topOpeningLayer) {
423                     topOpeningApp = wtoken;
424                     topOpeningLayer = layer;
425                 }
426             }
427             if (mService.mAppTransition.isNextAppTransitionThumbnailUp()) {
428                 createThumbnailAppAnimator(transit, wtoken, topOpeningLayer, topClosingLayer);
429             }
430         }
431         return topOpeningApp;
432     }
433 
handleClosingApps(int transit, LayoutParams animLp, boolean voiceInteraction, LayerAndToken layerAndToken)434     private void handleClosingApps(int transit, LayoutParams animLp, boolean voiceInteraction,
435             LayerAndToken layerAndToken) {
436         final int appsCount;
437         appsCount = mService.mClosingApps.size();
438         for (int i = 0; i < appsCount; i++) {
439             AppWindowToken wtoken = mService.mClosingApps.valueAt(i);
440 
441             // If we still have some windows animating with saved surfaces that's
442             // either invisible or already removed, mark them exiting so that they
443             // are disposed of after the exit animation. These are not supposed to
444             // be shown, or are delayed removal until app is actually drawn (in which
445             // case the window will be removed after the animation).
446             wtoken.markSavedSurfaceExiting();
447 
448             final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
449             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now closing app " + wtoken);
450             appAnimator.clearThumbnail();
451             appAnimator.setNullAnimation();
452             // TODO: Do we need to add to mNoAnimationNotifyOnTransitionFinished like above if not
453             //       animating?
454             wtoken.setVisibility(animLp, false, transit, false, voiceInteraction);
455             wtoken.updateReportedVisibilityLocked();
456             // Force the allDrawn flag, because we want to start
457             // this guy's animations regardless of whether it's
458             // gotten drawn.
459             wtoken.allDrawn = true;
460             wtoken.deferClearAllDrawn = false;
461             // Ensure that apps that are mid-starting are also scheduled to have their
462             // starting windows removed after the animation is complete
463             if (wtoken.startingWindow != null && !wtoken.startingWindow.mAnimatingExit
464                     && wtoken.getController() != null) {
465                 wtoken.getController().removeStartingWindow();
466             }
467             mService.mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
468 
469             if (animLp != null) {
470                 int layer = wtoken.getHighestAnimLayer();
471                 if (layerAndToken.token == null || layer > layerAndToken.layer) {
472                     layerAndToken.token = wtoken;
473                     layerAndToken.layer = layer;
474                 }
475             }
476             if (mService.mAppTransition.isNextAppTransitionThumbnailDown()) {
477                 createThumbnailAppAnimator(transit, wtoken, 0, layerAndToken.layer);
478             }
479         }
480     }
481 
handleNonAppWindowsInTransition(int transit, int flags)482     private void handleNonAppWindowsInTransition(int transit, int flags) {
483         if (transit == TRANSIT_KEYGUARD_GOING_AWAY) {
484             if ((flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0
485                     && (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION) == 0) {
486                 Animation anim = mService.mPolicy.createKeyguardWallpaperExit(
487                         (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0);
488                 if (anim != null) {
489                     mService.getDefaultDisplayContentLocked().mWallpaperController
490                             .startWallpaperAnimation(anim);
491                 }
492             }
493         }
494         if (transit == TRANSIT_KEYGUARD_GOING_AWAY
495                 || transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER) {
496             mService.getDefaultDisplayContentLocked().startKeyguardExitOnNonAppWindows(
497                     transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER,
498                     (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0);
499         }
500     }
501 
transitionGoodToGo(int appsCount)502     private boolean transitionGoodToGo(int appsCount) {
503         if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
504                 "Checking " + appsCount + " opening apps (frozen="
505                         + mService.mDisplayFrozen + " timeout="
506                         + mService.mAppTransition.isTimeout() + ")...");
507         final ScreenRotationAnimation screenRotationAnimation =
508             mService.mAnimator.getScreenRotationAnimationLocked(
509                     Display.DEFAULT_DISPLAY);
510 
511         final SparseIntArray reasons = mTempTransitionReasons;
512         if (!mService.mAppTransition.isTimeout()) {
513             // Imagine the case where we are changing orientation due to an app transition, but a previous
514             // orientation change is still in progress. We won't process the orientation change
515             // for our transition because we need to wait for the rotation animation to finish.
516             // If we start the app transition at this point, we will interrupt it halfway with a new rotation
517             // animation after the old one finally finishes. It's better to defer the
518             // app transition.
519             if (screenRotationAnimation != null && screenRotationAnimation.isAnimating() &&
520                     mService.rotationNeedsUpdateLocked()) {
521                 if (DEBUG_APP_TRANSITIONS) {
522                     Slog.v(TAG, "Delaying app transition for screen rotation animation to finish");
523                 }
524                 return false;
525             }
526             for (int i = 0; i < appsCount; i++) {
527                 AppWindowToken wtoken = mService.mOpeningApps.valueAt(i);
528                 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
529                         "Check opening app=" + wtoken + ": allDrawn="
530                         + wtoken.allDrawn + " startingDisplayed="
531                         + wtoken.startingDisplayed + " startingMoved="
532                         + wtoken.startingMoved + " isRelaunching()="
533                         + wtoken.isRelaunching());
534 
535                 final boolean drawnBeforeRestoring = wtoken.allDrawn;
536                 wtoken.restoreSavedSurfaceForInterestingWindows();
537 
538                 final boolean allDrawn = wtoken.allDrawn && !wtoken.isRelaunching();
539                 if (!allDrawn && !wtoken.startingDisplayed && !wtoken.startingMoved) {
540                     return false;
541                 }
542                 final TaskStack stack = wtoken.getStack();
543                 final int stackId = stack != null ? stack.mStackId : INVALID_STACK_ID;
544                 if (allDrawn) {
545                     reasons.put(stackId, drawnBeforeRestoring ? APP_TRANSITION_WINDOWS_DRAWN
546                             : APP_TRANSITION_SAVED_SURFACE);
547                 } else {
548                     reasons.put(stackId, wtoken.startingData instanceof SplashScreenStartingData
549                             ? APP_TRANSITION_SPLASH_SCREEN
550                             : APP_TRANSITION_SNAPSHOT);
551                 }
552             }
553 
554             // We also need to wait for the specs to be fetched, if needed.
555             if (mService.mAppTransition.isFetchingAppTransitionsSpecs()) {
556                 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "isFetchingAppTransitionSpecs=true");
557                 return false;
558             }
559 
560             if (!mService.mUnknownAppVisibilityController.allResolved()) {
561                 if (DEBUG_APP_TRANSITIONS) {
562                     Slog.v(TAG, "unknownApps is not empty: "
563                             + mService.mUnknownAppVisibilityController.getDebugMessage());
564                 }
565                 return false;
566             }
567 
568             // If the wallpaper is visible, we need to check it's ready too.
569             boolean wallpaperReady = !mWallpaperControllerLocked.isWallpaperVisible() ||
570                     mWallpaperControllerLocked.wallpaperTransitionReady();
571             if (wallpaperReady) {
572                 mService.mH.obtainMessage(NOTIFY_APP_TRANSITION_STARTING, reasons.clone())
573                         .sendToTarget();
574                 return true;
575             }
576             return false;
577         }
578         mService.mH.obtainMessage(NOTIFY_APP_TRANSITION_STARTING, reasons.clone()).sendToTarget();
579         return true;
580     }
581 
maybeUpdateTransitToWallpaper(int transit, boolean openingAppHasWallpaper, boolean closingAppHasWallpaper)582     private int maybeUpdateTransitToWallpaper(int transit, boolean openingAppHasWallpaper,
583             boolean closingAppHasWallpaper) {
584         // Given no app transition pass it through instead of a wallpaper transition
585         if (transit == TRANSIT_NONE) {
586             return TRANSIT_NONE;
587         }
588 
589         // if wallpaper is animating in or out set oldWallpaper to null else to wallpaper
590         final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget();
591         final WindowState oldWallpaper = mWallpaperControllerLocked.isWallpaperTargetAnimating()
592                 ? null : wallpaperTarget;
593         final ArraySet<AppWindowToken> openingApps = mService.mOpeningApps;
594         final ArraySet<AppWindowToken> closingApps = mService.mClosingApps;
595         boolean openingCanBeWallpaperTarget = canBeWallpaperTarget(openingApps);
596         if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
597                 "New wallpaper target=" + wallpaperTarget
598                         + ", oldWallpaper=" + oldWallpaper
599                         + ", openingApps=" + openingApps
600                         + ", closingApps=" + closingApps);
601         mService.mAnimateWallpaperWithTarget = false;
602         if (openingCanBeWallpaperTarget && transit == TRANSIT_KEYGUARD_GOING_AWAY) {
603             transit = TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
604             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
605                     "New transit: " + AppTransition.appTransitionToString(transit));
606         }
607         // We never want to change from a Keyguard transit to a non-Keyguard transit, as our logic
608         // relies on the fact that we always execute a Keyguard transition after preparing one.
609         else if (!isKeyguardGoingAwayTransit(transit)) {
610             if (closingAppHasWallpaper && openingAppHasWallpaper) {
611                 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Wallpaper animation!");
612                 switch (transit) {
613                     case TRANSIT_ACTIVITY_OPEN:
614                     case TRANSIT_TASK_OPEN:
615                     case TRANSIT_TASK_TO_FRONT:
616                         transit = TRANSIT_WALLPAPER_INTRA_OPEN;
617                         break;
618                     case TRANSIT_ACTIVITY_CLOSE:
619                     case TRANSIT_TASK_CLOSE:
620                     case TRANSIT_TASK_TO_BACK:
621                         transit = TRANSIT_WALLPAPER_INTRA_CLOSE;
622                         break;
623                 }
624                 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
625                         "New transit: " + AppTransition.appTransitionToString(transit));
626             } else if (oldWallpaper != null && !mService.mOpeningApps.isEmpty()
627                     && !openingApps.contains(oldWallpaper.mAppToken)
628                     && closingApps.contains(oldWallpaper.mAppToken)) {
629                 // We are transitioning from an activity with a wallpaper to one without.
630                 transit = TRANSIT_WALLPAPER_CLOSE;
631                 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit away from wallpaper: "
632                         + AppTransition.appTransitionToString(transit));
633             } else if (wallpaperTarget != null && wallpaperTarget.isVisibleLw() &&
634                     openingApps.contains(wallpaperTarget.mAppToken)) {
635                 // We are transitioning from an activity without
636                 // a wallpaper to now showing the wallpaper
637                 transit = TRANSIT_WALLPAPER_OPEN;
638                 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit into wallpaper: "
639                         + AppTransition.appTransitionToString(transit));
640             } else {
641                 mService.mAnimateWallpaperWithTarget = true;
642             }
643         }
644         return transit;
645     }
646 
canBeWallpaperTarget(ArraySet<AppWindowToken> apps)647     private boolean canBeWallpaperTarget(ArraySet<AppWindowToken> apps) {
648         for (int i = apps.size() - 1; i >= 0; i--) {
649             if (apps.valueAt(i).windowsCanBeWallpaperTarget()) {
650                 return true;
651             }
652         }
653         return false;
654     }
655 
processApplicationsAnimatingInPlace(int transit)656     private void processApplicationsAnimatingInPlace(int transit) {
657         if (transit == TRANSIT_TASK_IN_PLACE) {
658             // Find the focused window
659             final WindowState win = mService.getDefaultDisplayContentLocked().findFocusedWindow();
660             if (win != null) {
661                 final AppWindowToken wtoken = win.mAppToken;
662                 final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
663                 if (DEBUG_APP_TRANSITIONS)
664                     Slog.v(TAG, "Now animating app in place " + wtoken);
665                 appAnimator.clearThumbnail();
666                 appAnimator.setNullAnimation();
667                 mService.updateTokenInPlaceLocked(wtoken, transit);
668                 wtoken.updateReportedVisibilityLocked();
669                 wtoken.setAllAppWinAnimators();
670                 mService.mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
671                 mService.mAnimator.orAnimating(appAnimator.showAllWindowsLocked());
672             }
673         }
674     }
675 
createThumbnailAppAnimator(int transit, AppWindowToken appToken, int openingLayer, int closingLayer)676     private void createThumbnailAppAnimator(int transit, AppWindowToken appToken,
677             int openingLayer, int closingLayer) {
678         AppWindowAnimator openingAppAnimator = (appToken == null) ? null : appToken.mAppAnimator;
679         if (openingAppAnimator == null || openingAppAnimator.animation == null) {
680             return;
681         }
682         final int taskId = appToken.getTask().mTaskId;
683         final GraphicBuffer thumbnailHeader =
684                 mService.mAppTransition.getAppTransitionThumbnailHeader(taskId);
685         if (thumbnailHeader == null) {
686             if (DEBUG_APP_TRANSITIONS) Slog.d(TAG, "No thumbnail header bitmap for: " + taskId);
687             return;
688         }
689         // This thumbnail animation is very special, we need to have
690         // an extra surface with the thumbnail included with the animation.
691         Rect dirty = new Rect(0, 0, thumbnailHeader.getWidth(), thumbnailHeader.getHeight());
692         try {
693             // TODO(multi-display): support other displays
694             final DisplayContent displayContent = mService.getDefaultDisplayContentLocked();
695             final Display display = displayContent.getDisplay();
696             final DisplayInfo displayInfo = displayContent.getDisplayInfo();
697 
698             // Create a new surface for the thumbnail
699             WindowState window = appToken.findMainWindow();
700             SurfaceControl surfaceControl = new SurfaceControl(mService.mFxSession,
701                     "thumbnail anim", dirty.width(), dirty.height(),
702                     PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN,
703                     appToken.windowType,
704                     window != null ? window.mOwnerUid : Binder.getCallingUid());
705             surfaceControl.setLayerStack(display.getLayerStack());
706             if (SHOW_TRANSACTIONS) {
707                 Slog.i(TAG, "  THUMBNAIL " + surfaceControl + ": CREATE");
708             }
709 
710             // Transfer the thumbnail to the surface
711             Surface drawSurface = new Surface();
712             drawSurface.copyFrom(surfaceControl);
713             drawSurface.attachAndQueueBuffer(thumbnailHeader);
714             drawSurface.release();
715 
716             // Get the thumbnail animation
717             Animation anim;
718             if (mService.mAppTransition.isNextThumbnailTransitionAspectScaled()) {
719                 // If this is a multi-window scenario, we use the windows frame as
720                 // destination of the thumbnail header animation. If this is a full screen
721                 // window scenario, we use the whole display as the target.
722                 WindowState win = appToken.findMainWindow();
723                 Rect appRect = win != null ? win.getContentFrameLw() :
724                         new Rect(0, 0, displayInfo.appWidth, displayInfo.appHeight);
725                 Rect insets = win != null ? win.mContentInsets : null;
726                 final Configuration displayConfig = displayContent.getConfiguration();
727                 // For the new aspect-scaled transition, we want it to always show
728                 // above the animating opening/closing window, and we want to
729                 // synchronize its thumbnail surface with the surface for the
730                 // open/close animation (only on the way down)
731                 anim = mService.mAppTransition.createThumbnailAspectScaleAnimationLocked(appRect,
732                         insets, thumbnailHeader, taskId, displayConfig.uiMode,
733                         displayConfig.orientation);
734                 openingAppAnimator.thumbnailForceAboveLayer = Math.max(openingLayer, closingLayer);
735                 openingAppAnimator.deferThumbnailDestruction =
736                         !mService.mAppTransition.isNextThumbnailTransitionScaleUp();
737             } else {
738                 anim = mService.mAppTransition.createThumbnailScaleAnimationLocked(
739                         displayInfo.appWidth, displayInfo.appHeight, transit, thumbnailHeader);
740             }
741             anim.restrictDuration(MAX_ANIMATION_DURATION);
742             anim.scaleCurrentDuration(mService.getTransitionAnimationScaleLocked());
743 
744             openingAppAnimator.thumbnail = surfaceControl;
745             openingAppAnimator.thumbnailLayer = openingLayer;
746             openingAppAnimator.thumbnailAnimation = anim;
747             mService.mAppTransition.getNextAppTransitionStartRect(taskId, mTmpStartRect);
748         } catch (Surface.OutOfResourcesException e) {
749             Slog.e(TAG, "Can't allocate thumbnail/Canvas surface w="
750                     + dirty.width() + " h=" + dirty.height(), e);
751             openingAppAnimator.clearThumbnail();
752         }
753     }
754 
requestTraversal()755     void requestTraversal() {
756         if (!mTraversalScheduled) {
757             mTraversalScheduled = true;
758             mService.mAnimationHandler.post(mPerformSurfacePlacement);
759         }
760     }
761 
762     /**
763      * Puts the {@param surface} into a pending list to be destroyed after the current transaction
764      * has been committed.
765      */
destroyAfterTransaction(SurfaceControl surface)766     void destroyAfterTransaction(SurfaceControl surface) {
767         mPendingDestroyingSurfaces.add(surface);
768     }
769 
770     /**
771      * Destroys any surfaces that have been put into the pending list with
772      * {@link #destroyAfterTransaction}.
773      */
destroyPendingSurfaces()774     void destroyPendingSurfaces() {
775         for (int i = mPendingDestroyingSurfaces.size() - 1; i >= 0; i--) {
776             mPendingDestroyingSurfaces.get(i).destroy();
777         }
778         mPendingDestroyingSurfaces.clear();
779     }
780 
dump(PrintWriter pw, String prefix)781     public void dump(PrintWriter pw, String prefix) {
782         pw.println(prefix + "mTraversalScheduled=" + mTraversalScheduled);
783         pw.println(prefix + "mHoldScreenWindow=" + mService.mRoot.mHoldScreenWindow);
784         pw.println(prefix + "mObscuringWindow=" + mService.mRoot.mObscuringWindow);
785     }
786 }
787