Refactor animation out of WindowState.

Remove the animation stepping from WindowState and move it into a new
class, WindowStateAnimator. Update all references to moved variables
in related files.

Change-Id: I7540d8f897b370c73975f3ffe450140861cb0cd1
diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/java/com/android/server/wm/AppWindowToken.java
index 1442883..6269420 100644
--- a/services/java/com/android/server/wm/AppWindowToken.java
+++ b/services/java/com/android/server/wm/AppWindowToken.java
@@ -51,7 +51,7 @@
     int groupId = -1;
     boolean appFullscreen;
     int requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-    
+
     // The input dispatching timeout for this application token in nanoseconds.
     long inputDispatchingTimeoutNanos;
 
@@ -225,7 +225,7 @@
             if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG,
                     "performing show on: " + w);
             w.performShowLocked();
-            isAnimating |= w.isAnimating();
+            isAnimating |= w.mWinAnimator.isAnimating();
         }
         return isAnimating;
     }
@@ -243,11 +243,11 @@
         // cache often used attributes locally
         final float tmpFloats[] = service.mTmpFloats;
         thumbnailTransformation.getMatrix().getValues(tmpFloats);
-        if (WindowManagerService.SHOW_TRANSACTIONS) service.logSurface(thumbnail,
+        if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(thumbnail,
                 "thumbnail", "POS " + tmpFloats[Matrix.MTRANS_X]
                 + ", " + tmpFloats[Matrix.MTRANS_Y], null);
         thumbnail.setPosition(tmpFloats[Matrix.MTRANS_X], tmpFloats[Matrix.MTRANS_Y]);
-        if (WindowManagerService.SHOW_TRANSACTIONS) service.logSurface(thumbnail,
+        if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(thumbnail,
                 "thumbnail", "alpha=" + thumbnailTransformation.getAlpha()
                 + " layer=" + thumbnailLayer
                 + " matrix=[" + tmpFloats[Matrix.MSCALE_X]
@@ -358,7 +358,7 @@
 
         final int N = windows.size();
         for (int i=0; i<N; i++) {
-            windows.get(i).finishExit();
+            windows.get(i).mWinAnimator.finishExit();
         }
         updateReportedVisibilityLocked();
 
@@ -388,7 +388,7 @@
             if (WindowManagerService.DEBUG_VISIBILITY) {
                 Slog.v(WindowManagerService.TAG, "Win " + win + ": isDrawn="
                         + win.isDrawnLw()
-                        + ", isAnimating=" + win.isAnimating());
+                        + ", isAnimating=" + win.mWinAnimator.isAnimating());
                 if (!win.isDrawnLw()) {
                     Slog.v(WindowManagerService.TAG, "Not displayed: s=" + win.mSurface
                             + " pv=" + win.mPolicyVisibility
@@ -398,17 +398,17 @@
                             + " th="
                             + (win.mAppToken != null
                                     ? win.mAppToken.hiddenRequested : false)
-                            + " a=" + win.mAnimating);
+                            + " a=" + win.mWinAnimator.mAnimating);
                 }
             }
             numInteresting++;
             if (win.isDrawnLw()) {
                 numDrawn++;
-                if (!win.isAnimating()) {
+                if (!win.mWinAnimator.isAnimating()) {
                     numVisible++;
                 }
                 nowGone = false;
-            } else if (win.isAnimating()) {
+            } else if (win.mWinAnimator.isAnimating()) {
                 nowGone = false;
             }
         }
diff --git a/services/java/com/android/server/wm/DimAnimator.java b/services/java/com/android/server/wm/DimAnimator.java
index 85495ea..d8f2254 100644
--- a/services/java/com/android/server/wm/DimAnimator.java
+++ b/services/java/com/android/server/wm/DimAnimator.java
@@ -82,7 +82,7 @@
 
     /**
      * Set's the dim surface's layer and update dim parameters that will be used in
-     * {@link updateSurface} after all windows are examined.
+     * {@link #updateSurface} after all windows are examined.
      */
     void updateParameters(Resources res, WindowState w, long currentTime) {
         mDimSurface.setLayer(w.mAnimLayer - WindowManagerService.LAYER_OFFSET_DIM);
@@ -94,15 +94,15 @@
             // If the desired dim level has changed, then
             // start an animation to it.
             mLastDimAnimTime = currentTime;
-            long duration = (w.mAnimating && w.mAnimation != null)
-                    ? w.mAnimation.computeDurationHint()
+            long duration = (w.mWinAnimator.mAnimating && w.mWinAnimator.mAnimation != null)
+                    ? w.mWinAnimator.mAnimation.computeDurationHint()
                     : WindowManagerService.DEFAULT_DIM_DURATION;
             if (target > mDimTargetAlpha) {
                 TypedValue tv = new TypedValue();
                 res.getValue(com.android.internal.R.fraction.config_dimBehindFadeDuration,
                         tv, true);
                 if (tv.type == TypedValue.TYPE_FRACTION) {
-                    duration = (long)tv.getFraction((float)duration, (float)duration);
+                    duration = (long)tv.getFraction(duration, duration);
                 } else if (tv.type >= TypedValue.TYPE_FIRST_INT
                         && tv.type <= TypedValue.TYPE_LAST_INT) {
                     duration = tv.data;
diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java
index fbfd9ec..81e0a17 100644
--- a/services/java/com/android/server/wm/WindowAnimator.java
+++ b/services/java/com/android/server/wm/WindowAnimator.java
@@ -79,7 +79,7 @@
                 }
             }
         }
-        
+
         final int NEAT = mService.mExitingAppTokens.size();
         for (i=0; i<NEAT; i++) {
             final AppWindowToken appToken = mService.mExitingAppTokens.get(i);
@@ -115,6 +115,7 @@
 
         for (int i = mService.mWindows.size() - 1; i >= 0; i--) {
             WindowState w = mService.mWindows.get(i);
+            WindowStateAnimator winAnimator = w.mWinAnimator;
 
             final WindowManager.LayoutParams attrs = w.mAttrs;
 
@@ -143,7 +144,7 @@
                     // let's do something.
                     Animation a = AnimationUtils.loadAnimation(mContext,
                             com.android.internal.R.anim.window_move_from_decor);
-                    w.setAnimation(a);
+                    winAnimator.setAnimation(a);
                     w.mAnimDw = w.mLastFrame.left - w.mFrame.left;
                     w.mAnimDh = w.mLastFrame.top - w.mFrame.top;
                 } else {
@@ -151,8 +152,8 @@
                     w.mAnimDh = mInnerDh;
                 }
 
-                final boolean wasAnimating = w.mWasAnimating;
-                final boolean nowAnimating = w.stepAnimationLocked(mCurrentTime);
+                final boolean wasAnimating = winAnimator.mWasAnimating;
+                final boolean nowAnimating = winAnimator.stepAnimationLocked(mCurrentTime);
 
                 if (WindowManagerService.DEBUG_WALLPAPER) {
                     Slog.v(TAG, w + ": wasAnimating=" + wasAnimating +
@@ -163,17 +164,17 @@
                 // an animating window and take care of a request to run
                 // a detached wallpaper animation.
                 if (nowAnimating) {
-                    if (w.mAnimation != null) {
+                    if (winAnimator.mAnimation != null) {
                         if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0
-                                && w.mAnimation.getDetachWallpaper()) {
+                                && winAnimator.mAnimation.getDetachWallpaper()) {
                             mService.mInnerFields.mDetachedWallpaper = w;
                         }
-                        if (w.mAnimation.getBackgroundColor() != 0) {
+                        if (winAnimator.mAnimation.getBackgroundColor() != 0) {
                             if (mWindowAnimationBackground == null
                                     || (w.mAnimLayer < mWindowAnimationBackground.mAnimLayer)) {
                                 mWindowAnimationBackground = w;
                                 mWindowAnimationBackgroundColor =
-                                        w.mAnimation.getBackgroundColor();
+                                        winAnimator.mAnimation.getBackgroundColor();
                             }
                         }
                     }
@@ -200,7 +201,7 @@
                     }
                 }
 
-                if (wasAnimating && !w.mAnimating && mService.mWallpaperTarget == w) {
+                if (wasAnimating && !winAnimator.mAnimating && mService.mWallpaperTarget == w) {
                     mService.mInnerFields.mWallpaperMayChange = true;
                     mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
                     if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
@@ -219,7 +220,7 @@
                             mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 3");
                         }
                         mService.mFocusMayChange = true;
-                    } else if (w.isReadyForDisplay() && w.mAnimation == null) {
+                    } else if (w.isReadyForDisplay() && winAnimator.mAnimation == null) {
                         mForceHiding = true;
                     }
                 } else if (mPolicy.canBeForceHidden(w, attrs)) {
@@ -241,7 +242,7 @@
                                 // clean up later.
                                 Animation a = mPolicy.createForceHideEnterAnimation();
                                 if (a != null) {
-                                    w.setAnimation(a);
+                                    winAnimator.setAnimation(a);
                                 }
                             }
                             if (mCurrentFocus == null || mCurrentFocus.mLayer < w.mLayer) {
@@ -277,7 +278,7 @@
                             WindowManagerService.DEBUG_ORIENTATION) {
                         Slog.v(TAG, "Eval win " + w + ": isDrawn="
                                 + w.isDrawnLw()
-                                + ", isAnimating=" + w.isAnimating());
+                                + ", isAnimating=" + winAnimator.isAnimating());
                         if (!w.isDrawnLw()) {
                             Slog.v(TAG, "Not displayed: s=" + w.mSurface
                                     + " pv=" + w.mPolicyVisibility
@@ -285,7 +286,7 @@
                                     + " cdp=" + w.mCommitDrawPending
                                     + " ah=" + w.mAttachedHidden
                                     + " th=" + atoken.hiddenRequested
-                                    + " a=" + w.mAnimating);
+                                    + " a=" + winAnimator.mAnimating);
                         }
                     }
                     if (w != atoken.startingWindow) {
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 3ecbf77..221bbcc 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -1237,7 +1237,7 @@
                 if (highestTarget != null) {
                     if (DEBUG_INPUT_METHOD) Slog.v(TAG, "mNextAppTransition="
                             + mNextAppTransition + " " + highestTarget
-                            + " animating=" + highestTarget.isAnimating()
+                            + " animating=" + highestTarget.mWinAnimator.isAnimating()
                             + " layer=" + highestTarget.mAnimLayer
                             + " new layer=" + w.mAnimLayer);
 
@@ -1247,7 +1247,7 @@
                         mInputMethodTargetWaitingAnim = true;
                         mInputMethodTarget = highestTarget;
                         return highestPos + 1;
-                    } else if (highestTarget.isAnimating() &&
+                    } else if (highestTarget.mWinAnimator.isAnimating() &&
                             highestTarget.mAnimLayer > w.mAnimLayer) {
                         // If the window we are currently targeting is involved
                         // with an animation, and it is on top of the next target
@@ -1600,7 +1600,7 @@
                 foundI = i;
                 if (w == mWallpaperTarget && ((w.mAppToken != null
                         && w.mAppToken.animation != null)
-                        || w.mAnimation != null)) {
+                        || w.mWinAnimator.mAnimation != null)) {
                     // The current wallpaper target is animating, so we'll
                     // look behind it for another possible target and figure
                     // out what is going on below.
@@ -1657,9 +1657,9 @@
             // Now what is happening...  if the current and new targets are
             // animating, then we are in our super special mode!
             if (foundW != null && oldW != null) {
-                boolean oldAnim = oldW.mAnimation != null
+                boolean oldAnim = oldW.mWinAnimator.mAnimation != null
                         || (oldW.mAppToken != null && oldW.mAppToken.animation != null);
-                boolean foundAnim = foundW.mAnimation != null
+                boolean foundAnim = foundW.mWinAnimator.mAnimation != null
                         || (foundW.mAppToken != null && foundW.mAppToken.animation != null);
                 if (DEBUG_WALLPAPER) {
                     Slog.v(TAG, "New animation: " + foundAnim
@@ -1711,10 +1711,10 @@
 
         } else if (mLowerWallpaperTarget != null) {
             // Is it time to stop animating?
-            boolean lowerAnimating = mLowerWallpaperTarget.mAnimation != null
+            boolean lowerAnimating = mLowerWallpaperTarget.mWinAnimator.mAnimation != null
                     || (mLowerWallpaperTarget.mAppToken != null
                             && mLowerWallpaperTarget.mAppToken.animation != null);
-            boolean upperAnimating = mUpperWallpaperTarget.mAnimation != null
+            boolean upperAnimating = mUpperWallpaperTarget.mWinAnimator.mAnimation != null
                     || (mUpperWallpaperTarget.mAppToken != null
                             && mUpperWallpaperTarget.mAppToken.animation != null);
             if (!lowerAnimating || !upperAnimating) {
@@ -2302,7 +2302,7 @@
         if (DEBUG_APP_TRANSITIONS) Slog.v(
                 TAG, "Remove " + win + ": mSurface=" + win.mSurface
                 + " mExiting=" + win.mExiting
-                + " isAnimating=" + win.isAnimating()
+                + " isAnimating=" + win.mWinAnimator.isAnimating()
                 + " app-animation="
                 + (win.mAppToken != null ? win.mAppToken.animation : null)
                 + " inPendingTransaction="
@@ -2329,7 +2329,7 @@
                     win.mExiting = true;
                 }
             }
-            if (win.mExiting || win.isAnimating()) {
+            if (win.mExiting || win.mWinAnimator.isAnimating()) {
                 // The exit animation is running... wait for it!
                 //Slog.i(TAG, "*** Running exit animation...");
                 win.mExiting = true;
@@ -2698,7 +2698,7 @@
                     (win.mAppToken == null || !win.mAppToken.clientHidden)) {
                 displayed = !win.isVisibleLw();
                 if (win.mExiting) {
-                    win.cancelExitAnimationForNextAnimationLocked();
+                    win.mWinAnimator.cancelExitAnimationForNextAnimationLocked();
                 }
                 if (win.mDestroying) {
                     win.mDestroying = false;
@@ -2802,7 +2802,7 @@
                               applyAnimationLocked(win, transit, false)) {
                             focusMayChange = true;
                             win.mExiting = true;
-                        } else if (win.isAnimating()) {
+                        } else if (win.mWinAnimator.isAnimating()) {
                             // Currently in a hide animation... turn this into
                             // an exit.
                             win.mExiting = true;
@@ -2811,7 +2811,7 @@
                             // window, we need to change both of them inside
                             // of a transaction to avoid artifacts.
                             win.mExiting = true;
-                            win.mAnimating = true;
+                            win.mWinAnimator.mAnimating = true;
                         } else {
                             if (mInputMethodWindow == win) {
                                 mInputMethodWindow = null;
@@ -3025,7 +3025,8 @@
      */
     boolean applyAnimationLocked(WindowState win,
             int transit, boolean isEntrance) {
-        if (win.mLocalAnimating && win.mAnimationIsEntrance == isEntrance) {
+        if (win.mWinAnimator.mLocalAnimating &&
+                win.mWinAnimator.mAnimationIsEntrance == isEntrance) {
             // If we are trying to apply an animation, but already running
             // an animation of the same type, then just leave that one alone.
             return true;
@@ -3062,7 +3063,7 @@
             }
             if (DEBUG_ANIM) Slog.v(TAG, "applyAnimation: win=" + win
                     + " anim=" + anim + " attr=0x" + Integer.toHexString(attr)
-                    + " mAnimation=" + win.mAnimation
+                    + " mAnimation=" + win.mWinAnimator.mAnimation
                     + " isEntrance=" + isEntrance);
             if (a != null) {
                 if (DEBUG_ANIM) {
@@ -3073,14 +3074,14 @@
                     }
                     Slog.v(TAG, "Loaded animation " + a + " for " + win, e);
                 }
-                win.setAnimation(a);
-                win.mAnimationIsEntrance = isEntrance;
+                win.mWinAnimator.setAnimation(a);
+                win.mWinAnimator.mAnimationIsEntrance = isEntrance;
             }
         } else {
-            win.clearAnimation();
+            win.mWinAnimator.clearAnimation();
         }
 
-        return win.mAnimation != null;
+        return win.mWinAnimator.mAnimation != null;
     }
 
     private Animation loadAnimation(WindowManager.LayoutParams lp, int animAttr) {
@@ -3369,7 +3370,7 @@
                     for (int i=0; i<N; i++) {
                         WindowState win = wtoken.windows.get(i);
 
-                        if (win.isAnimating()) {
+                        if (win.mWinAnimator.isAnimating()) {
                             delayed = true;
                         }
 
@@ -4062,7 +4063,7 @@
                     continue;
                 }
 
-                if (win.isAnimating()) {
+                if (win.mWinAnimator.isAnimating()) {
                     delayed = true;
                 }
 
@@ -8098,11 +8099,11 @@
                         if (DEBUG_FOCUS) Slog.i(TAG, "win=" + w + " force hides other windows");
                         mAnimator.mForceHiding = true;
                     } else if (mPolicy.canBeForceHidden(w, attrs)) {
-                        if (!w.mAnimating) {
+                        if (!w.mWinAnimator.mAnimating) {
                             // We set the animation above so it
                             // is not yet running.
                             // TODO(cmautner): We lose the enter animation when this occurs.
-                            w.clearAnimation();
+                            w.mWinAnimator.clearAnimation();
                         }
                     }
                 }
@@ -9769,7 +9770,7 @@
     public interface OnHardKeyboardStatusChangeListener {
         public void onHardKeyboardStatusChange(boolean available, boolean enabled);
     }
-    
+
     void debugLayoutRepeats(final String msg) {
         if (mLayoutRepeatCount >= LAYOUT_REPEAT_THRESHOLD) {
             Slog.v(TAG, "Layouts looping: " + msg);
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index 1146189..615cd80 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -45,7 +45,6 @@
 import android.view.WindowManager;
 import android.view.WindowManagerPolicy;
 import android.view.WindowManager.LayoutParams;
-import android.view.animation.Animation;
 import android.view.animation.Transformation;
 
 import java.io.PrintWriter;
@@ -91,7 +90,6 @@
     boolean mAttachedHidden;    // is our parent window hidden?
     boolean mLastHidden;        // was this window last hidden?
     boolean mWallpaperVisible;  // for wallpaper, what was last vis report?
-    boolean mWasAnimating;      // Were we animating going into the most recent animation step?
 
     /**
      * The window size that was requested by the application.  These are in
@@ -110,9 +108,9 @@
     boolean mTurnOnScreen;
 
     int mLayoutSeq = -1;
-    
+
     Configuration mConfiguration = null;
-    
+
     /**
      * Actual frame shown on-screen (may be modified by animation).  These
      * are in the screen's coordinate space (WITH the compatibility scale
@@ -212,15 +210,6 @@
     // an enter animation.
     boolean mEnterAnimationPending;
 
-    // Currently running animation.
-    boolean mAnimating;
-    boolean mLocalAnimating;
-    Animation mAnimation;
-    boolean mAnimationIsEntrance;
-    boolean mHasTransformation;
-    boolean mHasLocalTransformation;
-    final Transformation mTransformation = new Transformation();
-
     // If a window showing a wallpaper: the requested offset for the
     // wallpaper; if a wallpaper window: the currently applied offset.
     float mWallpaperX = -1;
@@ -305,6 +294,8 @@
     int mAnimDw;
     int mAnimDh;
 
+    final WindowStateAnimator mWinAnimator;
+
     WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
            WindowState attachedWindow, int seq, WindowManager.LayoutParams a,
            int viewVisibility) {
@@ -333,6 +324,7 @@
             mBaseLayer = 0;
             mSubLayer = 0;
             mInputWindowHandle = null;
+            mWinAnimator = null;
             return;
         }
         mDeathRecipient = deathRecipient;
@@ -369,9 +361,11 @@
             mIsFloatingLayer = mIsImWindow || mIsWallpaper;
         }
 
+        mWinAnimator = new WindowStateAnimator(service, this, mAttachedWindow);
+
         WindowState appWin = this;
         while (appWin.mAttachedWindow != null) {
-            appWin = mAttachedWindow;
+            appWin = appWin.mAttachedWindow;
         }
         WindowToken appToken = appWin.mToken;
         while (appToken.appWindowToken == null) {
@@ -405,6 +399,7 @@
         mSession.windowAddedLocked();
     }
 
+    @Override
     public void computeFrameLw(Rect pf, Rect df, Rect cf, Rect vf) {
         mHaveFrame = true;
 
@@ -547,38 +542,47 @@
         }
     }
 
+    @Override
     public Rect getFrameLw() {
         return mFrame;
     }
 
+    @Override
     public RectF getShownFrameLw() {
         return mShownFrame;
     }
 
+    @Override
     public Rect getDisplayFrameLw() {
         return mDisplayFrame;
     }
 
+    @Override
     public Rect getContentFrameLw() {
         return mContentFrame;
     }
 
+    @Override
     public Rect getVisibleFrameLw() {
         return mVisibleFrame;
     }
 
+    @Override
     public boolean getGivenInsetsPendingLw() {
         return mGivenInsetsPending;
     }
 
+    @Override
     public Rect getGivenContentInsetsLw() {
         return mGivenContentInsets;
     }
 
+    @Override
     public Rect getGivenVisibleInsetsLw() {
         return mGivenVisibleInsets;
     }
 
+    @Override
     public WindowManager.LayoutParams getAttrs() {
         return mAttrs;
     }
@@ -632,41 +636,6 @@
         return mAppToken != null ? mAppToken.firstWindowDrawn : false;
     }
 
-    public void setAnimation(Animation anim) {
-        if (WindowManagerService.localLOGV) Slog.v(
-            WindowManagerService.TAG, "Setting animation in " + this + ": " + anim);
-        mAnimating = false;
-        mLocalAnimating = false;
-        mAnimation = anim;
-        mAnimation.restrictDuration(WindowManagerService.MAX_ANIMATION_DURATION);
-        mAnimation.scaleCurrentDuration(mService.mWindowAnimationScale);
-        // Start out animation gone if window is gone, or visible if window is visible.
-        mTransformation.clear();
-        mTransformation.setAlpha(mLastHidden ? 0 : 1);
-        mHasLocalTransformation = true;
-    }
-
-    public void clearAnimation() {
-        if (mAnimation != null) {
-            mAnimating = true;
-            mLocalAnimating = false;
-            mAnimation.cancel();
-            mAnimation = null;
-        }
-    }
-
-    // TODO: Fix and call finishExit() instead of cancelExitAnimationForNextAnimationLocked()
-    // for avoiding the code duplication.
-    void cancelExitAnimationForNextAnimationLocked() {
-        if (!mExiting) return;
-        if (mAnimation != null) {
-            mAnimation.cancel();
-            mAnimation = null;
-            destroySurfaceLocked();
-        }
-        mExiting = false;
-    }
-
     Surface createSurfaceLocked() {
         if (mSurface == null) {
             mReportDestroySurface = false;
@@ -931,7 +900,7 @@
                     + (mAppToken != null ? mAppToken.hiddenRequested : false)
                     + " tok.hidden="
                     + (mAppToken != null ? mAppToken.hidden : false)
-                    + " animating=" + mAnimating
+                    + " animating=" + mWinAnimator.mAnimating
                     + " tok animating="
                     + (mAppToken != null ? mAppToken.animating : false));
             if (!mService.showSurfaceRobustlyLocked(this)) {
@@ -978,11 +947,11 @@
                     // will do an animation to reveal it from behind the
                     // starting window, so there is no need for it to also
                     // be doing its own stuff.
-                    if (mAnimation != null) {
-                        mAnimation.cancel();
-                        mAnimation = null;
+                    if (mWinAnimator.mAnimation != null) {
+                        mWinAnimator.mAnimation.cancel();
+                        mWinAnimator.mAnimation = null;
                         // Make sure we clean up the animation.
-                        mAnimating = true;
+                        mWinAnimator.mAnimating = true;
                     }
                     mService.mFinishedStarting.add(mAppToken);
                     mService.mH.sendEmptyMessage(H.FINISHED_STARTING);
@@ -995,192 +964,6 @@
         return true;
     }
 
-    private boolean stepAnimation(long currentTime) {
-        if ((mAnimation == null) || !mLocalAnimating) {
-            return false;
-        }
-        mTransformation.clear();
-        final boolean more = mAnimation.getTransformation(currentTime, mTransformation);
-        if (WindowManagerService.DEBUG_ANIM) Slog.v(
-            WindowManagerService.TAG, "Stepped animation in " + this +
-            ": more=" + more + ", xform=" + mTransformation);
-        return more;
-    }
-
-    // This must be called while inside a transaction.  Returns true if
-    // there is more animation to run.
-    boolean stepAnimationLocked(long currentTime) {
-        // Save the animation state as it was before this step so WindowManagerService can tell if
-        // we just started or just stopped animating by comparing mWasAnimating with isAnimating().
-        mWasAnimating = mAnimating;
-        if (mService.okToDisplay()) {
-            // We will run animations as long as the display isn't frozen.
-
-            if (isDrawnLw() && mAnimation != null) {
-                mHasTransformation = true;
-                mHasLocalTransformation = true;
-                if (!mLocalAnimating) {
-                    if (WindowManagerService.DEBUG_ANIM) Slog.v(
-                        WindowManagerService.TAG, "Starting animation in " + this +
-                        " @ " + currentTime + ": ww=" + mFrame.width() +
-                        " wh=" + mFrame.height() +
-                        " dw=" + mAnimDw + " dh=" + mAnimDh +
-                        " scale=" + mService.mWindowAnimationScale);
-                    mAnimation.initialize(mFrame.width(), mFrame.height(), mAnimDw, mAnimDh);
-                    mAnimation.setStartTime(currentTime);
-                    mLocalAnimating = true;
-                    mAnimating = true;
-                }
-                if ((mAnimation != null) && mLocalAnimating) {
-                    if (stepAnimation(currentTime)) {
-                        return true;
-                    }
-                }
-                if (WindowManagerService.DEBUG_ANIM) Slog.v(
-                    WindowManagerService.TAG, "Finished animation in " + this +
-                    " @ " + currentTime);
-                //WindowManagerService.this.dump();
-            }
-            mHasLocalTransformation = false;
-            if ((!mLocalAnimating || mAnimationIsEntrance) && mAppToken != null
-                    && mAppToken.animation != null) {
-                // When our app token is animating, we kind-of pretend like
-                // we are as well.  Note the mLocalAnimating mAnimationIsEntrance
-                // part of this check means that we will only do this if
-                // our window is not currently exiting, or it is not
-                // locally animating itself.  The idea being that one that
-                // is exiting and doing a local animation should be removed
-                // once that animation is done.
-                mAnimating = true;
-                mHasTransformation = true;
-                mTransformation.clear();
-                return false;
-            } else if (mHasTransformation) {
-                // Little trick to get through the path below to act like
-                // we have finished an animation.
-                mAnimating = true;
-            } else if (isAnimating()) {
-                mAnimating = true;
-            }
-        } else if (mAnimation != null) {
-            // If the display is frozen, and there is a pending animation,
-            // clear it and make sure we run the cleanup code.
-            mAnimating = true;
-            mLocalAnimating = true;
-            mAnimation.cancel();
-            mAnimation = null;
-        }
-
-        if (!mAnimating && !mLocalAnimating) {
-            return false;
-        }
-
-        if (WindowManagerService.DEBUG_ANIM) Slog.v(
-            WindowManagerService.TAG, "Animation done in " + this + ": exiting=" + mExiting
-            + ", reportedVisible="
-            + (mAppToken != null ? mAppToken.reportedVisible : false));
-
-        mAnimating = false;
-        mLocalAnimating = false;
-        if (mAnimation != null) {
-            mAnimation.cancel();
-            mAnimation = null;
-        }
-        if (mService.mWindowDetachedWallpaper == this) {
-            mService.mWindowDetachedWallpaper = null;
-        }
-        mAnimLayer = mLayer;
-        if (mIsImWindow) {
-            mAnimLayer += mService.mInputMethodAnimLayerAdjustment;
-        } else if (mIsWallpaper) {
-            mAnimLayer += mService.mWallpaperAnimLayerAdjustment;
-        }
-        if (WindowManagerService.DEBUG_LAYERS) Slog.v(WindowManagerService.TAG, "Stepping win " + this
-                + " anim layer: " + mAnimLayer);
-        mHasTransformation = false;
-        mHasLocalTransformation = false;
-        if (mPolicyVisibility != mPolicyVisibilityAfterAnim) {
-            if (DEBUG_VISIBILITY) {
-                Slog.v(WindowManagerService.TAG, "Policy visibility changing after anim in " + this + ": "
-                        + mPolicyVisibilityAfterAnim);
-            }
-            mPolicyVisibility = mPolicyVisibilityAfterAnim;
-            mService.mLayoutNeeded = true;
-            if (!mPolicyVisibility) {
-                if (mService.mCurrentFocus == this) {
-                    mService.mFocusMayChange = true;
-                }
-                // Window is no longer visible -- make sure if we were waiting
-                // for it to be displayed before enabling the display, that
-                // we allow the display to be enabled now.
-                mService.enableScreenIfNeededLocked();
-            }
-        }
-        mTransformation.clear();
-        if (mHasDrawn
-                && mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING
-                && mAppToken != null
-                && mAppToken.firstWindowDrawn
-                && mAppToken.startingData != null) {
-            if (WindowManagerService.DEBUG_STARTING_WINDOW) Slog.v(WindowManagerService.TAG, "Finish starting "
-                    + mToken + ": first real window done animating");
-            mService.mFinishedStarting.add(mAppToken);
-            mService.mH.sendEmptyMessage(H.FINISHED_STARTING);
-        }
-
-        finishExit();
-        mService.mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
-        if (WindowManagerService.DEBUG_LAYOUT_REPEATS) mService.debugLayoutRepeats("WindowState");
-
-        if (mAppToken != null) {
-            mAppToken.updateReportedVisibilityLocked();
-        }
-
-        return false;
-    }
-
-    void finishExit() {
-        if (WindowManagerService.DEBUG_ANIM) Slog.v(
-                WindowManagerService.TAG, "finishExit in " + this
-                + ": exiting=" + mExiting
-                + " remove=" + mRemoveOnExit
-                + " windowAnimating=" + isWindowAnimating());
-
-        final int N = mChildWindows.size();
-        for (int i=0; i<N; i++) {
-            mChildWindows.get(i).finishExit();
-        }
-
-        if (!mExiting) {
-            return;
-        }
-
-        if (isWindowAnimating()) {
-            return;
-        }
-
-        if (WindowManagerService.localLOGV) Slog.v(
-                WindowManagerService.TAG, "Exit animation finished in " + this
-                + ": remove=" + mRemoveOnExit);
-        if (mSurface != null) {
-            mService.mDestroySurface.add(this);
-            mDestroying = true;
-            if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(this, "HIDE (finishExit)", null);
-            mSurfaceShown = false;
-            try {
-                mSurface.hide();
-            } catch (RuntimeException e) {
-                Slog.w(WindowManagerService.TAG, "Error hiding surface in " + this, e);
-            }
-            mLastHidden = true;
-        }
-        mExiting = false;
-        if (mRemoveOnExit) {
-            mService.mPendingRemove.add(this);
-            mRemoveOnExit = false;
-        }
-    }
-
     boolean isIdentityMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
         if (dsdx < .99999f || dsdx > 1.00001f) return false;
         if (dtdy < .99999f || dtdy > 1.00001f) return false;
@@ -1199,10 +982,10 @@
     }
 
     void computeShownFrameLocked() {
-        final boolean selfTransformation = mHasLocalTransformation;
+        final boolean selfTransformation = mWinAnimator.mHasLocalTransformation;
         Transformation attachedTransformation =
-                (mAttachedWindow != null && mAttachedWindow.mHasLocalTransformation)
-                ? mAttachedWindow.mTransformation : null;
+                (mAttachedWindow != null && mAttachedWindow.mWinAnimator.mHasLocalTransformation)
+                ? mAttachedWindow.mWinAnimator.mTransformation : null;
         Transformation appTransformation =
                 (mAppToken != null && mAppToken.hasTransformation)
                 ? mAppToken.transformation : null;
@@ -1211,10 +994,10 @@
         // are currently targeting.
         if (mAttrs.type == TYPE_WALLPAPER && mService.mLowerWallpaperTarget == null
                 && mService.mWallpaperTarget != null) {
-            if (mService.mWallpaperTarget.mHasLocalTransformation &&
-                    mService.mWallpaperTarget.mAnimation != null &&
-                    !mService.mWallpaperTarget.mAnimation.getDetachWallpaper()) {
-                attachedTransformation = mService.mWallpaperTarget.mTransformation;
+            if (mService.mWallpaperTarget.mWinAnimator.mHasLocalTransformation &&
+                    mService.mWallpaperTarget.mWinAnimator.mAnimation != null &&
+                    !mService.mWallpaperTarget.mWinAnimator.mAnimation.getDetachWallpaper()) {
+                attachedTransformation = mService.mWallpaperTarget.mWinAnimator.mTransformation;
                 if (WindowManagerService.DEBUG_WALLPAPER && attachedTransformation != null) {
                     Slog.v(WindowManagerService.TAG, "WP target attached xform: " + attachedTransformation);
                 }
@@ -1260,7 +1043,7 @@
             }
             tmpMatrix.postScale(mGlobalScale, mGlobalScale);
             if (selfTransformation) {
-                tmpMatrix.postConcat(mTransformation.getMatrix());
+                tmpMatrix.postConcat(mWinAnimator.mTransformation.getMatrix());
             }
             tmpMatrix.postTranslate(frame.left + mXOffset, frame.top + mYOffset);
             if (attachedTransformation != null) {
@@ -1304,7 +1087,7 @@
                             && x == frame.left && y == frame.top))) {
                 //Slog.i(TAG, "Applying alpha transform");
                 if (selfTransformation) {
-                    mShownAlpha *= mTransformation.getAlpha();
+                    mShownAlpha *= mWinAnimator.mTransformation.getAlpha();
                 }
                 if (attachedTransformation != null) {
                     mShownAlpha *= attachedTransformation.getAlpha();
@@ -1323,7 +1106,7 @@
             if (WindowManagerService.localLOGV) Slog.v(
                 WindowManagerService.TAG, "computeShownFrameLocked: Animating " + this +
                 ": " + mShownFrame +
-                ", alpha=" + mTransformation.getAlpha() + ", mShownAlpha=" + mShownAlpha);
+                ", alpha=" + mWinAnimator.mTransformation.getAlpha() + ", mShownAlpha=" + mShownAlpha);
             return;
         }
 
@@ -1374,7 +1157,7 @@
                 && (atoken == null ? mPolicyVisibility : !atoken.hiddenRequested)
                 && ((!mAttachedHidden && mViewVisibility == View.VISIBLE
                                 && !mRootToken.hidden)
-                        || mAnimation != null || animating);
+                        || mWinAnimator.mAnimation != null || animating);
     }
 
     /**
@@ -1431,10 +1214,10 @@
         if (atoken != null) {
             return mSurface != null && mPolicyVisibility && !mDestroying
                     && ((!mAttachedHidden && !atoken.hiddenRequested)
-                            || mAnimation != null || atoken.animation != null);
+                            || mWinAnimator.mAnimation != null || atoken.animation != null);
         } else {
             return mSurface != null && mPolicyVisibility && !mDestroying
-                    && (!mAttachedHidden || mAnimation != null);
+                    && (!mAttachedHidden || mWinAnimator.mAnimation != null);
         }
     }
 
@@ -1450,26 +1233,10 @@
         return mSurface != null && mPolicyVisibility && !mDestroying
                 && ((!mAttachedHidden && mViewVisibility == View.VISIBLE
                                 && !mRootToken.hidden)
-                        || mAnimation != null
+                        || mWinAnimator.mAnimation != null
                         || ((mAppToken != null) && (mAppToken.animation != null)));
     }
 
-    /** Is the window or its container currently animating? */
-    boolean isAnimating() {
-        final WindowState attached = mAttachedWindow;
-        final AppWindowToken atoken = mAppToken;
-        return mAnimation != null
-                || (attached != null && attached.mAnimation != null)
-                || (atoken != null &&
-                        (atoken.animation != null
-                                || atoken.inPendingTransaction));
-    }
-
-    /** Is this window currently animating? */
-    boolean isWindowAnimating() {
-        return mAnimation != null;
-    }
-
     /**
      * Like isOnScreen, but returns false if the surface hasn't yet
      * been drawn.
@@ -1479,7 +1246,7 @@
         return isDrawnLw() && mPolicyVisibility
             && ((!mAttachedHidden &&
                     (atoken == null || !atoken.hiddenRequested))
-                    || mAnimating);
+                    || mWinAnimator.mAnimating);
     }
 
     public boolean isGoneForLayoutLw() {
@@ -1508,7 +1275,7 @@
     boolean isOpaqueDrawn() {
         return (mAttrs.format == PixelFormat.OPAQUE
                         || mAttrs.type == TYPE_WALLPAPER)
-                && isDrawnLw() && mAnimation == null
+                && isDrawnLw() && mWinAnimator.mAnimation == null
                 && (mAppToken == null || mAppToken.animation == null);
     }
 
@@ -1607,10 +1374,10 @@
         if (DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, "Policy visibility true: " + this);
         if (doAnimation) {
             if (DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, "doAnimation: mPolicyVisibility="
-                    + mPolicyVisibility + " mAnimation=" + mAnimation);
+                    + mPolicyVisibility + " mAnimation=" + mWinAnimator.mAnimation);
             if (!mService.okToDisplay()) {
                 doAnimation = false;
-            } else if (mPolicyVisibility && mAnimation == null) {
+            } else if (mPolicyVisibility && mWinAnimator.mAnimation == null) {
                 // Check for the case where we are currently visible and
                 // not animating; we do not want to do animation at such a
                 // point to become visible when we already are.
@@ -1646,7 +1413,7 @@
         }
         if (doAnimation) {
             mService.applyAnimationLocked(this, WindowManagerPolicy.TRANSIT_EXIT, false);
-            if (mAnimation == null) {
+            if (mWinAnimator.mAnimation == null) {
                 doAnimation = false;
             }
         }
@@ -1821,20 +1588,7 @@
                     pw.print(" last="); mLastVisibleInsets.printShortString(pw);
                     pw.println();
         }
-        if (mAnimating || mLocalAnimating || mAnimationIsEntrance
-                || mAnimation != null) {
-            pw.print(prefix); pw.print("mAnimating="); pw.print(mAnimating);
-                    pw.print(" mLocalAnimating="); pw.print(mLocalAnimating);
-                    pw.print(" mAnimationIsEntrance="); pw.print(mAnimationIsEntrance);
-                    pw.print(" mAnimation="); pw.println(mAnimation);
-        }
-        if (mHasTransformation || mHasLocalTransformation) {
-            pw.print(prefix); pw.print("XForm: has=");
-                    pw.print(mHasTransformation);
-                    pw.print(" hasLocal="); pw.print(mHasLocalTransformation);
-                    pw.print(" "); mTransformation.printShortString(pw);
-                    pw.println();
-        }
+        mWinAnimator.dump(pw, prefix, dumpAll);
         if (mShownAlpha != 1 || mAlpha != 1 || mLastAlpha != 1) {
             pw.print(prefix); pw.print("mShownAlpha="); pw.print(mShownAlpha);
                     pw.print(" mAlpha="); pw.print(mAlpha);
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
new file mode 100644
index 0000000..d86d411
--- /dev/null
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -0,0 +1,298 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+
+package com.android.server.wm;
+
+import android.util.Slog;
+import android.view.WindowManager;
+import android.view.WindowManagerPolicy;
+import android.view.animation.Animation;
+import android.view.animation.Transformation;
+
+import com.android.server.wm.WindowManagerService.H;
+
+import java.io.PrintWriter;
+
+/**
+ * @author cmautner@google.com (Craig Mautner)
+ *
+ */
+class WindowStateAnimator {
+
+    final WindowManagerService mService;
+    final WindowState mWin;
+    final WindowState mAttachedWindow;
+
+    // Currently running animation.
+    boolean mAnimating;
+    boolean mLocalAnimating;
+    Animation mAnimation;
+    boolean mAnimationIsEntrance;
+    boolean mHasTransformation;
+    boolean mHasLocalTransformation;
+    final Transformation mTransformation = new Transformation();
+    boolean mWasAnimating;      // Were we animating going into the most recent animation step?
+
+    public WindowStateAnimator(final WindowManagerService service, final WindowState win,
+                               final WindowState attachedWindow) {
+        mService = service;
+        mWin = win;
+        mAttachedWindow = attachedWindow;
+    }
+
+    public void setAnimation(Animation anim) {
+        if (WindowManagerService.localLOGV) Slog.v(
+            WindowManagerService.TAG, "Setting animation in " + this + ": " + anim);
+        mAnimating = false;
+        mLocalAnimating = false;
+        mAnimation = anim;
+        mAnimation.restrictDuration(WindowManagerService.MAX_ANIMATION_DURATION);
+        mAnimation.scaleCurrentDuration(mService.mWindowAnimationScale);
+        // Start out animation gone if window is gone, or visible if window is visible.
+        mTransformation.clear();
+        mTransformation.setAlpha(mWin.mLastHidden ? 0 : 1);
+        mHasLocalTransformation = true;
+    }
+
+    public void clearAnimation() {
+        if (mAnimation != null) {
+            mAnimating = true;
+            mLocalAnimating = false;
+            mAnimation.cancel();
+            mAnimation = null;
+        }
+    }
+
+    /** Is the window or its container currently animating? */
+    boolean isAnimating() {
+        final WindowState attached = mAttachedWindow;
+        final AppWindowToken atoken = mWin.mAppToken;
+        return mAnimation != null
+                || (attached != null && attached.mWinAnimator.mAnimation != null)
+                || (atoken != null &&
+                        (atoken.animation != null
+                                || atoken.inPendingTransaction));
+    }
+
+    /** Is this window currently animating? */
+    boolean isWindowAnimating() {
+        return mAnimation != null;
+    }
+
+    // TODO: Fix and call finishExit() instead of cancelExitAnimationForNextAnimationLocked()
+    // for avoiding the code duplication.
+    void cancelExitAnimationForNextAnimationLocked() {
+        if (!mWin.mExiting) return;
+        if (mAnimation != null) {
+            mAnimation.cancel();
+            mAnimation = null;
+            mWin.destroySurfaceLocked();
+        }
+        mWin.mExiting = false;
+    }
+
+    private boolean stepAnimation(long currentTime) {
+        if ((mAnimation == null) || !mLocalAnimating) {
+            return false;
+        }
+        mTransformation.clear();
+        final boolean more = mAnimation.getTransformation(currentTime, mTransformation);
+        if (WindowManagerService.DEBUG_ANIM) Slog.v(
+            WindowManagerService.TAG, "Stepped animation in " + this +
+            ": more=" + more + ", xform=" + mTransformation);
+        return more;
+    }
+
+    // This must be called while inside a transaction.  Returns true if
+    // there is more animation to run.
+    boolean stepAnimationLocked(long currentTime) {
+        // Save the animation state as it was before this step so WindowManagerService can tell if
+        // we just started or just stopped animating by comparing mWasAnimating with isAnimating().
+        mWasAnimating = mAnimating;
+        if (mService.okToDisplay()) {
+            // We will run animations as long as the display isn't frozen.
+
+            if (mWin.isDrawnLw() && mAnimation != null) {
+                mHasTransformation = true;
+                mHasLocalTransformation = true;
+                if (!mLocalAnimating) {
+                    if (WindowManagerService.DEBUG_ANIM) Slog.v(
+                        WindowManagerService.TAG, "Starting animation in " + this +
+                        " @ " + currentTime + ": ww=" + mWin.mFrame.width() +
+                        " wh=" + mWin.mFrame.height() +
+                        " dw=" + mWin.mAnimDw + " dh=" + mWin.mAnimDh +
+                        " scale=" + mService.mWindowAnimationScale);
+                    mAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(), mWin.mAnimDw,
+                        mWin.mAnimDh);
+                    mAnimation.setStartTime(currentTime);
+                    mLocalAnimating = true;
+                    mAnimating = true;
+                }
+                if ((mAnimation != null) && mLocalAnimating) {
+                    if (stepAnimation(currentTime)) {
+                        return true;
+                    }
+                }
+                if (WindowManagerService.DEBUG_ANIM) Slog.v(
+                    WindowManagerService.TAG, "Finished animation in " + this +
+                    " @ " + currentTime);
+                //WindowManagerService.this.dump();
+            }
+            mHasLocalTransformation = false;
+            if ((!mLocalAnimating || mAnimationIsEntrance) && mWin.mAppToken != null
+                    && mWin.mAppToken.animation != null) {
+                // When our app token is animating, we kind-of pretend like
+                // we are as well.  Note the mLocalAnimating mAnimationIsEntrance
+                // part of this check means that we will only do this if
+                // our window is not currently exiting, or it is not
+                // locally animating itself.  The idea being that one that
+                // is exiting and doing a local animation should be removed
+                // once that animation is done.
+                mAnimating = true;
+                mHasTransformation = true;
+                mTransformation.clear();
+                return false;
+            } else if (mHasTransformation) {
+                // Little trick to get through the path below to act like
+                // we have finished an animation.
+                mAnimating = true;
+            } else if (isAnimating()) {
+                mAnimating = true;
+            }
+        } else if (mAnimation != null) {
+            // If the display is frozen, and there is a pending animation,
+            // clear it and make sure we run the cleanup code.
+            mAnimating = true;
+            mLocalAnimating = true;
+            mAnimation.cancel();
+            mAnimation = null;
+        }
+
+        if (!mAnimating && !mLocalAnimating) {
+            return false;
+        }
+
+        if (WindowManagerService.DEBUG_ANIM) Slog.v(
+            WindowManagerService.TAG, "Animation done in " + this + ": exiting=" + mWin.mExiting
+            + ", reportedVisible="
+            + (mWin.mAppToken != null ? mWin.mAppToken.reportedVisible : false));
+
+        mAnimating = false;
+        mLocalAnimating = false;
+        if (mAnimation != null) {
+            mAnimation.cancel();
+            mAnimation = null;
+        }
+        if (mService.mWindowDetachedWallpaper == mWin) {
+            mService.mWindowDetachedWallpaper = null;
+        }
+        mWin.mAnimLayer = mWin.mLayer;
+        if (mWin.mIsImWindow) {
+            mWin.mAnimLayer += mService.mInputMethodAnimLayerAdjustment;
+        } else if (mWin.mIsWallpaper) {
+            mWin.mAnimLayer += mService.mWallpaperAnimLayerAdjustment;
+        }
+        if (WindowManagerService.DEBUG_LAYERS) Slog.v(WindowManagerService.TAG, "Stepping win " + this
+                + " anim layer: " + mWin.mAnimLayer);
+        mHasTransformation = false;
+        mHasLocalTransformation = false;
+        if (mWin.mPolicyVisibility != mWin.mPolicyVisibilityAfterAnim) {
+            if (WindowState.DEBUG_VISIBILITY) {
+                Slog.v(WindowManagerService.TAG, "Policy visibility changing after anim in " + this + ": "
+                        + mWin.mPolicyVisibilityAfterAnim);
+            }
+            mWin.mPolicyVisibility = mWin.mPolicyVisibilityAfterAnim;
+            mService.mLayoutNeeded = true;
+            if (!mWin.mPolicyVisibility) {
+                if (mService.mCurrentFocus == mWin) {
+                    mService.mFocusMayChange = true;
+                }
+                // Window is no longer visible -- make sure if we were waiting
+                // for it to be displayed before enabling the display, that
+                // we allow the display to be enabled now.
+                mService.enableScreenIfNeededLocked();
+            }
+        }
+        mTransformation.clear();
+        if (mWin.mHasDrawn
+                && mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING
+                && mWin.mAppToken != null
+                && mWin.mAppToken.firstWindowDrawn
+                && mWin.mAppToken.startingData != null) {
+            if (WindowManagerService.DEBUG_STARTING_WINDOW) Slog.v(WindowManagerService.TAG, "Finish starting "
+                    + mWin.mToken + ": first real window done animating");
+            mService.mFinishedStarting.add(mWin.mAppToken);
+            mService.mH.sendEmptyMessage(H.FINISHED_STARTING);
+        }
+
+        finishExit();
+        mService.mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
+        if (WindowManagerService.DEBUG_LAYOUT_REPEATS) mService.debugLayoutRepeats("WindowState");
+
+        if (mWin.mAppToken != null) {
+            mWin.mAppToken.updateReportedVisibilityLocked();
+        }
+
+        return false;
+    }
+
+    void finishExit() {
+        if (WindowManagerService.DEBUG_ANIM) Slog.v(
+                WindowManagerService.TAG, "finishExit in " + this
+                + ": exiting=" + mWin.mExiting
+                + " remove=" + mWin.mRemoveOnExit
+                + " windowAnimating=" + isWindowAnimating());
+
+        final int N = mWin.mChildWindows.size();
+        for (int i=0; i<N; i++) {
+            mWin.mChildWindows.get(i).mWinAnimator.finishExit();
+        }
+
+        if (!mWin.mExiting) {
+            return;
+        }
+
+        if (isWindowAnimating()) {
+            return;
+        }
+
+        if (WindowManagerService.localLOGV) Slog.v(
+                WindowManagerService.TAG, "Exit animation finished in " + this
+                + ": remove=" + mWin.mRemoveOnExit);
+        if (mWin.mSurface != null) {
+            mService.mDestroySurface.add(mWin);
+            mWin.mDestroying = true;
+            if (WindowState.SHOW_TRANSACTIONS) WindowManagerService.logSurface(
+                mWin, "HIDE (finishExit)", null);
+            mWin.mSurfaceShown = false;
+            try {
+                mWin.mSurface.hide();
+            } catch (RuntimeException e) {
+                Slog.w(WindowManagerService.TAG, "Error hiding surface in " + this, e);
+            }
+            mWin.mLastHidden = true;
+        }
+        mWin.mExiting = false;
+        if (mWin.mRemoveOnExit) {
+            mService.mPendingRemove.add(mWin);
+            mWin.mRemoveOnExit = false;
+        }
+    }
+
+    public void dump(PrintWriter pw, String prefix, boolean dumpAll) {
+        if (mAnimating || mLocalAnimating || mAnimationIsEntrance
+                || mAnimation != null) {
+            pw.print(prefix); pw.print("mAnimating="); pw.print(mAnimating);
+                    pw.print(" mLocalAnimating="); pw.print(mLocalAnimating);
+                    pw.print(" mAnimationIsEntrance="); pw.print(mAnimationIsEntrance);
+                    pw.print(" mAnimation="); pw.println(mAnimation);
+        }
+        if (mHasTransformation || mHasLocalTransformation) {
+            pw.print(prefix); pw.print("XForm: has=");
+                    pw.print(mHasTransformation);
+                    pw.print(" hasLocal="); pw.print(mHasLocalTransformation);
+                    pw.print(" "); mTransformation.printShortString(pw);
+                    pw.println();
+        }
+    }
+
+}