Home | History | Annotate | Download | only in wm
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License
     15  */
     16 
     17 package com.android.server.wm;
     18 
     19 import static android.app.ActivityManagerInternal.APP_TRANSITION_SNAPSHOT;
     20 import static android.app.ActivityManagerInternal.APP_TRANSITION_SPLASH_SCREEN;
     21 import static android.app.ActivityManagerInternal.APP_TRANSITION_WINDOWS_DRAWN;
     22 
     23 import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE;
     24 import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS;
     25 import static android.view.WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE;
     26 import static android.view.WindowManager.TRANSIT_TRANSLUCENT_ACTIVITY_OPEN;
     27 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
     28 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
     29 import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE;
     30 import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
     31 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
     32 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
     33 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
     34 import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
     35 import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
     36 import static android.view.WindowManager.TRANSIT_NONE;
     37 import static android.view.WindowManager.TRANSIT_TASK_CLOSE;
     38 import static android.view.WindowManager.TRANSIT_TASK_IN_PLACE;
     39 import static android.view.WindowManager.TRANSIT_TASK_OPEN;
     40 import static android.view.WindowManager.TRANSIT_TASK_TO_BACK;
     41 import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
     42 import static android.view.WindowManager.TRANSIT_WALLPAPER_CLOSE;
     43 import static android.view.WindowManager.TRANSIT_WALLPAPER_INTRA_CLOSE;
     44 import static android.view.WindowManager.TRANSIT_WALLPAPER_INTRA_OPEN;
     45 import static android.view.WindowManager.TRANSIT_WALLPAPER_OPEN;
     46 import static com.android.server.wm.AppTransition.isKeyguardGoingAwayTransit;
     47 import static com.android.server.wm.AppTransition.isTaskTransit;
     48 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
     49 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
     50 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
     51 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
     52 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
     53 import static com.android.server.wm.WindowManagerService.H.NOTIFY_APP_TRANSITION_STARTING;
     54 import static com.android.server.wm.WindowManagerService.H.REPORT_WINDOWS_CHANGE;
     55 import static com.android.server.wm.WindowManagerService.LAYOUT_REPEAT_THRESHOLD;
     56 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SURFACES;
     57 
     58 import android.app.WindowConfiguration;
     59 import android.os.Debug;
     60 import android.os.Trace;
     61 import android.util.ArraySet;
     62 import android.util.Slog;
     63 import android.util.SparseIntArray;
     64 import android.view.Display;
     65 import android.view.RemoteAnimationAdapter;
     66 import android.view.RemoteAnimationDefinition;
     67 import android.view.WindowManager;
     68 import android.view.WindowManager.LayoutParams;
     69 import android.view.WindowManager.TransitionType;
     70 import android.view.animation.Animation;
     71 
     72 import com.android.internal.annotations.VisibleForTesting;
     73 import com.android.server.wm.WindowManagerService.H;
     74 
     75 import java.io.PrintWriter;
     76 import java.util.function.Predicate;
     77 
     78 /**
     79  * Positions windows and their surfaces.
     80  *
     81  * It sets positions of windows by calculating their frames and then applies this by positioning
     82  * surfaces according to these frames. Z layer is still assigned withing WindowManagerService.
     83  */
     84 class WindowSurfacePlacer {
     85     private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowSurfacePlacer" : TAG_WM;
     86     private final WindowManagerService mService;
     87     private final WallpaperController mWallpaperControllerLocked;
     88 
     89     private boolean mInLayout = false;
     90 
     91     /** Only do a maximum of 6 repeated layouts. After that quit */
     92     private int mLayoutRepeatCount;
     93 
     94     static final int SET_UPDATE_ROTATION                = 1 << 0;
     95     static final int SET_WALLPAPER_MAY_CHANGE           = 1 << 1;
     96     static final int SET_FORCE_HIDING_CHANGED           = 1 << 2;
     97     static final int SET_ORIENTATION_CHANGE_COMPLETE    = 1 << 3;
     98     static final int SET_WALLPAPER_ACTION_PENDING       = 1 << 4;
     99 
    100     private boolean mTraversalScheduled;
    101     private int mDeferDepth = 0;
    102 
    103     private static final class LayerAndToken {
    104         public int layer;
    105         public AppWindowToken token;
    106     }
    107     private final LayerAndToken mTmpLayerAndToken = new LayerAndToken();
    108 
    109     private final SparseIntArray mTempTransitionReasons = new SparseIntArray();
    110 
    111     private final Runnable mPerformSurfacePlacement;
    112 
    113     public WindowSurfacePlacer(WindowManagerService service) {
    114         mService = service;
    115         mWallpaperControllerLocked = mService.mRoot.mWallpaperController;
    116         mPerformSurfacePlacement = () -> {
    117             synchronized (mService.mWindowMap) {
    118                 performSurfacePlacement();
    119             }
    120         };
    121     }
    122 
    123     /**
    124      * See {@link WindowManagerService#deferSurfaceLayout()}
    125      */
    126     void deferLayout() {
    127         mDeferDepth++;
    128     }
    129 
    130     /**
    131      * See {@link WindowManagerService#continueSurfaceLayout()}
    132      */
    133     void continueLayout() {
    134         mDeferDepth--;
    135         if (mDeferDepth <= 0) {
    136             performSurfacePlacement();
    137         }
    138     }
    139 
    140     boolean isLayoutDeferred() {
    141         return mDeferDepth > 0;
    142     }
    143 
    144     final void performSurfacePlacement() {
    145         performSurfacePlacement(false /* force */);
    146     }
    147 
    148     final void performSurfacePlacement(boolean force) {
    149         if (mDeferDepth > 0 && !force) {
    150             return;
    151         }
    152         int loopCount = 6;
    153         do {
    154             mTraversalScheduled = false;
    155             performSurfacePlacementLoop();
    156             mService.mAnimationHandler.removeCallbacks(mPerformSurfacePlacement);
    157             loopCount--;
    158         } while (mTraversalScheduled && loopCount > 0);
    159         mService.mRoot.mWallpaperActionPending = false;
    160     }
    161 
    162     private void performSurfacePlacementLoop() {
    163         if (mInLayout) {
    164             if (DEBUG) {
    165                 throw new RuntimeException("Recursive call!");
    166             }
    167             Slog.w(TAG, "performLayoutAndPlaceSurfacesLocked called while in layout. Callers="
    168                     + Debug.getCallers(3));
    169             return;
    170         }
    171 
    172         if (mService.mWaitingForConfig) {
    173             // Our configuration has changed (most likely rotation), but we
    174             // don't yet have the complete configuration to report to
    175             // applications.  Don't do any window layout until we have it.
    176             return;
    177         }
    178 
    179         if (!mService.mDisplayReady) {
    180             // Not yet initialized, nothing to do.
    181             return;
    182         }
    183 
    184         Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmLayout");
    185         mInLayout = true;
    186 
    187         boolean recoveringMemory = false;
    188         if (!mService.mForceRemoves.isEmpty()) {
    189             recoveringMemory = true;
    190             // Wait a little bit for things to settle down, and off we go.
    191             while (!mService.mForceRemoves.isEmpty()) {
    192                 final WindowState ws = mService.mForceRemoves.remove(0);
    193                 Slog.i(TAG, "Force removing: " + ws);
    194                 ws.removeImmediately();
    195             }
    196             Slog.w(TAG, "Due to memory failure, waiting a bit for next layout");
    197             Object tmp = new Object();
    198             synchronized (tmp) {
    199                 try {
    200                     tmp.wait(250);
    201                 } catch (InterruptedException e) {
    202                 }
    203             }
    204         }
    205 
    206         try {
    207             mService.mRoot.performSurfacePlacement(recoveringMemory);
    208 
    209             mInLayout = false;
    210 
    211             if (mService.mRoot.isLayoutNeeded()) {
    212                 if (++mLayoutRepeatCount < 6) {
    213                     requestTraversal();
    214                 } else {
    215                     Slog.e(TAG, "Performed 6 layouts in a row. Skipping");
    216                     mLayoutRepeatCount = 0;
    217                 }
    218             } else {
    219                 mLayoutRepeatCount = 0;
    220             }
    221 
    222             if (mService.mWindowsChanged && !mService.mWindowChangeListeners.isEmpty()) {
    223                 mService.mH.removeMessages(REPORT_WINDOWS_CHANGE);
    224                 mService.mH.sendEmptyMessage(REPORT_WINDOWS_CHANGE);
    225             }
    226         } catch (RuntimeException e) {
    227             mInLayout = false;
    228             Slog.wtf(TAG, "Unhandled exception while laying out windows", e);
    229         }
    230 
    231         Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
    232     }
    233 
    234     void debugLayoutRepeats(final String msg, int pendingLayoutChanges) {
    235         if (mLayoutRepeatCount >= LAYOUT_REPEAT_THRESHOLD) {
    236             Slog.v(TAG, "Layouts looping: " + msg +
    237                     ", mPendingLayoutChanges = 0x" + Integer.toHexString(pendingLayoutChanges));
    238         }
    239     }
    240 
    241     boolean isInLayout() {
    242         return mInLayout;
    243     }
    244 
    245     /**
    246      * @return bitmap indicating if another pass through layout must be made.
    247      */
    248     int handleAppTransitionReadyLocked() {
    249         int appsCount = mService.mOpeningApps.size();
    250         if (!transitionGoodToGo(appsCount, mTempTransitionReasons)) {
    251             return 0;
    252         }
    253         Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "AppTransitionReady");
    254 
    255         if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
    256         int transit = mService.mAppTransition.getAppTransition();
    257         if (mService.mSkipAppTransitionAnimation && !isKeyguardGoingAwayTransit(transit)) {
    258             transit = WindowManager.TRANSIT_UNSET;
    259         }
    260         mService.mSkipAppTransitionAnimation = false;
    261         mService.mNoAnimationNotifyOnTransitionFinished.clear();
    262 
    263         mService.mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
    264 
    265         final DisplayContent displayContent = mService.getDefaultDisplayContentLocked();
    266 
    267         mService.mRoot.mWallpaperMayChange = false;
    268 
    269         int i;
    270         for (i = 0; i < appsCount; i++) {
    271             final AppWindowToken wtoken = mService.mOpeningApps.valueAt(i);
    272             // Clearing the mAnimatingExit flag before entering animation. It's set to true if app
    273             // window is removed, or window relayout to invisible. This also affects window
    274             // visibility. We need to clear it *before* maybeUpdateTransitToWallpaper() as the
    275             // transition selection depends on wallpaper target visibility.
    276             wtoken.clearAnimatingFlags();
    277         }
    278 
    279         // Adjust wallpaper before we pull the lower/upper target, since pending changes
    280         // (like the clearAnimatingFlags() above) might affect wallpaper target result.
    281         // Or, the opening app window should be a wallpaper target.
    282         mWallpaperControllerLocked.adjustWallpaperWindowsForAppTransitionIfNeeded(displayContent,
    283                 mService.mOpeningApps);
    284 
    285         // Determine if closing and opening app token sets are wallpaper targets, in which case
    286         // special animations are needed.
    287         final boolean hasWallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget() != null;
    288         final boolean openingAppHasWallpaper = canBeWallpaperTarget(mService.mOpeningApps)
    289                 && hasWallpaperTarget;
    290         final boolean closingAppHasWallpaper = canBeWallpaperTarget(mService.mClosingApps)
    291                 && hasWallpaperTarget;
    292 
    293         transit = maybeUpdateTransitToTranslucentAnim(transit);
    294         transit = maybeUpdateTransitToWallpaper(transit, openingAppHasWallpaper,
    295                 closingAppHasWallpaper);
    296 
    297         // Find the layout params of the top-most application window in the tokens, which is
    298         // what will control the animation theme. If all closing windows are obscured, then there is
    299         // no need to do an animation. This is the case, for example, when this transition is being
    300         // done behind a dream window.
    301         final ArraySet<Integer> activityTypes = collectActivityTypes(mService.mOpeningApps,
    302                 mService.mClosingApps);
    303         final AppWindowToken animLpToken = mService.mPolicy.allowAppAnimationsLw()
    304                 ? findAnimLayoutParamsToken(transit, activityTypes)
    305                 : null;
    306 
    307         final LayoutParams animLp = getAnimLp(animLpToken);
    308         overrideWithRemoteAnimationIfSet(animLpToken, transit, activityTypes);
    309 
    310         final boolean voiceInteraction = containsVoiceInteraction(mService.mOpeningApps)
    311                 || containsVoiceInteraction(mService.mOpeningApps);
    312 
    313         final int layoutRedo;
    314         mService.mSurfaceAnimationRunner.deferStartingAnimations();
    315         try {
    316             processApplicationsAnimatingInPlace(transit);
    317 
    318             mTmpLayerAndToken.token = null;
    319             handleClosingApps(transit, animLp, voiceInteraction, mTmpLayerAndToken);
    320             final AppWindowToken topClosingApp = mTmpLayerAndToken.token;
    321             final AppWindowToken topOpeningApp = handleOpeningApps(transit, animLp,
    322                     voiceInteraction);
    323 
    324             mService.mAppTransition.setLastAppTransition(transit, topOpeningApp, topClosingApp);
    325 
    326             final int flags = mService.mAppTransition.getTransitFlags();
    327             layoutRedo = mService.mAppTransition.goodToGo(transit, topOpeningApp,
    328                     topClosingApp, mService.mOpeningApps, mService.mClosingApps);
    329             handleNonAppWindowsInTransition(transit, flags);
    330             mService.mAppTransition.postAnimationCallback();
    331             mService.mAppTransition.clear();
    332         } finally {
    333             mService.mSurfaceAnimationRunner.continueStartingAnimations();
    334         }
    335 
    336         mService.mTaskSnapshotController.onTransitionStarting();
    337 
    338         mService.mOpeningApps.clear();
    339         mService.mClosingApps.clear();
    340         mService.mUnknownAppVisibilityController.clear();
    341 
    342         // This has changed the visibility of windows, so perform
    343         // a new layout to get them all up-to-date.
    344         displayContent.setLayoutNeeded();
    345 
    346         // TODO(multidisplay): IMEs are only supported on the default display.
    347         final DisplayContent dc = mService.getDefaultDisplayContentLocked();
    348         dc.computeImeTarget(true /* updateImeTarget */);
    349         mService.updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
    350                 true /*updateInputWindows*/);
    351         mService.mFocusMayChange = false;
    352 
    353         mService.mH.obtainMessage(NOTIFY_APP_TRANSITION_STARTING,
    354                 mTempTransitionReasons.clone()).sendToTarget();
    355 
    356         Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
    357 
    358         return layoutRedo | FINISH_LAYOUT_REDO_LAYOUT | FINISH_LAYOUT_REDO_CONFIG;
    359     }
    360 
    361     private static LayoutParams getAnimLp(AppWindowToken wtoken) {
    362         final WindowState mainWindow = wtoken != null ? wtoken.findMainWindow() : null;
    363         return mainWindow != null ? mainWindow.mAttrs : null;
    364     }
    365 
    366     /**
    367      * Overrides the pending transition with the remote animation defined for the transition in the
    368      * set of defined remote animations in the app window token.
    369      */
    370     private void overrideWithRemoteAnimationIfSet(AppWindowToken animLpToken, int transit,
    371             ArraySet<Integer> activityTypes) {
    372         if (transit == TRANSIT_CRASHING_ACTIVITY_CLOSE) {
    373             // The crash transition has higher priority than any involved remote animations.
    374             return;
    375         }
    376         if (animLpToken == null) {
    377             return;
    378         }
    379         final RemoteAnimationDefinition definition = animLpToken.getRemoteAnimationDefinition();
    380         if (definition != null) {
    381             final RemoteAnimationAdapter adapter = definition.getAdapter(transit, activityTypes);
    382             if (adapter != null) {
    383                 mService.mAppTransition.overridePendingAppTransitionRemote(adapter);
    384             }
    385         }
    386     }
    387 
    388     /**
    389      * @return The window token that determines the animation theme.
    390      */
    391     private AppWindowToken findAnimLayoutParamsToken(@TransitionType int transit,
    392             ArraySet<Integer> activityTypes) {
    393         AppWindowToken result;
    394 
    395         // Remote animations always win, but fullscreen tokens override non-fullscreen tokens.
    396         result = lookForHighestTokenWithFilter(mService.mClosingApps, mService.mOpeningApps,
    397                 w -> w.getRemoteAnimationDefinition() != null
    398                         && w.getRemoteAnimationDefinition().hasTransition(transit, activityTypes));
    399         if (result != null) {
    400             return result;
    401         }
    402         result = lookForHighestTokenWithFilter(mService.mClosingApps, mService.mOpeningApps,
    403                 w -> w.fillsParent() && w.findMainWindow() != null);
    404         if (result != null) {
    405             return result;
    406         }
    407         return lookForHighestTokenWithFilter(mService.mClosingApps, mService.mOpeningApps,
    408                 w -> w.findMainWindow() != null);
    409     }
    410 
    411     /**
    412      * @return The set of {@link WindowConfiguration.ActivityType}s contained in the set of apps in
    413      *         {@code array1} and {@code array2}.
    414      */
    415     private ArraySet<Integer> collectActivityTypes(ArraySet<AppWindowToken> array1,
    416             ArraySet<AppWindowToken> array2) {
    417         final ArraySet<Integer> result = new ArraySet<>();
    418         for (int i = array1.size() - 1; i >= 0; i--) {
    419             result.add(array1.valueAt(i).getActivityType());
    420         }
    421         for (int i = array2.size() - 1; i >= 0; i--) {
    422             result.add(array2.valueAt(i).getActivityType());
    423         }
    424         return result;
    425     }
    426 
    427     private AppWindowToken lookForHighestTokenWithFilter(ArraySet<AppWindowToken> array1,
    428             ArraySet<AppWindowToken> array2, Predicate<AppWindowToken> filter) {
    429         final int array1count = array1.size();
    430         final int count = array1count + array2.size();
    431         int bestPrefixOrderIndex = Integer.MIN_VALUE;
    432         AppWindowToken bestToken = null;
    433         for (int i = 0; i < count; i++) {
    434             final AppWindowToken wtoken = i < array1count
    435                     ? array1.valueAt(i)
    436                     : array2.valueAt(i - array1count);
    437             final int prefixOrderIndex = wtoken.getPrefixOrderIndex();
    438             if (filter.test(wtoken) && prefixOrderIndex > bestPrefixOrderIndex) {
    439                 bestPrefixOrderIndex = prefixOrderIndex;
    440                 bestToken = wtoken;
    441             }
    442         }
    443         return bestToken;
    444     }
    445 
    446     private boolean containsVoiceInteraction(ArraySet<AppWindowToken> apps) {
    447         for (int i = apps.size() - 1; i >= 0; i--) {
    448             if (apps.valueAt(i).mVoiceInteraction) {
    449                 return true;
    450             }
    451         }
    452         return false;
    453     }
    454 
    455     private AppWindowToken handleOpeningApps(int transit, LayoutParams animLp,
    456             boolean voiceInteraction) {
    457         AppWindowToken topOpeningApp = null;
    458         int topOpeningLayer = Integer.MIN_VALUE;
    459         final int appsCount = mService.mOpeningApps.size();
    460         for (int i = 0; i < appsCount; i++) {
    461             AppWindowToken wtoken = mService.mOpeningApps.valueAt(i);
    462             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken);
    463 
    464             if (!wtoken.setVisibility(animLp, true, transit, false, voiceInteraction)) {
    465                 // This token isn't going to be animating. Add it to the list of tokens to
    466                 // be notified of app transition complete since the notification will not be
    467                 // sent be the app window animator.
    468                 mService.mNoAnimationNotifyOnTransitionFinished.add(wtoken.token);
    469             }
    470             wtoken.updateReportedVisibilityLocked();
    471             wtoken.waitingToShow = false;
    472             if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
    473                     ">>> OPEN TRANSACTION handleAppTransitionReadyLocked()");
    474             mService.openSurfaceTransaction();
    475             try {
    476                 wtoken.showAllWindowsLocked();
    477             } finally {
    478                 mService.closeSurfaceTransaction("handleAppTransitionReadyLocked");
    479                 if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
    480                         "<<< CLOSE TRANSACTION handleAppTransitionReadyLocked()");
    481             }
    482 
    483             if (animLp != null) {
    484                 final int layer = wtoken.getHighestAnimLayer();
    485                 if (topOpeningApp == null || layer > topOpeningLayer) {
    486                     topOpeningApp = wtoken;
    487                     topOpeningLayer = layer;
    488                 }
    489             }
    490             if (mService.mAppTransition.isNextAppTransitionThumbnailUp()) {
    491                 wtoken.attachThumbnailAnimation();
    492             } else if (mService.mAppTransition.isNextAppTransitionOpenCrossProfileApps()) {
    493                 wtoken.attachCrossProfileAppsThumbnailAnimation();
    494             }
    495         }
    496         return topOpeningApp;
    497     }
    498 
    499     private void handleClosingApps(int transit, LayoutParams animLp, boolean voiceInteraction,
    500             LayerAndToken layerAndToken) {
    501         final int appsCount;
    502         appsCount = mService.mClosingApps.size();
    503         for (int i = 0; i < appsCount; i++) {
    504             AppWindowToken wtoken = mService.mClosingApps.valueAt(i);
    505 
    506             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now closing app " + wtoken);
    507             // TODO: Do we need to add to mNoAnimationNotifyOnTransitionFinished like above if not
    508             //       animating?
    509             wtoken.setVisibility(animLp, false, transit, false, voiceInteraction);
    510             wtoken.updateReportedVisibilityLocked();
    511             // Force the allDrawn flag, because we want to start
    512             // this guy's animations regardless of whether it's
    513             // gotten drawn.
    514             wtoken.allDrawn = true;
    515             wtoken.deferClearAllDrawn = false;
    516             // Ensure that apps that are mid-starting are also scheduled to have their
    517             // starting windows removed after the animation is complete
    518             if (wtoken.startingWindow != null && !wtoken.startingWindow.mAnimatingExit
    519                     && wtoken.getController() != null) {
    520                 wtoken.getController().removeStartingWindow();
    521             }
    522 
    523             if (animLp != null) {
    524                 int layer = wtoken.getHighestAnimLayer();
    525                 if (layerAndToken.token == null || layer > layerAndToken.layer) {
    526                     layerAndToken.token = wtoken;
    527                     layerAndToken.layer = layer;
    528                 }
    529             }
    530             if (mService.mAppTransition.isNextAppTransitionThumbnailDown()) {
    531                 wtoken.attachThumbnailAnimation();
    532             }
    533         }
    534     }
    535 
    536     private void handleNonAppWindowsInTransition(int transit, int flags) {
    537         if (transit == TRANSIT_KEYGUARD_GOING_AWAY) {
    538             if ((flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0
    539                     && (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION) == 0) {
    540                 Animation anim = mService.mPolicy.createKeyguardWallpaperExit(
    541                         (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0);
    542                 if (anim != null) {
    543                     mService.getDefaultDisplayContentLocked().mWallpaperController
    544                             .startWallpaperAnimation(anim);
    545                 }
    546             }
    547         }
    548         if (transit == TRANSIT_KEYGUARD_GOING_AWAY
    549                 || transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER) {
    550             mService.getDefaultDisplayContentLocked().startKeyguardExitOnNonAppWindows(
    551                     transit == TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER,
    552                     (flags & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE) != 0);
    553         }
    554     }
    555 
    556     private boolean transitionGoodToGo(int appsCount, SparseIntArray outReasons) {
    557         if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
    558                 "Checking " + appsCount + " opening apps (frozen="
    559                         + mService.mDisplayFrozen + " timeout="
    560                         + mService.mAppTransition.isTimeout() + ")...");
    561         final ScreenRotationAnimation screenRotationAnimation =
    562             mService.mAnimator.getScreenRotationAnimationLocked(
    563                     Display.DEFAULT_DISPLAY);
    564 
    565         outReasons.clear();
    566         if (!mService.mAppTransition.isTimeout()) {
    567             // Imagine the case where we are changing orientation due to an app transition, but a previous
    568             // orientation change is still in progress. We won't process the orientation change
    569             // for our transition because we need to wait for the rotation animation to finish.
    570             // If we start the app transition at this point, we will interrupt it halfway with a new rotation
    571             // animation after the old one finally finishes. It's better to defer the
    572             // app transition.
    573             if (screenRotationAnimation != null && screenRotationAnimation.isAnimating() &&
    574                     mService.rotationNeedsUpdateLocked()) {
    575                 if (DEBUG_APP_TRANSITIONS) {
    576                     Slog.v(TAG, "Delaying app transition for screen rotation animation to finish");
    577                 }
    578                 return false;
    579             }
    580             for (int i = 0; i < appsCount; i++) {
    581                 AppWindowToken wtoken = mService.mOpeningApps.valueAt(i);
    582                 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
    583                         "Check opening app=" + wtoken + ": allDrawn="
    584                         + wtoken.allDrawn + " startingDisplayed="
    585                         + wtoken.startingDisplayed + " startingMoved="
    586                         + wtoken.startingMoved + " isRelaunching()="
    587                         + wtoken.isRelaunching() + " startingWindow="
    588                         + wtoken.startingWindow);
    589 
    590 
    591                 final boolean allDrawn = wtoken.allDrawn && !wtoken.isRelaunching();
    592                 if (!allDrawn && !wtoken.startingDisplayed && !wtoken.startingMoved) {
    593                     return false;
    594                 }
    595                 final int windowingMode = wtoken.getWindowingMode();
    596                 if (allDrawn) {
    597                     outReasons.put(windowingMode,  APP_TRANSITION_WINDOWS_DRAWN);
    598                 } else {
    599                     outReasons.put(windowingMode,
    600                             wtoken.startingData instanceof SplashScreenStartingData
    601                                     ? APP_TRANSITION_SPLASH_SCREEN
    602                                     : APP_TRANSITION_SNAPSHOT);
    603                 }
    604             }
    605 
    606             // We also need to wait for the specs to be fetched, if needed.
    607             if (mService.mAppTransition.isFetchingAppTransitionsSpecs()) {
    608                 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "isFetchingAppTransitionSpecs=true");
    609                 return false;
    610             }
    611 
    612             if (!mService.mUnknownAppVisibilityController.allResolved()) {
    613                 if (DEBUG_APP_TRANSITIONS) {
    614                     Slog.v(TAG, "unknownApps is not empty: "
    615                             + mService.mUnknownAppVisibilityController.getDebugMessage());
    616                 }
    617                 return false;
    618             }
    619 
    620             // If the wallpaper is visible, we need to check it's ready too.
    621             boolean wallpaperReady = !mWallpaperControllerLocked.isWallpaperVisible() ||
    622                     mWallpaperControllerLocked.wallpaperTransitionReady();
    623             if (wallpaperReady) {
    624                 return true;
    625             }
    626             return false;
    627         }
    628         return true;
    629     }
    630 
    631     private int maybeUpdateTransitToWallpaper(int transit, boolean openingAppHasWallpaper,
    632             boolean closingAppHasWallpaper) {
    633         // Given no app transition pass it through instead of a wallpaper transition.
    634         // Never convert the crashing transition.
    635         // Never update the transition for the wallpaper if we are just docking from recents
    636         if (transit == TRANSIT_NONE || transit == TRANSIT_CRASHING_ACTIVITY_CLOSE
    637                 || transit == TRANSIT_DOCK_TASK_FROM_RECENTS) {
    638             return transit;
    639         }
    640 
    641         // if wallpaper is animating in or out set oldWallpaper to null else to wallpaper
    642         final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget();
    643         final WindowState oldWallpaper = mWallpaperControllerLocked.isWallpaperTargetAnimating()
    644                 ? null : wallpaperTarget;
    645         final ArraySet<AppWindowToken> openingApps = mService.mOpeningApps;
    646         final ArraySet<AppWindowToken> closingApps = mService.mClosingApps;
    647         final AppWindowToken topOpeningApp = getTopApp(mService.mOpeningApps,
    648                 false /* ignoreHidden */);
    649         final AppWindowToken topClosingApp = getTopApp(mService.mClosingApps,
    650                 true /* ignoreHidden */);
    651 
    652         boolean openingCanBeWallpaperTarget = canBeWallpaperTarget(openingApps);
    653         if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
    654                 "New wallpaper target=" + wallpaperTarget
    655                         + ", oldWallpaper=" + oldWallpaper
    656                         + ", openingApps=" + openingApps
    657                         + ", closingApps=" + closingApps);
    658 
    659         if (openingCanBeWallpaperTarget && transit == TRANSIT_KEYGUARD_GOING_AWAY) {
    660             transit = TRANSIT_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
    661             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
    662                     "New transit: " + AppTransition.appTransitionToString(transit));
    663         }
    664         // We never want to change from a Keyguard transit to a non-Keyguard transit, as our logic
    665         // relies on the fact that we always execute a Keyguard transition after preparing one.
    666         else if (!isKeyguardGoingAwayTransit(transit)) {
    667             if (closingAppHasWallpaper && openingAppHasWallpaper) {
    668                 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Wallpaper animation!");
    669                 switch (transit) {
    670                     case TRANSIT_ACTIVITY_OPEN:
    671                     case TRANSIT_TASK_OPEN:
    672                     case TRANSIT_TASK_TO_FRONT:
    673                         transit = TRANSIT_WALLPAPER_INTRA_OPEN;
    674                         break;
    675                     case TRANSIT_ACTIVITY_CLOSE:
    676                     case TRANSIT_TASK_CLOSE:
    677                     case TRANSIT_TASK_TO_BACK:
    678                         transit = TRANSIT_WALLPAPER_INTRA_CLOSE;
    679                         break;
    680                 }
    681                 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
    682                         "New transit: " + AppTransition.appTransitionToString(transit));
    683             } else if (oldWallpaper != null && !mService.mOpeningApps.isEmpty()
    684                     && !openingApps.contains(oldWallpaper.mAppToken)
    685                     && closingApps.contains(oldWallpaper.mAppToken)
    686                     && topClosingApp == oldWallpaper.mAppToken) {
    687                 // We are transitioning from an activity with a wallpaper to one without.
    688                 transit = TRANSIT_WALLPAPER_CLOSE;
    689                 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit away from wallpaper: "
    690                         + AppTransition.appTransitionToString(transit));
    691             } else if (wallpaperTarget != null && wallpaperTarget.isVisibleLw()
    692                     && openingApps.contains(wallpaperTarget.mAppToken)
    693                     && topOpeningApp == wallpaperTarget.mAppToken
    694                     && transit != TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE) {
    695                 // We are transitioning from an activity without
    696                 // a wallpaper to now showing the wallpaper
    697                 transit = TRANSIT_WALLPAPER_OPEN;
    698                 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit into wallpaper: "
    699                         + AppTransition.appTransitionToString(transit));
    700             }
    701         }
    702         return transit;
    703     }
    704 
    705     /**
    706      * There are cases where we open/close a new task/activity, but in reality only a translucent
    707      * activity on top of existing activities is opening/closing. For that one, we have a different
    708      * animation because non of the task/activity animations actually work well with translucent
    709      * apps.
    710      *
    711      * @param transit The current transition type.
    712      * @return The current transition type or
    713      *         {@link WindowManager#TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE}/
    714      *         {@link WindowManager#TRANSIT_TRANSLUCENT_ACTIVITY_OPEN} if appropriate for the
    715      *         situation.
    716      */
    717     @VisibleForTesting
    718     int maybeUpdateTransitToTranslucentAnim(int transit) {
    719         final boolean taskOrActivity = AppTransition.isTaskTransit(transit)
    720                 || AppTransition.isActivityTransit(transit);
    721         boolean allOpeningVisible = true;
    722         boolean allTranslucentOpeningApps = !mService.mOpeningApps.isEmpty();
    723         for (int i = mService.mOpeningApps.size() - 1; i >= 0; i--) {
    724             final AppWindowToken token = mService.mOpeningApps.valueAt(i);
    725             if (!token.isVisible()) {
    726                 allOpeningVisible = false;
    727                 if (token.fillsParent()) {
    728                     allTranslucentOpeningApps = false;
    729                 }
    730             }
    731         }
    732         boolean allTranslucentClosingApps = !mService.mClosingApps.isEmpty();
    733         for (int i = mService.mClosingApps.size() - 1; i >= 0; i--) {
    734             if (mService.mClosingApps.valueAt(i).fillsParent()) {
    735                 allTranslucentClosingApps = false;
    736                 break;
    737             }
    738         }
    739 
    740         if (taskOrActivity && allTranslucentClosingApps && allOpeningVisible) {
    741             return TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE;
    742         }
    743         if (taskOrActivity && allTranslucentOpeningApps && mService.mClosingApps.isEmpty()) {
    744             return TRANSIT_TRANSLUCENT_ACTIVITY_OPEN;
    745         }
    746         return transit;
    747     }
    748 
    749     private boolean canBeWallpaperTarget(ArraySet<AppWindowToken> apps) {
    750         for (int i = apps.size() - 1; i >= 0; i--) {
    751             if (apps.valueAt(i).windowsCanBeWallpaperTarget()) {
    752                 return true;
    753             }
    754         }
    755         return false;
    756     }
    757 
    758     /**
    759      * Finds the top app in a list of apps, using its {@link AppWindowToken#getPrefixOrderIndex} to
    760      * compare z-order.
    761      *
    762      * @param apps The list of apps to search.
    763      * @param ignoreHidden If set to true, ignores apps that are {@link AppWindowToken#isHidden}.
    764      * @return The top {@link AppWindowToken}.
    765      */
    766     private AppWindowToken getTopApp(ArraySet<AppWindowToken> apps, boolean ignoreHidden) {
    767         int topPrefixOrderIndex = Integer.MIN_VALUE;
    768         AppWindowToken topApp = null;
    769         for (int i = apps.size() - 1; i >= 0; i--) {
    770             final AppWindowToken app = apps.valueAt(i);
    771             if (ignoreHidden && app.isHidden()) {
    772                 continue;
    773             }
    774             final int prefixOrderIndex = app.getPrefixOrderIndex();
    775             if (prefixOrderIndex > topPrefixOrderIndex) {
    776                 topPrefixOrderIndex = prefixOrderIndex;
    777                 topApp = app;
    778             }
    779         }
    780         return topApp;
    781     }
    782 
    783     private void processApplicationsAnimatingInPlace(int transit) {
    784         if (transit == TRANSIT_TASK_IN_PLACE) {
    785             // Find the focused window
    786             final WindowState win = mService.getDefaultDisplayContentLocked().findFocusedWindow();
    787             if (win != null) {
    788                 final AppWindowToken wtoken = win.mAppToken;
    789                 if (DEBUG_APP_TRANSITIONS)
    790                     Slog.v(TAG, "Now animating app in place " + wtoken);
    791                 wtoken.cancelAnimation();
    792                 wtoken.applyAnimationLocked(null, transit, false, false);
    793                 wtoken.updateReportedVisibilityLocked();
    794                 wtoken.showAllWindowsLocked();
    795             }
    796         }
    797     }
    798 
    799     void requestTraversal() {
    800         if (!mTraversalScheduled) {
    801             mTraversalScheduled = true;
    802             mService.mAnimationHandler.post(mPerformSurfacePlacement);
    803         }
    804     }
    805 
    806     public void dump(PrintWriter pw, String prefix) {
    807         pw.println(prefix + "mTraversalScheduled=" + mTraversalScheduled);
    808         pw.println(prefix + "mHoldScreenWindow=" + mService.mRoot.mHoldScreenWindow);
    809         pw.println(prefix + "mObscuringWindow=" + mService.mRoot.mObscuringWindow);
    810     }
    811 }
    812