Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c48a3547 authored by Wale Ogunwale's avatar Wale Ogunwale
Browse files

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
parent 31af215b
Loading
Loading
Loading
Loading
+6 −6
Original line number Diff line number Diff line
@@ -254,7 +254,7 @@ class AppWindowToken extends WindowToken {
                // 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 @@ class AppWindowToken extends WindowToken {
            // 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 @@ class AppWindowToken extends WindowToken {
                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();
+1 −1
Original line number Diff line number Diff line
@@ -420,7 +420,7 @@ public class TaskStack implements DimLayer.DimLayerUser,
                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;
                    }
                }
+55 −50
Original line number Diff line number Diff line
@@ -116,7 +116,7 @@ import android.view.WindowManagerPolicy.PointerEventListener;
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.WindowManager.LayoutParams.TYPE_WALLPAPER;
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 @@ public class WindowManagerService extends IWindowManager.Stub
                            + " 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 @@ public class WindowManagerService extends IWindowManager.Stub
        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 @@ public class WindowManagerService extends IWindowManager.Stub
            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 @@ public class WindowManagerService extends IWindowManager.Stub

        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 @@ public class WindowManagerService extends IWindowManager.Stub
                // 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 @@ public class WindowManagerService extends IWindowManager.Stub
                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 @@ public class WindowManagerService extends IWindowManager.Stub
                    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 @@ public class WindowManagerService extends IWindowManager.Stub
    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--) {
            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 @@ public class WindowManagerService extends IWindowManager.Stub
                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 @@ public class WindowManagerService extends IWindowManager.Stub
        }
        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 @@ public class WindowManagerService extends IWindowManager.Stub
    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;
+20 −20
Original line number Diff line number Diff line
@@ -358,7 +358,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
    boolean mLayoutNeeded;

    /** Currently running an exit animation? */
    boolean mExiting;
    boolean mAnimatingExit;

    /** Currently on the mDestroySurface list? */
    boolean mDestroying;
@@ -387,11 +387,11 @@ final class WindowState implements WindowManagerPolicy.WindowState {
    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 @@ final class WindowState implements WindowManagerPolicy.WindowState {
    @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 @@ final class WindowState implements WindowManagerPolicy.WindowState {
     */
    private boolean isVisibleUnchecked() {
        return mHasSurface && mPolicyVisibility && !mAttachedHidden
                && !mExiting && !mDestroying && (!mIsWallpaper || mWallpaperVisible);
                && !mAnimatingExit && !mDestroying && (!mIsWallpaper || mWallpaperVisible);
    }

    /**
@@ -1100,7 +1100,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
        }
        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 @@ final class WindowState implements WindowManagerPolicy.WindowState {
        return (mHasSurface || (!mRelayoutCalled && mViewVisibility == View.VISIBLE))
                && mPolicyVisibility && !mAttachedHidden
                && (atoken == null || !atoken.hiddenRequested)
                && !mExiting && !mDestroying;
                && !mAnimatingExit && !mDestroying;
    }

    /**
@@ -1237,7 +1237,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
                || (atoken == null && mRootToken.hidden)
                || (atoken != null && (atoken.hiddenRequested || atoken.hidden))
                || mAttachedHidden
                || (mExiting && !isAnimatingLw())
                || (mAnimatingExit && !isAnimatingLw())
                || mDestroying;
    }

@@ -1283,7 +1283,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
     */
    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 @@ final class WindowState implements WindowManagerPolicy.WindowState {
            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 @@ final class WindowState implements WindowManagerPolicy.WindowState {
                win.mAnimateReplacingWindow = false;
                win.mReplacingRemoveRequested = false;
                win.mReplacingWindow = null;
                if (win.mExiting) {
                if (win.mAnimatingExit) {
                    mService.removeWindowInnerLocked(win);
                }
            }
@@ -1810,7 +1810,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
    }

    boolean isClosing() {
        return mExiting || (mService.mClosingApps.contains(mAppToken));
        return mAnimatingExit || (mService.mClosingApps.contains(mAppToken));
    }

    boolean isAnimatingWithSavedSurface() {
@@ -2341,8 +2341,8 @@ final class WindowState implements WindowManagerPolicy.WindowState {
        }
        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 @@ final class WindowState implements WindowManagerPolicy.WindowState {
    @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;
    }
+10 −11
Original line number Diff line number Diff line
@@ -29,7 +29,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE
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 @@ class WindowStateAnimator {

        // 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 @@ class WindowStateAnimator {
    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 @@ class WindowStateAnimator {
            }
        }

        if (!mWin.mExiting) {
        if (!mWin.mAnimatingExit) {
            return;
        }

@@ -475,27 +474,27 @@ class WindowStateAnimator {

        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);
    }

Loading