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