Clean-up WindowState if exit animation is done before app finishes

In ag/862571 we prevent window states from been removed before the
app is stopped since it can still be rendering to the surface.
The CL also left WindowState.mExiting as true after the exit
transition animation runs. This is okay if the app finishes before
the exit animation is done, but if the exit animation finishes before
the app finishes, then we will always think we need to run an exit
animation and not remove the windows when the app and later activity
manager tries to remove the windows.
mExiting is used to mean exiting animation is running, if it is set to
true then all the code assumes an exit animation is still running and
doesn't remove the window state.
- Always set mExiting when animation is done.
- Renamed mExiting to mAnimatingExit so it is more clear what it is used
for
- Allow window state to be removed is the current surface isn't shown.
This should be save since there won't be any visual effect to the user.
- Rename WindowState.mClientRemoveRequested to WindowState.mWindowRemovalAllowed
and move setting it to true into WMS.removeWindow() so it catches all cases.
- Cleaned-up the code some to be a little clearer.

Bug: 27112965
Change-Id: I6f03d3c75b5b7728e42ceadc8703df40a3b4ae63
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 2a091ba..12c62bd 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -254,7 +254,7 @@
                 // In cases where there are multiple windows, we prefer the non-exiting window. This
                 // happens for example when replacing windows during an activity relaunch. When
                 // constructing the animation, we want the new window, not the exiting one.
-                if (win.mExiting) {
+                if (win.mAnimatingExit) {
                     candidate = win;
                 } else {
                     return win;
@@ -307,11 +307,11 @@
             // If the app already requested to remove its window, we don't modify
             // its exiting state. Otherwise the stale window won't get removed on
             // exit and could cause focus to be given to the wrong window.
-            if (!(win.mRemoveOnExit && win.mExiting)) {
-                win.mExiting = exiting;
+            if (!(win.mRemoveOnExit && win.mAnimatingExit)) {
+                win.mAnimatingExit = exiting;
             }
             // If we're no longer exiting, remove the window from destroying list
-            if (!win.mExiting && win.mDestroying) {
+            if (!win.mAnimatingExit && win.mDestroying) {
                 win.mDestroying = false;
                 service.mDestroySurface.remove(win);
             }
@@ -330,13 +330,13 @@
                 continue;
             }
 
-            if (!mAppStopped && !win.mClientRemoveRequested) {
+            if (!(mAppStopped || win.mWindowRemovalAllowed)) {
                 continue;
             }
 
             win.destroyOrSaveSurface();
             if (win.mRemoveOnExit) {
-                win.mExiting = false;
+                win.mAnimatingExit = false;
                 service.removeWindowInnerLocked(win);
             }
             final DisplayContent displayContent = win.getDisplayContent();
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 8409058..55c7450 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -420,7 +420,7 @@
                 final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows;
                 for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
                     final WindowStateAnimator winAnimator = windows.get(winNdx).mWinAnimator;
-                    if (winAnimator.isAnimating() || winAnimator.mWin.mExiting) {
+                    if (winAnimator.isAnimating() || winAnimator.mWin.mAnimatingExit) {
                         return true;
                     }
                 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index b661786..172340f 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -116,7 +116,7 @@
 import android.view.animation.Animation;
 import android.view.inputmethod.InputMethodManagerInternal;
 import android.widget.Toast;
-import com.android.internal.R;
+
 import com.android.internal.app.IAssistScreenshotReceiver;
 import com.android.internal.os.IResultReceiver;
 import com.android.internal.util.FastPrintWriter;
@@ -192,6 +192,8 @@
 import static android.view.WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY;
 import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static android.view.WindowManagerPolicy.TRANSIT_EXIT;
+import static android.view.WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
 import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_END;
 import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_START;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
@@ -1354,7 +1356,7 @@
                             + " policyVis=" + w.mPolicyVisibility
                             + " policyVisAfterAnim=" + w.mPolicyVisibilityAfterAnim
                             + " attachHid=" + w.mAttachedHidden
-                            + " exiting=" + w.mExiting + " destroying=" + w.mDestroying);
+                            + " exiting=" + w.mAnimatingExit + " destroying=" + w.mDestroying);
                     if (w.mAppToken != null) {
                         Slog.i(TAG_WM, "  mAppToken.hiddenRequested=" + w.mAppToken.hiddenRequested);
                     }
@@ -2057,7 +2059,7 @@
         WindowState replacedWindow = null;
         for (int i = atoken.windows.size() - 1; i >= 0 && replacedWindow == null; i--) {
             WindowState candidate = atoken.windows.get(i);
-            if (candidate.mExiting && candidate.mWillReplaceWindow
+            if (candidate.mAnimatingExit && candidate.mWillReplaceWindow
                     && candidate.mAnimateReplacingWindow) {
                 replacedWindow = candidate;
             }
@@ -2131,19 +2133,12 @@
             if (win == null) {
                 return;
             }
-            // We set this here instead of removeWindowLocked because we only want it to be
-            // true when the client has requested we remove the window. In other remove
-            // cases, we have to wait for activity stop to safely remove the window (as the
-            // client may still be using the surface). In this case though, the client has
-            // just dismissed a window (for example a Dialog) and activity stop isn't
-            // necessarily imminent, so we need to know not to wait for it after our
-            // hanimation (if applicable) finishes.
-            win.mClientRemoveRequested = true;
             removeWindowLocked(win);
         }
     }
 
     void removeWindowLocked(WindowState win) {
+        win.mWindowRemovalAllowed = true;
         final boolean startingWindow = win.mAttrs.type == TYPE_APPLICATION_STARTING;
         if (startingWindow) {
             if (DEBUG_STARTING_WINDOW) Slog.d(TAG_WM, "Starting window removed " + win);
@@ -2159,23 +2154,25 @@
 
         win.disposeInputChannel();
 
-        if (DEBUG_APP_TRANSITIONS) Slog.v(
-                TAG_WM, "Remove " + win + ": mSurfaceController=" + win.mWinAnimator.mSurfaceController
-                + " mExiting=" + win.mExiting
+        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM,
+                "Remove " + win + ": mSurfaceController=" + win.mWinAnimator.mSurfaceController
+                + " mAnimatingExit=" + win.mAnimatingExit
+                + " mRemoveOnExit=" + win.mRemoveOnExit
+                + " mHasSurface=" + win.mHasSurface
+                + " surfaceShowing=" + win.mWinAnimator.getShown()
                 + " isAnimating=" + win.mWinAnimator.isAnimating()
                 + " app-animation="
                 + (win.mAppToken != null ? win.mAppToken.mAppAnimator.animation : null)
-                + " mWillReplaceWindow="
-                + win.mWillReplaceWindow
+                + " mWillReplaceWindow=" + win.mWillReplaceWindow
                 + " inPendingTransaction="
                 + (win.mAppToken != null ? win.mAppToken.inPendingTransaction : false)
-                + " mDisplayFrozen=" + mDisplayFrozen);
+                + " mDisplayFrozen=" + mDisplayFrozen
+                + " callers=" + Debug.getCallers(6));
         // Visibility of the removed window. Will be used later to update orientation later on.
         boolean wasVisible = false;
-        // First, see if we need to run an animation.  If we do, we have
-        // to hold off on removing the window until the animation is done.
-        // If the display is frozen, just remove immediately, since the
-        // animation wouldn't be seen.
+        // First, see if we need to run an animation. If we do, we have to hold off on removing the
+        // window until the animation is done. If the display is frozen, just remove immediately,
+        // since the animation wouldn't be seen.
         if (win.mHasSurface && okToDisplay()) {
             final AppWindowToken appToken = win.mAppToken;
             if (win.mWillReplaceWindow) {
@@ -2183,13 +2180,16 @@
                 // gets added, then we will get rid of this one.
                 if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "Preserving " + win + " until the new one is "
                         + "added");
-                win.mExiting = true;
+                // TODO: We are overloading mAnimatingExit flag to prevent the window state from
+                // been removed. We probably need another falg to indicate that window removal
+                // should be deffered vs. overloading the flag that says we are playing an exit
+                // animation.
+                win.mAnimatingExit = true;
                 win.mReplacingRemoveRequested = true;
                 Binder.restoreCallingIdentity(origId);
                 return;
             }
-            // If we are not currently running the exit animation, we
-            // need to see about starting one.
+            // If we are not currently running the exit animation, we need to see about starting one
             wasVisible = win.isWinVisibleLw();
 
             if (win.shouldKeepVisibleDeadAppWindow()) {
@@ -2209,14 +2209,13 @@
                 return;
             }
 
+            final WindowStateAnimator winAnimator = win.mWinAnimator;
             if (wasVisible) {
-                final int transit = (!startingWindow)
-                        ? WindowManagerPolicy.TRANSIT_EXIT
-                        : WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
+                final int transit = (!startingWindow) ? TRANSIT_EXIT : TRANSIT_PREVIEW_DONE;
 
                 // Try starting an animation.
-                if (win.mWinAnimator.applyAnimationLocked(transit, false)) {
-                    win.mExiting = true;
+                if (winAnimator.applyAnimationLocked(transit, false)) {
+                    win.mAnimatingExit = true;
                 }
                 //TODO (multidisplay): Magnification is supported only for the default display.
                 if (mAccessibilityController != null
@@ -2224,15 +2223,20 @@
                     mAccessibilityController.onWindowTransitionLocked(win, transit);
                 }
             }
-            final boolean isAnimating = win.mWinAnimator.isAnimating()
-                    && !win.mWinAnimator.isDummyAnimation();
-            // The starting window is the last window in this app token and it isn't animating.
-            // Allow it to be removed now as there is no additional window or animation that will
-            // trigger its removal.
-            final boolean lastWinStartingNotAnimating = startingWindow && appToken!= null
-                    && appToken.allAppWindows.size() == 1 && !isAnimating;
-            if (!lastWinStartingNotAnimating && win.mExiting) {
-                // The exit animation is running... wait for it!
+            final boolean isAnimating =
+                    winAnimator.isAnimating() && !winAnimator.isDummyAnimation();
+            final boolean lastWindowIsStartingWindow = startingWindow && appToken != null
+                    && appToken.allAppWindows.size() == 1;
+            // We delay the removal of a window if it has a showing surface that can be used to run
+            // exit animation and it is marked as exiting.
+            // Also, If isn't the an animating starting window that is the last window in the app.
+            // We allow the removal of the non-animating starting window now as there is no
+            // additional window or animation that will trigger its removal.
+            if (winAnimator.getShown() && win.mAnimatingExit
+                    && (!lastWindowIsStartingWindow || isAnimating)) {
+                // The exit animation is running or should run... wait for it!
+                if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
+                        "Not removing " + win + " due to exit animation ");
                 win.mRemoveOnExit = true;
                 win.setDisplayLayoutNeeded();
                 final boolean focusChanged = updateFocusedWindowLocked(
@@ -2262,13 +2266,14 @@
     void removeWindowInnerLocked(WindowState win) {
         if (win.mRemoved) {
             // Nothing to do.
+            if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
+                    "removeWindowInnerLocked: " + win + " Already removed...");
             return;
         }
 
-        for (int i=win.mChildWindows.size()-1; i>=0; i--) {
+        for (int i = win.mChildWindows.size() - 1; i >= 0; i--) {
             WindowState cwin = win.mChildWindows.get(i);
-            Slog.w(TAG_WM, "Force-removing child win " + cwin + " from container "
-                    + win);
+            Slog.w(TAG_WM, "Force-removing child win " + cwin + " from container " + win);
             removeWindowInnerLocked(cwin);
         }
 
@@ -2681,16 +2686,16 @@
                 final boolean usingSavedSurfaceBeforeVisible =
                         oldVisibility != View.VISIBLE && win.isAnimatingWithSavedSurface();
                 if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
-                    if (winAnimator.hasSurface() && !win.mExiting
+                    if (winAnimator.hasSurface() && !win.mAnimatingExit
                             && usingSavedSurfaceBeforeVisible) {
                         Slog.d(TAG, "Ignoring layout to invisible when using saved surface " + win);
                     }
                 }
 
-                if (winAnimator.hasSurface() && !win.mExiting
+                if (winAnimator.hasSurface() && !win.mAnimatingExit
                         && !usingSavedSurfaceBeforeVisible) {
                     if (DEBUG_VISIBILITY) Slog.i(TAG_WM, "Relayout invis " + win
-                            + ": mExiting=" + win.mExiting);
+                            + ": mAnimatingExit=" + win.mAnimatingExit);
                     // If we are not currently running the exit animation, we
                     // need to see about starting one.
                     // We don't want to animate visibility of windows which are pending
@@ -2797,16 +2802,16 @@
         }
         if (win.isWinVisibleLw() && winAnimator.applyAnimationLocked(transit, false)) {
             focusMayChange = isDefaultDisplay;
-            win.mExiting = true;
+            win.mAnimatingExit = true;
         } else if (win.mWinAnimator.isAnimating()) {
             // Currently in a hide animation... turn this into
             // an exit.
-            win.mExiting = true;
+            win.mAnimatingExit = true;
         } else if (mWallpaperControllerLocked.isWallpaperTarget(win)) {
             // If the wallpaper is currently behind this
             // window, we need to change both of them inside
             // of a transaction to avoid artifacts.
-            win.mExiting = true;
+            win.mAnimatingExit = true;
             win.mWinAnimator.mAnimating = true;
         } else {
             if (mInputMethodWindow == win) {
@@ -2842,12 +2847,12 @@
     private int relayoutVisibleWindow(Configuration outConfig, int result, WindowState win,
             WindowStateAnimator winAnimator, int attrChanges, int oldVisibility) {
         result |= !win.isVisibleLw() ? WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME : 0;
-        if (win.mExiting) {
-            Slog.d(TAG, "relayoutVisibleWindow: " + win + " mExiting=true, mRemoveOnExit="
+        if (win.mAnimatingExit) {
+            Slog.d(TAG, "relayoutVisibleWindow: " + win + " mAnimatingExit=true, mRemoveOnExit="
                     + win.mRemoveOnExit + ", mDestroying=" + win.mDestroying);
 
             winAnimator.cancelExitAnimationForNextAnimationLocked();
-            win.mExiting = false;
+            win.mAnimatingExit = false;
         }
         if (win.mDestroying) {
             win.mDestroying = false;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 0958ad2..f30c8d3 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -358,7 +358,7 @@
     boolean mLayoutNeeded;
 
     /** Currently running an exit animation? */
-    boolean mExiting;
+    boolean mAnimatingExit;
 
     /** Currently on the mDestroySurface list? */
     boolean mDestroying;
@@ -387,11 +387,11 @@
     boolean mRemoved;
 
     /**
-     * Has the client requested we remove the window? In this case we know
-     * that we can dispose of it when we wish without further synchronization
-     * with the client
+     * It is save to remove the window and destroy the surface because the client requested removal
+     * or some other higher level component said so (e.g. activity manager).
+     * TODO: We should either have different booleans for the removal reason or use a bit-field.
      */
-    boolean mClientRemoveRequested;
+    boolean mWindowRemovalAllowed;
 
     /**
      * Temp for keeping track of windows that have been removed when
@@ -614,7 +614,7 @@
     @Override
     public void computeFrameLw(Rect pf, Rect df, Rect of, Rect cf, Rect vf, Rect dcf, Rect sf,
             Rect osf) {
-        if (mWillReplaceWindow && (mExiting || !mReplacingRemoveRequested)) {
+        if (mWillReplaceWindow && (mAnimatingExit || !mReplacingRemoveRequested)) {
             // This window is being replaced and either already got information that it's being
             // removed or we are still waiting for some information. Because of this we don't
             // want to apply any more changes to it, so it remains in this state until new window
@@ -1075,7 +1075,7 @@
      */
     private boolean isVisibleUnchecked() {
         return mHasSurface && mPolicyVisibility && !mAttachedHidden
-                && !mExiting && !mDestroying && (!mIsWallpaper || mWallpaperVisible);
+                && !mAnimatingExit && !mDestroying && (!mIsWallpaper || mWallpaperVisible);
     }
 
     /**
@@ -1100,7 +1100,7 @@
         }
         final AppWindowToken atoken = mAppToken;
         final boolean animating = atoken != null && atoken.mAppAnimator.animation != null;
-        return mHasSurface && !mDestroying && !mExiting
+        return mHasSurface && !mDestroying && !mAnimatingExit
                 && (atoken == null ? mPolicyVisibility : !atoken.hiddenRequested)
                 && ((!mAttachedHidden && mViewVisibility == View.VISIBLE && !mRootToken.hidden)
                         || mWinAnimator.mAnimation != null || animating);
@@ -1143,7 +1143,7 @@
         return (mHasSurface || (!mRelayoutCalled && mViewVisibility == View.VISIBLE))
                 && mPolicyVisibility && !mAttachedHidden
                 && (atoken == null || !atoken.hiddenRequested)
-                && !mExiting && !mDestroying;
+                && !mAnimatingExit && !mDestroying;
     }
 
     /**
@@ -1237,7 +1237,7 @@
                 || (atoken == null && mRootToken.hidden)
                 || (atoken != null && (atoken.hiddenRequested || atoken.hidden))
                 || mAttachedHidden
-                || (mExiting && !isAnimatingLw())
+                || (mAnimatingExit && !isAnimatingLw())
                 || mDestroying;
     }
 
@@ -1283,7 +1283,7 @@
      */
     boolean hasMoved() {
         return mHasSurface && (mContentChanged || mMovedByResize)
-                && !mExiting && !mWinAnimator.mLastHidden && mService.okToDisplay()
+                && !mAnimatingExit && !mWinAnimator.mLastHidden && mService.okToDisplay()
                 && (mFrame.top != mLastFrame.top || mFrame.left != mLastFrame.left)
                 && (mAttachedWindow == null || !mAttachedWindow.hasMoved());
     }
@@ -1438,11 +1438,11 @@
             return;
         }
 
-        if (!mExiting && mAppDied) {
+        if (!mAnimatingExit && mAppDied) {
             // If app died visible, apply a dim over the window to indicate that it's inactive
             mDisplayContent.mDimLayerController.applyDimAbove(getDimLayerUser(), mWinAnimator);
         } else if ((mAttrs.flags & FLAG_DIM_BEHIND) != 0
-                && mDisplayContent != null && !mExiting && isDisplayedLw()) {
+                && mDisplayContent != null && !mAnimatingExit && isDisplayedLw()) {
             mDisplayContent.mDimLayerController.applyDimBehind(getDimLayerUser(), mWinAnimator);
         }
     }
@@ -1467,7 +1467,7 @@
                 win.mAnimateReplacingWindow = false;
                 win.mReplacingRemoveRequested = false;
                 win.mReplacingWindow = null;
-                if (win.mExiting) {
+                if (win.mAnimatingExit) {
                     mService.removeWindowInnerLocked(win);
                 }
             }
@@ -1810,7 +1810,7 @@
     }
 
     boolean isClosing() {
-        return mExiting || (mService.mClosingApps.contains(mAppToken));
+        return mAnimatingExit || (mService.mClosingApps.contains(mAppToken));
     }
 
     boolean isAnimatingWithSavedSurface() {
@@ -2341,8 +2341,8 @@
         }
         pw.print(prefix); pw.print(mWinAnimator); pw.println(":");
         mWinAnimator.dump(pw, prefix + "  ", dumpAll);
-        if (mExiting || mRemoveOnExit || mDestroying || mRemoved) {
-            pw.print(prefix); pw.print("mExiting="); pw.print(mExiting);
+        if (mAnimatingExit || mRemoveOnExit || mDestroying || mRemoved) {
+            pw.print(prefix); pw.print("mAnimatingExit="); pw.print(mAnimatingExit);
                     pw.print(" mRemoveOnExit="); pw.print(mRemoveOnExit);
                     pw.print(" mDestroying="); pw.print(mDestroying);
                     pw.print(" mRemoved="); pw.println(mRemoved);
@@ -2403,12 +2403,12 @@
     @Override
     public String toString() {
         final CharSequence title = getWindowTag();
-        if (mStringNameCache == null || mLastTitle != title || mWasExiting != mExiting) {
+        if (mStringNameCache == null || mLastTitle != title || mWasExiting != mAnimatingExit) {
             mLastTitle = title;
-            mWasExiting = mExiting;
+            mWasExiting = mAnimatingExit;
             mStringNameCache = "Window{" + Integer.toHexString(System.identityHashCode(this))
                     + " u" + UserHandle.getUserId(mSession.mUid)
-                    + " " + mLastTitle + (mExiting ? " EXITING}" : "}");
+                    + " " + mLastTitle + (mAnimatingExit ? " EXITING}" : "}");
         }
         return mStringNameCache;
     }
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 84a2c09..0828417 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -29,7 +29,6 @@
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_CROP;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_STACK_CRAWLS;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC;
 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
@@ -375,7 +374,7 @@
 
         // Done animating, clean up.
         if (DEBUG_ANIM) Slog.v(
-            TAG, "Animation done in " + this + ": exiting=" + mWin.mExiting
+            TAG, "Animation done in " + this + ": exiting=" + mWin.mAnimatingExit
             + ", reportedVisible="
             + (mWin.mAppToken != null ? mWin.mAppToken.reportedVisible : false));
 
@@ -430,7 +429,7 @@
     void finishExit() {
         if (DEBUG_ANIM) Slog.v(
                 TAG, "finishExit in " + this
-                + ": exiting=" + mWin.mExiting
+                + ": exiting=" + mWin.mAnimatingExit
                 + " remove=" + mWin.mRemoveOnExit
                 + " windowAnimating=" + isWindowAnimating());
 
@@ -460,7 +459,7 @@
             }
         }
 
-        if (!mWin.mExiting) {
+        if (!mWin.mAnimatingExit) {
             return;
         }
 
@@ -475,27 +474,27 @@
 
         mWin.mDestroying = true;
 
+        final boolean hasSurface = hasSurface();
+        if (hasSurface) {
+            hide("finishExit");
+        }
+
         // If we have an app token, we ask it to destroy the surface for us,
         // so that it can take care to ensure the activity has actually stopped
         // and the surface is not still in use. Otherwise we add the service to
         // mDestroySurface and allow it to be processed in our next transaction.
         if (mWin.mAppToken != null) {
-            if (hasSurface()) {
-                hide("finishExit");
-            }
             mWin.mAppToken.destroySurfaces();
         } else {
-            if (hasSurface()) {
+            if (hasSurface) {
                 mService.mDestroySurface.add(mWin);
-                hide("finishExit");
             }
-            mWin.mExiting = false;
             if (mWin.mRemoveOnExit) {
                 mService.mPendingRemove.add(mWin);
                 mWin.mRemoveOnExit = false;
             }
         }
-
+        mWin.mAnimatingExit = false;
         mWallpaperControllerLocked.hideWallpapers(mWin);
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 4e1b644..e760f40 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -7,7 +7,6 @@
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
 import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
@@ -751,7 +750,7 @@
                     }
                     if ((w.isOnScreenIgnoringKeyguard()
                             || winAnimator.mAttrType == TYPE_BASE_APPLICATION)
-                            && !w.mExiting && !w.mDestroying) {
+                            && !w.mAnimatingExit && !w.mDestroying) {
                         if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
                             Slog.v(TAG, "Eval win " + w + ": isDrawn="
                                     + w.isDrawnLw()
@@ -1181,17 +1180,17 @@
                 int layer = -1;
                 for (int j = 0; j < wtoken.windows.size(); j++) {
                     final WindowState win = wtoken.windows.get(j);
-                    // Clearing the mExiting flag before entering animation. It will be set to true
+                    // Clearing the mAnimatingExit flag before entering animation. It will be set to true
                     // if app window is removed, or window relayout to invisible. We don't want to
                     // clear it out for windows that get replaced, because the animation depends on
                     // the flag to remove the replaced window.
                     //
-                    // We also don't clear the mExiting flag for windows which have the
+                    // We also don't clear the mAnimatingExit flag for windows which have the
                     // mRemoveOnExit flag. This indicates an explicit remove request has been issued
                     // by the client. We should let animation proceed and not clear this flag or
                     // they won't eventually be removed by WindowStateAnimator#finishExit.
                     if (!win.mWillReplaceWindow && !win.mRemoveOnExit) {
-                        win.mExiting = false;
+                        win.mAnimatingExit = false;
                     }
                     if (win.mWinAnimator.mAnimLayer > layer) {
                         layer = win.mWinAnimator.mAnimLayer;
@@ -1230,7 +1229,7 @@
             wtoken.deferClearAllDrawn = false;
             // Ensure that apps that are mid-starting are also scheduled to have their
             // starting windows removed after the animation is complete
-            if (wtoken.startingWindow != null && !wtoken.startingWindow.mExiting) {
+            if (wtoken.startingWindow != null && !wtoken.startingWindow.mAnimatingExit) {
                 mService.scheduleRemoveStartingWindowLocked(wtoken);
             }
             mService.mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();