Home | History | Annotate | Download | only in wm
      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 
    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      */
    116     void deferLayout() {
    117         mDeferDepth++;
    118     }
    119 
    120     /**
    121      * See {@link WindowManagerService#continueSurfaceLayout()}
    122      */
    123     void continueLayout() {
    124         mDeferDepth--;
    125         if (mDeferDepth <= 0) {
    126             performSurfacePlacement();
    127         }
    128     }
    129 
    130     final void performSurfacePlacement() {
    131         performSurfacePlacement(false /* force */);
    132     }
    133 
    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 
    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 
    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 
    227     boolean isInLayout() {
    228         return mInLayout;
    229     }
    230 
    231     /**
    232      * @return bitmap indicating if another pass through layout must be made.
    233      */
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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      */
    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      */
    774     void destroyPendingSurfaces() {
    775         for (int i = mPendingDestroyingSurfaces.size() - 1; i >= 0; i--) {
    776             mPendingDestroyingSurfaces.get(i).destroy();
    777         }
    778         mPendingDestroyingSurfaces.clear();
    779     }
    780 
    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