Separate animation into separate class.

Introduction of the class WindowAnimator which takes care of all
animations stepping and Surface operations.

Change-Id: I78f1c269fa57df0616c08adbe156e3059709ae48
diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/java/com/android/server/wm/AppWindowToken.java
index 3043da2..0e110be 100644
--- a/services/java/com/android/server/wm/AppWindowToken.java
+++ b/services/java/com/android/server/wm/AppWindowToken.java
@@ -56,7 +56,8 @@
     // These are used for determining when all windows associated with
     // an activity have been drawn, so they can be made visible together
     // at the same time.
-    int lastTransactionSequence;
+    // initialize so that it doesn't match mTransactionSequence which is an int.
+    long lastTransactionSequence = Long.MIN_VALUE;
     int numInterestingWindows;
     int numDrawnWindows;
     boolean inPendingTransaction;
@@ -113,7 +114,6 @@
         appWindowToken = this;
         appToken = _token;
         mInputApplicationHandle = new InputApplicationHandle(this);
-        lastTransactionSequence = service.mTransactionSequence-1;
     }
 
     public void setAnimation(Animation anim) {
diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java
new file mode 100644
index 0000000..b3dbee1
--- /dev/null
+++ b/services/java/com/android/server/wm/WindowAnimator.java
@@ -0,0 +1,575 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+
+package com.android.server.wm;
+
+import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+
+import android.content.Context;
+import android.os.SystemClock;
+import android.util.Log;
+import android.util.Slog;
+import android.view.Surface;
+import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
+import android.view.WindowManagerPolicy;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+
+import com.android.internal.policy.impl.PhoneWindowManager;
+
+/**
+ * @author cmautner@google.com (Craig Mautner)
+ * Singleton class that carries out the animations and Surface operations in a separate task
+ * on behalf of WindowManagerService.
+ */
+public class WindowAnimator {
+    private static final String TAG = "WindowAnimations";
+
+    final WindowManagerService mService;
+    final Context mContext;
+    final WindowManagerPolicy mPolicy;
+
+    boolean mAnimating;
+    boolean mUpdateRotation;
+    boolean mTokenMayBeDrawn;
+    boolean mForceHiding;
+    WindowState mWindowAnimationBackground;
+    int mWindowAnimationBackgroundColor;
+    int mAdjResult;
+
+    int mPendingLayoutChanges;
+
+    /** Overall window dimensions */
+    int mDw, mDh;
+
+    /** Interior window dimensions */
+    int mInnerDw, mInnerDh;
+
+    /** Time of current animation step. Reset on each iteration */
+    long mCurrentTime;
+
+    /** Skip repeated AppWindowTokens initialization. Note that AppWindowsToken's version of this
+     * is a long initialized to Long.MIN_VALUE so that it doesn't match this value on startup. */
+    private int mTransactionSequence;
+
+    /** The one and only screen rotation if one is happening */
+    ScreenRotationAnimation mScreenRotationAnimation = null;
+
+    WindowAnimator(final WindowManagerService service, final Context context,
+            final WindowManagerPolicy policy) {
+        mService = service;
+        mContext = context;
+        mPolicy = policy;
+    }
+
+    private void updateWindowsAppsAndRotationAnimationsLocked() {
+        int i;
+        final int NAT = mService.mAppTokens.size();
+        for (i=0; i<NAT; i++) {
+            final AppWindowToken appToken = mService.mAppTokens.get(i);
+            if (appToken.stepAnimationLocked(mCurrentTime, mInnerDw, mInnerDh)) {
+                mAnimating = true;
+            }
+        }
+
+        if (mScreenRotationAnimation != null &&
+                (mScreenRotationAnimation.isAnimating() ||
+                        mScreenRotationAnimation.mFinishAnimReady)) {
+            if (mScreenRotationAnimation.stepAnimationLocked(mCurrentTime)) {
+                mUpdateRotation = false;
+                mAnimating = true;
+            } else {
+                mUpdateRotation = true;
+                mScreenRotationAnimation.kill();
+                mScreenRotationAnimation = null;
+            }
+        }
+    }
+
+    private void updateWindowsAndWallpaperLocked() {
+        ++mTransactionSequence;
+
+        for (int i = mService.mWindows.size() - 1; i >= 0; i--) {
+            WindowState w = mService.mWindows.get(i);
+
+            final WindowManager.LayoutParams attrs = w.mAttrs;
+
+            if (w.mSurface != null) {
+                // Take care of the window being ready to display.
+                if (w.commitFinishDrawingLocked(mCurrentTime)) {
+                    if ((w.mAttrs.flags
+                            & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
+                        if (WindowManagerService.DEBUG_WALLPAPER) Slog.v(TAG,
+                                "First draw done in potential wallpaper target " + w);
+                        mService.mInnerFields.mWallpaperMayChange = true;
+                        mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+                    }
+                }
+
+                // If the window has moved due to its containing
+                // content frame changing, then we'd like to animate
+                // it.  The checks here are ordered by what is least
+                // likely to be true first.
+                if (w.shouldAnimateMove()) {
+                    // Frame has moved, containing content frame
+                    // has also moved, and we're not currently animating...
+                    // let's do something.
+                    Animation a = AnimationUtils.loadAnimation(mContext,
+                            com.android.internal.R.anim.window_move_from_decor);
+                    w.setAnimation(a);
+                    w.mAnimDw = w.mLastFrame.left - w.mFrame.left;
+                    w.mAnimDh = w.mLastFrame.top - w.mFrame.top;
+                } else {
+                    w.mAnimDw = mInnerDw;
+                    w.mAnimDh = mInnerDh;
+                }
+
+                final boolean wasAnimating = w.mWasAnimating;
+                final boolean nowAnimating = w.stepAnimationLocked(mCurrentTime);
+
+                if (WindowManagerService.DEBUG_WALLPAPER) {
+                    Slog.v(TAG, w + ": wasAnimating=" + wasAnimating +
+                            ", nowAnimating=" + nowAnimating);
+                }
+
+                // If this window is animating, make a note that we have
+                // an animating window and take care of a request to run
+                // a detached wallpaper animation.
+                if (nowAnimating) {
+                    if (w.mAnimation != null) {
+                        if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0
+                                && w.mAnimation.getDetachWallpaper()) {
+                            mService.mInnerFields.mDetachedWallpaper = w;
+                        }
+                        if (w.mAnimation.getBackgroundColor() != 0) {
+                            if (mWindowAnimationBackground == null
+                                    || (w.mAnimLayer < mWindowAnimationBackground.mAnimLayer)) {
+                                mWindowAnimationBackground = w;
+                                mWindowAnimationBackgroundColor =
+                                        w.mAnimation.getBackgroundColor();
+                            }
+                        }
+                    }
+                    mAnimating = true;
+                }
+
+                // If this window's app token is running a detached wallpaper
+                // animation, make a note so we can ensure the wallpaper is
+                // displayed behind it.
+                if (w.mAppToken != null && w.mAppToken.animation != null
+                        && w.mAppToken.animating) {
+                    if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0
+                            && w.mAppToken.animation.getDetachWallpaper()) {
+                        mService.mInnerFields.mDetachedWallpaper = w;
+                    }
+                    if (w.mAppToken.animation.getBackgroundColor() != 0) {
+                        if (mWindowAnimationBackground == null
+                                || (w.mAnimLayer <
+                                        mWindowAnimationBackground.mAnimLayer)) {
+                            mWindowAnimationBackground = w;
+                            mWindowAnimationBackgroundColor =
+                                    w.mAppToken.animation.getBackgroundColor();
+                        }
+                    }
+                }
+
+                if (wasAnimating && !w.mAnimating && mService.mWallpaperTarget == w) {
+                    mService.mInnerFields.mWallpaperMayChange = true;
+                    mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+                }
+
+                if (mPolicy.doesForceHide(w, attrs)) {
+                    if (!wasAnimating && nowAnimating) {
+                        if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
+                                "Animation started that could impact force hide: "
+                                + w);
+                        mService.mInnerFields.mWallpaperForceHidingChanged = true;
+                        mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+                        mService.mFocusMayChange = true;
+                    } else if (w.isReadyForDisplay() && w.mAnimation == null) {
+                        mForceHiding = true;
+                    }
+                } else if (mPolicy.canBeForceHidden(w, attrs)) {
+                    boolean changed;
+                    if (mForceHiding) {
+                        changed = w.hideLw(false, false);
+                        if (WindowManagerService.DEBUG_VISIBILITY && changed) Slog.v(TAG,
+                                "Now policy hidden: " + w);
+                    } else {
+                        changed = w.showLw(false, false);
+                        if (WindowManagerService.DEBUG_VISIBILITY && changed) Slog.v(TAG,
+                                "Now policy shown: " + w);
+                        if (changed) {
+                            if (mService.mInnerFields.mWallpaperForceHidingChanged
+                                    && w.isVisibleNow() /*w.isReadyForDisplay()*/) {
+                                // Assume we will need to animate.  If
+                                // we don't (because the wallpaper will
+                                // stay with the lock screen), then we will
+                                // clean up later.
+                                Animation a = mPolicy.createForceHideEnterAnimation();
+                                if (a != null) {
+                                    w.setAnimation(a);
+                                }
+                            }
+                            if (mCurrentFocus == null || mCurrentFocus.mLayer < w.mLayer) {
+                                // We are showing on to of the current
+                                // focus, so re-evaluate focus to make
+                                // sure it is correct.
+                                mService.mFocusMayChange = true;
+                            }
+                        }
+                    }
+                    if (changed && (attrs.flags
+                            & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
+                        mService.mInnerFields.mWallpaperMayChange = true;
+                        mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+                    }
+                }
+            }
+
+            final AppWindowToken atoken = w.mAppToken;
+            if (atoken != null && (!atoken.allDrawn || atoken.freezingScreen)) {
+                if (atoken.lastTransactionSequence != mTransactionSequence) {
+                    atoken.lastTransactionSequence = mTransactionSequence;
+                    atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
+                    atoken.startingDisplayed = false;
+                }
+                if ((w.isOnScreen() || w.mAttrs.type
+                        == WindowManager.LayoutParams.TYPE_BASE_APPLICATION)
+                        && !w.mExiting && !w.mDestroying) {
+                    if (WindowManagerService.DEBUG_VISIBILITY ||
+                            WindowManagerService.DEBUG_ORIENTATION) {
+                        Slog.v(TAG, "Eval win " + w + ": isDrawn="
+                                + w.isDrawnLw()
+                                + ", isAnimating=" + w.isAnimating());
+                        if (!w.isDrawnLw()) {
+                            Slog.v(TAG, "Not displayed: s=" + w.mSurface
+                                    + " pv=" + w.mPolicyVisibility
+                                    + " dp=" + w.mDrawPending
+                                    + " cdp=" + w.mCommitDrawPending
+                                    + " ah=" + w.mAttachedHidden
+                                    + " th=" + atoken.hiddenRequested
+                                    + " a=" + w.mAnimating);
+                        }
+                    }
+                    if (w != atoken.startingWindow) {
+                        if (!atoken.freezingScreen || !w.mAppFreezing) {
+                            atoken.numInterestingWindows++;
+                            if (w.isDrawnLw()) {
+                                atoken.numDrawnWindows++;
+                                if (WindowManagerService.DEBUG_VISIBILITY ||
+                                        WindowManagerService.DEBUG_ORIENTATION) Slog.v(TAG,
+                                        "tokenMayBeDrawn: " + atoken
+                                        + " freezingScreen=" + atoken.freezingScreen
+                                        + " mAppFreezing=" + w.mAppFreezing);
+                                mTokenMayBeDrawn = true;
+                            }
+                        }
+                    } else if (w.isDrawnLw()) {
+                        atoken.startingDisplayed = true;
+                    }
+                }
+            } else if (w.mReadyToShow) {
+                w.performShowLocked();
+                mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
+            }
+        } // end forall windows
+    }
+
+    private void testTokenMayBeDrawnLocked() {
+        // See if any windows have been drawn, so they (and others
+        // associated with them) can now be shown.
+        final int NT = mService.mAppTokens.size();
+        for (int i=0; i<NT; i++) {
+            AppWindowToken wtoken = mService.mAppTokens.get(i);
+            if (wtoken.freezingScreen) {
+                int numInteresting = wtoken.numInterestingWindows;
+                if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
+                    if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
+                            "allDrawn: " + wtoken
+                            + " interesting=" + numInteresting
+                            + " drawn=" + wtoken.numDrawnWindows);
+                    wtoken.showAllWindowsLocked();
+                    mService.unsetAppFreezingScreenLocked(wtoken, false, true);
+                    if (WindowManagerService.DEBUG_ORIENTATION) Slog.i(TAG,
+                            "Setting mOrientationChangeComplete=true because wtoken "
+                            + wtoken + " numInteresting=" + numInteresting
+                            + " numDrawn=" + wtoken.numDrawnWindows);
+                    mService.mInnerFields.mOrientationChangeComplete = true;
+                }
+            } else if (!wtoken.allDrawn) {
+                int numInteresting = wtoken.numInterestingWindows;
+                if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
+                    if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
+                            "allDrawn: " + wtoken
+                            + " interesting=" + numInteresting
+                            + " drawn=" + wtoken.numDrawnWindows);
+                    wtoken.allDrawn = true;
+                    mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
+
+                    // We can now show all of the drawn windows!
+                    if (!mService.mOpeningApps.contains(wtoken)) {
+                        mAnimating |= wtoken.showAllWindowsLocked();
+                    }
+                }
+            }
+        }
+    }
+
+    private void performAnimationsLocked() {
+        if (WindowManagerService.DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** ANIM STEP: seq="
+                + mTransactionSequence + " mAnimating="
+                + mAnimating);
+
+        mTokenMayBeDrawn = false;
+        mService.mInnerFields.mWallpaperMayChange = false;
+        mForceHiding = false;
+        mService.mInnerFields.mDetachedWallpaper = null;
+        mWindowAnimationBackground = null;
+        mWindowAnimationBackgroundColor = 0;
+
+        updateWindowsAndWallpaperLocked();
+
+        if (mTokenMayBeDrawn) {
+            testTokenMayBeDrawnLocked();
+        }
+
+        if (WindowManagerService.DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** ANIM STEP: changes=0x"
+                + Integer.toHexString(mPendingLayoutChanges));
+    }
+
+    public void prepareSurfaceLocked(final WindowState w, final boolean recoveringMemory) {
+        if (w.mSurface == null) {
+            if (w.mOrientationChanging) {
+                if (WindowManagerService.DEBUG_ORIENTATION) {
+                    Slog.v(TAG, "Orientation change skips hidden " + w);
+                }
+                w.mOrientationChanging = false;
+            }
+            return;
+        }
+
+        boolean displayed = false;
+
+        w.computeShownFrameLocked();
+
+        int width, height;
+        if ((w.mAttrs.flags & LayoutParams.FLAG_SCALED) != 0) {
+            // for a scaled surface, we just want to use
+            // the requested size.
+            width  = w.mRequestedWidth;
+            height = w.mRequestedHeight;
+        } else {
+            width = w.mCompatFrame.width();
+            height = w.mCompatFrame.height();
+        }
+
+        if (width < 1) {
+            width = 1;
+        }
+        if (height < 1) {
+            height = 1;
+        }
+        final boolean surfaceResized = w.mSurfaceW != width || w.mSurfaceH != height;
+        if (surfaceResized) {
+            w.mSurfaceW = width;
+            w.mSurfaceH = height;
+        }
+
+        if (w.mSurfaceX != w.mShownFrame.left
+                || w.mSurfaceY != w.mShownFrame.top) {
+            try {
+                if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
+                        "POS " + w.mShownFrame.left
+                        + ", " + w.mShownFrame.top, null);
+                w.mSurfaceX = w.mShownFrame.left;
+                w.mSurfaceY = w.mShownFrame.top;
+                w.mSurface.setPosition(w.mShownFrame.left, w.mShownFrame.top);
+            } catch (RuntimeException e) {
+                Slog.w(TAG, "Error positioning surface of " + w
+                        + " pos=(" + w.mShownFrame.left
+                        + "," + w.mShownFrame.top + ")", e);
+                if (!recoveringMemory) {
+                    mService.reclaimSomeSurfaceMemoryLocked(w, "position", true);
+                }
+            }
+        }
+
+        if (surfaceResized) {
+            try {
+                if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
+                        "SIZE " + width + "x" + height, null);
+                w.mSurfaceResized = true;
+                w.mSurface.setSize(width, height);
+            } catch (RuntimeException e) {
+                // If something goes wrong with the surface (such
+                // as running out of memory), don't take down the
+                // entire system.
+                Slog.e(TAG, "Error resizing surface of " + w
+                        + " size=(" + width + "x" + height + ")", e);
+                if (!recoveringMemory) {
+                    mService.reclaimSomeSurfaceMemoryLocked(w, "size", true);
+                }
+            }
+        }
+
+        if (w.mAttachedHidden || !w.isReadyForDisplay()) {
+            if (!w.mLastHidden) {
+                //dump();
+                w.mLastHidden = true;
+                if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
+                        "HIDE (performLayout)", null);
+                if (w.mSurface != null) {
+                    w.mSurfaceShown = false;
+                    try {
+                        w.mSurface.hide();
+                    } catch (RuntimeException e) {
+                        Slog.w(TAG, "Exception hiding surface in " + w);
+                    }
+                }
+            }
+            // If we are waiting for this window to handle an
+            // orientation change, well, it is hidden, so
+            // doesn't really matter.  Note that this does
+            // introduce a potential glitch if the window
+            // becomes unhidden before it has drawn for the
+            // new orientation.
+            if (w.mOrientationChanging) {
+                w.mOrientationChanging = false;
+                if (WindowManagerService.DEBUG_ORIENTATION) Slog.v(TAG,
+                        "Orientation change skips hidden " + w);
+            }
+        } else if (w.mLastLayer != w.mAnimLayer
+                || w.mLastAlpha != w.mShownAlpha
+                || w.mLastDsDx != w.mDsDx
+                || w.mLastDtDx != w.mDtDx
+                || w.mLastDsDy != w.mDsDy
+                || w.mLastDtDy != w.mDtDy
+                || w.mLastHScale != w.mHScale
+                || w.mLastVScale != w.mVScale
+                || w.mLastHidden) {
+            displayed = true;
+            w.mLastAlpha = w.mShownAlpha;
+            w.mLastLayer = w.mAnimLayer;
+            w.mLastDsDx = w.mDsDx;
+            w.mLastDtDx = w.mDtDx;
+            w.mLastDsDy = w.mDsDy;
+            w.mLastDtDy = w.mDtDy;
+            w.mLastHScale = w.mHScale;
+            w.mLastVScale = w.mVScale;
+            if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
+                    "alpha=" + w.mShownAlpha + " layer=" + w.mAnimLayer
+                    + " matrix=[" + (w.mDsDx*w.mHScale)
+                    + "," + (w.mDtDx*w.mVScale)
+                    + "][" + (w.mDsDy*w.mHScale)
+                    + "," + (w.mDtDy*w.mVScale) + "]", null);
+            if (w.mSurface != null) {
+                try {
+                    w.mSurfaceAlpha = w.mShownAlpha;
+                    w.mSurface.setAlpha(w.mShownAlpha);
+                    w.mSurfaceLayer = w.mAnimLayer;
+                    w.mSurface.setLayer(w.mAnimLayer);
+                    w.mSurface.setMatrix(
+                            w.mDsDx*w.mHScale, w.mDtDx*w.mVScale,
+                            w.mDsDy*w.mHScale, w.mDtDy*w.mVScale);
+                } catch (RuntimeException e) {
+                    Slog.w(TAG, "Error updating surface in " + w, e);
+                    if (!recoveringMemory) {
+                        mService.reclaimSomeSurfaceMemoryLocked(w, "update", true);
+                    }
+                }
+            }
+
+            if (w.mLastHidden && w.isDrawnLw()
+                    && !w.mReadyToShow) {
+                if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
+                        "SHOW (performLayout)", null);
+                if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG, "Showing " + w
+                        + " during relayout");
+                if (mService.showSurfaceRobustlyLocked(w)) {
+                    w.mHasDrawn = true;
+                    w.mLastHidden = false;
+                } else {
+                    w.mOrientationChanging = false;
+                }
+            }
+            if (w.mSurface != null) {
+                w.mToken.hasVisible = true;
+            }
+        } else {
+            displayed = true;
+        }
+
+        if (displayed) {
+            if (w.mOrientationChanging) {
+                if (!w.isDrawnLw()) {
+                    mService.mInnerFields.mOrientationChangeComplete = false;
+                    if (WindowManagerService.DEBUG_ORIENTATION) Slog.v(TAG,
+                            "Orientation continue waiting for draw in " + w);
+                } else {
+                    w.mOrientationChanging = false;
+                    if (WindowManagerService.DEBUG_ORIENTATION) Slog.v(TAG,
+                            "Orientation change complete in " + w);
+                }
+            }
+            w.mToken.hasVisible = true;
+        }
+    }
+
+    void animate() {
+        mCurrentTime = SystemClock.uptimeMillis();
+
+        // Update animations of all applications, including those
+        // associated with exiting/removed apps
+        Surface.openTransaction();
+
+        try {
+            updateWindowsAppsAndRotationAnimationsLocked();
+            performAnimationsLocked();
+
+            // THIRD LOOP: Update the surfaces of all windows.
+
+            if (mScreenRotationAnimation != null) {
+                mScreenRotationAnimation.updateSurfaces();
+            }
+
+            final int N = mService.mWindows.size();
+            for (int i=N-1; i>=0; i--) {
+                WindowState w = mService.mWindows.get(i);
+                prepareSurfaceLocked(w, true);
+            }
+
+            if (mService.mDimAnimator != null && mService.mDimAnimator.mDimShown) {
+                mAnimating |= mService.mDimAnimator.updateSurface(mService.mInnerFields.mDimming,
+                            mCurrentTime, !mService.okToDisplay());
+            }
+
+            if (mService.mBlackFrame != null) {
+                if (mScreenRotationAnimation != null) {
+                    mService.mBlackFrame.setMatrix(
+                            mScreenRotationAnimation.getEnterTransformation().getMatrix());
+                } else {
+                    mService.mBlackFrame.clearMatrix();
+                }
+            }
+        } catch (RuntimeException e) {
+            Log.wtf(TAG, "Unhandled exception in Window Manager", e);
+        } finally {
+            Surface.closeTransaction();
+        }
+    }
+
+    WindowState mCurrentFocus;
+    void setCurrentFocus(WindowState currentFocus) {
+        mCurrentFocus = currentFocus;
+    }
+
+    void setDisplayDimensions(final int curWidth, final int curHeight,
+                        final int appWidth, final int appHeight) {
+        mDw = curWidth;
+        mDh = curHeight;
+        mInnerDw = appWidth;
+        mInnerDh = appHeight;
+    }
+
+}
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 31a2788..26367d2 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -408,15 +408,12 @@
     IInputMethodManager mInputMethodManager;
 
     SurfaceSession mFxSession;
-    private DimAnimator mDimAnimator = null;
+    DimAnimator mDimAnimator = null;
     Watermark mWatermark;
     StrictModeFlash mStrictModeFlash;
-    ScreenRotationAnimation mScreenRotationAnimation;
 
     BlackFrame mBlackFrame;
 
-    int mTransactionSequence = 0;
-
     final float[] mTmpFloats = new float[9];
 
     boolean mSafeMode;
@@ -575,26 +572,21 @@
 
     /** Pulled out of performLayoutAndPlaceSurfacesLockedInner in order to refactor into multiple
      * methods. */
-    private class LayoutAndSurfaceFields {
-        private boolean mAnimating = false;
-        private boolean mWallpaperForceHidingChanged = false;
-        private boolean mTokenMayBeDrawn = false;
-        private boolean mWallpaperMayChange = false;
-        private boolean mForceHiding = false;
-        private WindowState mDetachedWallpaper = null;
-        private WindowState mWindowAnimationBackground = null;
-        private int mWindowAnimationBackgroundColor = 0;
-        private boolean mOrientationChangeComplete = true;
+    class LayoutAndSurfaceFields {
+        boolean mWallpaperForceHidingChanged = false;
+        boolean mWallpaperMayChange = false;
+        WindowState mDetachedWallpaper = null;
+        boolean mOrientationChangeComplete = true;
         private int mAdjResult = 0;
         private Session mHoldScreen = null;
         private boolean mObscured = false;
-        private boolean mDimming = false;
+        boolean mDimming = false;
         private boolean mSyswin = false;
         private float mScreenBrightness = -1;
         private float mButtonBrightness = -1;
         private boolean mUpdateRotation = false;
     }
-    private LayoutAndSurfaceFields mInnerFields = new LayoutAndSurfaceFields();
+    LayoutAndSurfaceFields mInnerFields = new LayoutAndSurfaceFields();
 
     private final class AnimationRunnable implements Runnable {
         @Override
@@ -607,6 +599,8 @@
     }
     final AnimationRunnable mAnimationRunnable = new AnimationRunnable();
     boolean mAnimationScheduled;
+    
+    final WindowAnimator mAnimator;
 
     final class DragInputEventReceiver extends InputEventReceiver {
         public DragInputEventReceiver(InputChannel inputChannel, Looper looper) {
@@ -828,6 +822,7 @@
         mHoldingScreenWakeLock.setReferenceCounted(false);
 
         mInputManager = new InputManager(context, this);
+        mAnimator = new WindowAnimator(this, context, mPolicy);
 
         PolicyThread thr = new PolicyThread(mPolicy, this, context, pm);
         thr.start();
@@ -2209,7 +2204,7 @@
             if (mInTouchMode) {
                 res |= WindowManagerImpl.ADD_FLAG_IN_TOUCH_MODE;
             }
-            if (win == null || win.mAppToken == null || !win.mAppToken.clientHidden) {
+            if (win.mAppToken == null || !win.mAppToken.clientHidden) {
                 res |= WindowManagerImpl.ADD_FLAG_APP_VISIBLE;
             }
 
@@ -2276,7 +2271,7 @@
             + ", surface=" + win.mSurface);
 
         final long origId = Binder.clearCallingIdentity();
-        
+
         win.disposeInputChannel();
 
         if (DEBUG_APP_TRANSITIONS) Slog.v(
@@ -2297,7 +2292,8 @@
         if (win.mSurface != null && okToDisplay()) {
             // If we are not currently running the exit animation, we
             // need to see about starting one.
-            if (wasVisible=win.isWinVisibleLw()) {
+            wasVisible = win.isWinVisibleLw();
+            if (wasVisible) {
 
                 int transit = WindowManagerPolicy.TRANSIT_EXIT;
                 if (win.getAttrs().type == TYPE_APPLICATION_STARTING) {
@@ -5382,7 +5378,8 @@
             return false;
         }
 
-        if (mScreenRotationAnimation != null && mScreenRotationAnimation.isAnimating()) {
+        if (mAnimator.mScreenRotationAnimation != null &&
+                mAnimator.mScreenRotationAnimation.isAnimating()) {
             // Rotation updates cannot be performed while the previous rotation change
             // animation is still in progress.  Skip this update.  We will try updating
             // again after the animation is finished and the display is unfrozen.
@@ -5452,9 +5449,9 @@
         try {
             // NOTE: We disable the rotation in the emulator because
             //       it doesn't support hardware OpenGL emulation yet.
-            if (CUSTOM_SCREEN_ROTATION && mScreenRotationAnimation != null
-                    && mScreenRotationAnimation.hasScreenshot()) {
-                if (mScreenRotationAnimation.setRotation(rotation, mFxSession,
+            if (CUSTOM_SCREEN_ROTATION && mAnimator.mScreenRotationAnimation != null
+                    && mAnimator.mScreenRotationAnimation.hasScreenshot()) {
+                if (mAnimator.mScreenRotationAnimation.setRotation(rotation, mFxSession,
                         MAX_ANIMATION_DURATION, mTransitionAnimationScale,
                         mCurDisplayWidth, mCurDisplayHeight)) {
                     scheduleAnimationLocked();
@@ -6156,6 +6153,8 @@
         synchronized(mDisplaySizeLock) {
             mAppDisplayWidth = appWidth;
             mAppDisplayHeight = appHeight;
+            mAnimator.setDisplayDimensions(mCurDisplayWidth, mCurDisplayHeight,
+                    mAppDisplayWidth, mAppDisplayHeight);
         }
         if (false) {
             Slog.i(TAG, "Set app display size: " + mAppDisplayWidth
@@ -6542,6 +6541,8 @@
                 }
                 mBaseDisplayWidth = mCurDisplayWidth = mAppDisplayWidth = mInitialDisplayWidth;
                 mBaseDisplayHeight = mCurDisplayHeight = mAppDisplayHeight = mInitialDisplayHeight;
+                mAnimator.setDisplayDimensions(mCurDisplayWidth, mCurDisplayHeight,
+                        mAppDisplayWidth, mAppDisplayHeight);
             }
             mInputManager.setDisplaySize(Display.DEFAULT_DISPLAY,
                     mDisplay.getRawWidth(), mDisplay.getRawHeight(),
@@ -7622,342 +7623,6 @@
 
     /**
      * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
-     * Update animations of all applications, including those associated with exiting/removed apps.
-     *
-     * @param currentTime The time which animations use for calculating transitions.
-     * @param innerDw Width of app window.
-     * @param innerDh Height of app window.
-     */
-    private void updateWindowsAppsAndRotationAnimationsLocked(long currentTime,
-                                                          int innerDw, int innerDh) {
-        int i;
-        final int NAT = mAppTokens.size();
-        for (i=0; i<NAT; i++) {
-            final AppWindowToken appToken = mAppTokens.get(i);
-            if (appToken.stepAnimationLocked(currentTime, innerDw, innerDh)) {
-                mInnerFields.mAnimating = true;
-            }
-        }
-        final int NEAT = mExitingAppTokens.size();
-        for (i=0; i<NEAT; i++) {
-            final AppWindowToken appToken = mExitingAppTokens.get(i);
-            if (appToken.stepAnimationLocked(currentTime, innerDw, innerDh)) {
-                mInnerFields.mAnimating = true;
-            }
-        }
-
-        if (mScreenRotationAnimation != null &&
-                (mScreenRotationAnimation.isAnimating() ||
-                        mScreenRotationAnimation.mFinishAnimReady)) {
-            if (mScreenRotationAnimation.stepAnimationLocked(currentTime)) {
-                mInnerFields.mUpdateRotation = false;
-                mInnerFields.mAnimating = true;
-            } else {
-                mInnerFields.mUpdateRotation = true;
-                mScreenRotationAnimation.kill();
-                mScreenRotationAnimation = null;
-            }
-        }
-    }
-
-    private void animateAndUpdateSurfaces(final long currentTime, final int dw, final int dh,
-                                          final int innerDw, final int innerDh, 
-                                          final boolean recoveringMemory) {
-        // Update animations of all applications, including those
-        // associated with exiting/removed apps
-        Surface.openTransaction();
-
-        try {
-            updateWindowsAppsAndRotationAnimationsLocked(currentTime, innerDw, innerDh);
-            mPendingLayoutChanges = performAnimationsLocked(currentTime, dw, dh,
-                    innerDw, innerDh);
-        
-            // THIRD LOOP: Update the surfaces of all windows.
-            
-            if (mScreenRotationAnimation != null) {
-                mScreenRotationAnimation.updateSurfaces();
-            }
-        
-            final int N = mWindows.size();
-            for (int i=N-1; i>=0; i--) {
-                WindowState w = mWindows.get(i);
-                prepareSurfaceLocked(w, recoveringMemory);
-            }
-        
-            if (mDimAnimator != null && mDimAnimator.mDimShown) {
-                mInnerFields.mAnimating |=
-                        mDimAnimator.updateSurface(mInnerFields.mDimming, currentTime,
-                            !okToDisplay());
-            }
-        
-            if (mBlackFrame != null) {
-                if (mScreenRotationAnimation != null) {
-                    mBlackFrame.setMatrix(
-                            mScreenRotationAnimation.getEnterTransformation().getMatrix());
-                } else {
-                    mBlackFrame.clearMatrix();
-                }
-            }
-        } catch (RuntimeException e) {
-            Log.wtf(TAG, "Unhandled exception in Window Manager", e);
-        } finally {
-            Surface.closeTransaction();
-        }
-    }
-    
-    /**
-     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
-     *
-     * @param currentTime The time which animations use for calculating transitions.
-     * @param dw Width of app window.
-     * @param dh Height of app window.
-     * @param innerDw Width of app window.
-     * @param innerDh Height of app window.
-     */
-    private int updateWindowsAndWallpaperLocked(final long currentTime, final int dw, final int dh,
-                                                final int innerDw, final int innerDh) {
-        ++mTransactionSequence;
-
-        int changes = 0;
-        for (int i = mWindows.size() - 1; i >= 0; i--) {
-            WindowState w = mWindows.get(i);
-
-            final WindowManager.LayoutParams attrs = w.mAttrs;
-
-            if (w.mSurface != null) {
-                // Take care of the window being ready to display.
-                if (w.commitFinishDrawingLocked(currentTime)) {
-                    if ((w.mAttrs.flags
-                            & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
-                        if (DEBUG_WALLPAPER) Slog.v(TAG,
-                                "First draw done in potential wallpaper target " + w);
-                        mInnerFields.mWallpaperMayChange = true;
-                        changes |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
-                    }
-                }
-
-                // If the window has moved due to its containing
-                // content frame changing, then we'd like to animate
-                // it.  The checks here are ordered by what is least
-                // likely to be true first.
-                if (w.shouldAnimateMove()) {
-                    // Frame has moved, containing content frame
-                    // has also moved, and we're not currently animating...
-                    // let's do something.
-                    Animation a = AnimationUtils.loadAnimation(mContext,
-                            com.android.internal.R.anim.window_move_from_decor);
-                    w.setAnimation(a);
-                    w.mAnimDw = w.mLastFrame.left - w.mFrame.left;
-                    w.mAnimDh = w.mLastFrame.top - w.mFrame.top;
-                } else {
-                    w.mAnimDw = innerDw;
-                    w.mAnimDh = innerDh;
-                }
-
-                final boolean wasAnimating = w.mWasAnimating;
-                final boolean nowAnimating = w.stepAnimationLocked(currentTime);
-
-                if (DEBUG_WALLPAPER) {
-                    Slog.v(TAG, w + ": wasAnimating=" + wasAnimating +
-                            ", nowAnimating=" + nowAnimating);
-                }
-
-                // If this window is animating, make a note that we have
-                // an animating window and take care of a request to run
-                // a detached wallpaper animation.
-                if (nowAnimating) {
-                    if (w.mAnimation != null) {
-                        if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0
-                                && w.mAnimation.getDetachWallpaper()) {
-                            mInnerFields.mDetachedWallpaper = w;
-                        }
-                        if (w.mAnimation.getBackgroundColor() != 0) {
-                            if (mInnerFields.mWindowAnimationBackground == null
-                                    || (w.mAnimLayer <
-                                            mInnerFields.mWindowAnimationBackground.mAnimLayer)) {
-                                mInnerFields.mWindowAnimationBackground = w;
-                                mInnerFields.mWindowAnimationBackgroundColor =
-                                        w.mAnimation.getBackgroundColor();
-                            }
-                        }
-                    }
-                    mInnerFields.mAnimating = true;
-                }
-
-                // If this window's app token is running a detached wallpaper
-                // animation, make a note so we can ensure the wallpaper is
-                // displayed behind it.
-                if (w.mAppToken != null && w.mAppToken.animation != null
-                        && w.mAppToken.animating) {
-                    if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0
-                            && w.mAppToken.animation.getDetachWallpaper()) {
-                        mInnerFields.mDetachedWallpaper = w;
-                    }
-                    if (w.mAppToken.animation.getBackgroundColor() != 0) {
-                        if (mInnerFields.mWindowAnimationBackground == null
-                                || (w.mAnimLayer <
-                                        mInnerFields.mWindowAnimationBackground.mAnimLayer)) {
-                            mInnerFields.mWindowAnimationBackground = w;
-                            mInnerFields.mWindowAnimationBackgroundColor =
-                                    w.mAppToken.animation.getBackgroundColor();
-                        }
-                    }
-                }
-
-                if (wasAnimating && !w.mAnimating && mWallpaperTarget == w) {
-                    mInnerFields.mWallpaperMayChange = true;
-                    changes |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
-                }
-
-                if (mPolicy.doesForceHide(w, attrs)) {
-                    if (!wasAnimating && nowAnimating) {
-                        if (DEBUG_VISIBILITY) Slog.v(TAG,
-                                "Animation started that could impact force hide: "
-                                + w);
-                        mInnerFields.mWallpaperForceHidingChanged = true;
-                        changes |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
-                        mFocusMayChange = true;
-                    } else if (w.isReadyForDisplay() && w.mAnimation == null) {
-                        mInnerFields.mForceHiding = true;
-                    }
-                } else if (mPolicy.canBeForceHidden(w, attrs)) {
-                    boolean changed;
-                    if (mInnerFields.mForceHiding) {
-                        changed = w.hideLw(false, false);
-                        if (DEBUG_VISIBILITY && changed) Slog.v(TAG,
-                                "Now policy hidden: " + w);
-                    } else {
-                        changed = w.showLw(false, false);
-                        if (DEBUG_VISIBILITY && changed) Slog.v(TAG,
-                                "Now policy shown: " + w);
-                        if (changed) {
-                            if (mInnerFields.mWallpaperForceHidingChanged
-                                    && w.isVisibleNow() /*w.isReadyForDisplay()*/) {
-                                // Assume we will need to animate.  If
-                                // we don't (because the wallpaper will
-                                // stay with the lock screen), then we will
-                                // clean up later.
-                                Animation a = mPolicy.createForceHideEnterAnimation();
-                                if (a != null) {
-                                    w.setAnimation(a);
-                                }
-                            }
-                            if (mCurrentFocus == null ||
-                                    mCurrentFocus.mLayer < w.mLayer) {
-                                // We are showing on to of the current
-                                // focus, so re-evaluate focus to make
-                                // sure it is correct.
-                                mFocusMayChange = true;
-                            }
-                        }
-                    }
-                    if (changed && (attrs.flags
-                            & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
-                        mInnerFields.mWallpaperMayChange = true;
-                        changes |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
-                    }
-                }
-            }
-
-            final AppWindowToken atoken = w.mAppToken;
-            if (atoken != null && (!atoken.allDrawn || atoken.freezingScreen)) {
-                if (atoken.lastTransactionSequence != mTransactionSequence) {
-                    atoken.lastTransactionSequence = mTransactionSequence;
-                    atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
-                    atoken.startingDisplayed = false;
-                }
-                if ((w.isOnScreen() || w.mAttrs.type
-                        == WindowManager.LayoutParams.TYPE_BASE_APPLICATION)
-                        && !w.mExiting && !w.mDestroying) {
-                    if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
-                        Slog.v(TAG, "Eval win " + w + ": isDrawn="
-                                + w.isDrawnLw()
-                                + ", isAnimating=" + w.isAnimating());
-                        if (!w.isDrawnLw()) {
-                            Slog.v(TAG, "Not displayed: s=" + w.mSurface
-                                    + " pv=" + w.mPolicyVisibility
-                                    + " dp=" + w.mDrawPending
-                                    + " cdp=" + w.mCommitDrawPending
-                                    + " ah=" + w.mAttachedHidden
-                                    + " th=" + atoken.hiddenRequested
-                                    + " a=" + w.mAnimating);
-                        }
-                    }
-                    if (w != atoken.startingWindow) {
-                        if (!atoken.freezingScreen || !w.mAppFreezing) {
-                            atoken.numInterestingWindows++;
-                            if (w.isDrawnLw()) {
-                                atoken.numDrawnWindows++;
-                                if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Slog.v(TAG,
-                                        "tokenMayBeDrawn: " + atoken
-                                        + " freezingScreen=" + atoken.freezingScreen
-                                        + " mAppFreezing=" + w.mAppFreezing);
-                                mInnerFields.mTokenMayBeDrawn = true;
-                            }
-                        }
-                    } else if (w.isDrawnLw()) {
-                        atoken.startingDisplayed = true;
-                    }
-                }
-            } else if (w.mReadyToShow) {
-                w.performShowLocked();
-                changes |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
-            }
-        } // end forall windows
-
-        return changes;
-    }
-
-    /**
-     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
-     *
-     * @return bitmap indicating if another pass through layout must be made.
-     */
-    private int testTokenMayBeDrawnLocked() {
-        int changes = 0;
-        // See if any windows have been drawn, so they (and others
-        // associated with them) can now be shown.
-        final int NT = mAppTokens.size();
-        for (int i=0; i<NT; i++) {
-            AppWindowToken wtoken = mAppTokens.get(i);
-            if (wtoken.freezingScreen) {
-                int numInteresting = wtoken.numInterestingWindows;
-                if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
-                    if (DEBUG_VISIBILITY) Slog.v(TAG,
-                            "allDrawn: " + wtoken
-                            + " interesting=" + numInteresting
-                            + " drawn=" + wtoken.numDrawnWindows);
-                    wtoken.showAllWindowsLocked();
-                    unsetAppFreezingScreenLocked(wtoken, false, true);
-                    if (DEBUG_ORIENTATION) Slog.i(TAG,
-                            "Setting mOrientationChangeComplete=true because wtoken "
-                            + wtoken + " numInteresting=" + numInteresting
-                            + " numDrawn=" + wtoken.numDrawnWindows);
-                    mInnerFields.mOrientationChangeComplete = true;
-                }
-            } else if (!wtoken.allDrawn) {
-                int numInteresting = wtoken.numInterestingWindows;
-                if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
-                    if (DEBUG_VISIBILITY) Slog.v(TAG,
-                            "allDrawn: " + wtoken
-                            + " interesting=" + numInteresting
-                            + " drawn=" + wtoken.numDrawnWindows);
-                    wtoken.allDrawn = true;
-                    changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
-
-                    // We can now show all of the drawn windows!
-                    if (!mOpeningApps.contains(wtoken)) {
-                        mInnerFields.mAnimating |= wtoken.showAllWindowsLocked();
-                    }
-                }
-            }
-        }
-
-        return changes;
-    }
-
-    /**
-     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
      *
      * @return bitmap indicating if another pass through layout must be made.
      */
@@ -8131,7 +7796,7 @@
                         transit, false);
                 wtoken.updateReportedVisibilityLocked();
                 wtoken.waitingToShow = false;
-                mInnerFields.mAnimating |= wtoken.showAllWindowsLocked();
+                mAnimator.mAnimating |= wtoken.showAllWindowsLocked();
             }
             NN = mClosingApps.size();
             for (i=0; i<NN; i++) {
@@ -8229,14 +7894,14 @@
         if (mLowerWallpaperTarget == null) {
             // Whoops, we don't need a special wallpaper animation.
             // Clear them out.
-            mInnerFields.mForceHiding = false;
+            mAnimator.mForceHiding = false;
             for (int i=mWindows.size()-1; i>=0; i--) {
                 WindowState w = mWindows.get(i);
                 if (w.mSurface != null) {
                     final WindowManager.LayoutParams attrs = w.mAttrs;
                     if (mPolicy.doesForceHide(w, attrs) && w.isVisibleLw()) {
                         if (DEBUG_FOCUS) Slog.i(TAG, "win=" + w + " force hides other windows");
-                        mInnerFields.mForceHiding = true;
+                        mAnimator.mForceHiding = true;
                     } else if (mPolicy.canBeForceHidden(w, attrs)) {
                         if (!w.mAnimating) {
                             // We set the animation above so it
@@ -8267,11 +7932,11 @@
             mInnerFields.mWallpaperMayChange = true;
         }
 
-        if (mInnerFields.mWindowAnimationBackgroundColor != 0) {
+        if (mAnimator.mWindowAnimationBackgroundColor != 0) {
             // If the window that wants black is the current wallpaper
             // target, then the black goes *below* the wallpaper so we
             // don't cause the wallpaper to suddenly disappear.
-            WindowState target = mInnerFields.mWindowAnimationBackground;
+            WindowState target = mAnimator.mWindowAnimationBackground;
             if (mWallpaperTarget == target
                     || mLowerWallpaperTarget == target
                     || mUpperWallpaperTarget == target) {
@@ -8290,7 +7955,7 @@
             final int dh = mCurDisplayHeight;
             mWindowAnimationBackgroundSurface.show(dw, dh,
                     target.mAnimLayer - LAYER_OFFSET_DIM,
-                    mInnerFields.mWindowAnimationBackgroundColor);
+                    mAnimator.mWindowAnimationBackgroundColor);
         } else if (mWindowAnimationBackgroundSurface != null) {
             mWindowAnimationBackgroundSurface.hide();
         }
@@ -8393,206 +8058,6 @@
     /**
      * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
      *
-     * @param w WindowState whos Surface is being prepared.
-     * @param recoveringMemory true if the caller will reclaim surface memory on error.
-     */
-    public void prepareSurfaceLocked(final WindowState w, final boolean recoveringMemory) {
-        // XXX NOTE: The logic here could be improved.  We have
-        // the decision about whether to resize a window separated
-        // from whether to hide the surface.  This can cause us to
-        // resize a surface even if we are going to hide it.  You
-        // can see this by (1) holding device in landscape mode on
-        // home screen; (2) tapping browser icon (device will rotate
-        // to landscape; (3) tap home.  The wallpaper will be resized
-        // in step 2 but then immediately hidden, causing us to
-        // have to resize and then redraw it again in step 3.  It
-        // would be nice to figure out how to avoid this, but it is
-        // difficult because we do need to resize surfaces in some
-        // cases while they are hidden such as when first showing a
-        // window.
-        
-        if (w.mSurface == null) {
-            if (w.mOrientationChanging) {
-                if (DEBUG_ORIENTATION) {
-                    Slog.v(TAG, "Orientation change skips hidden " + w);
-                }
-                w.mOrientationChanging = false;
-            }
-            return;
-        }
-        
-        boolean displayed = false;
-
-        w.computeShownFrameLocked();
-
-        int width, height;
-        if ((w.mAttrs.flags & w.mAttrs.FLAG_SCALED) != 0) {
-            // for a scaled surface, we just want to use
-            // the requested size.
-            width  = w.mRequestedWidth;
-            height = w.mRequestedHeight;
-        } else {
-            width = w.mCompatFrame.width();
-            height = w.mCompatFrame.height();
-        }
-
-        if (width < 1) {
-            width = 1;
-        }
-        if (height < 1) {
-            height = 1;
-        }
-        final boolean surfaceResized = w.mSurfaceW != width || w.mSurfaceH != height;
-        if (surfaceResized) {
-            w.mSurfaceW = width;
-            w.mSurfaceH = height;
-        }
-
-        if (w.mSurfaceX != w.mShownFrame.left
-                || w.mSurfaceY != w.mShownFrame.top) {
-            try {
-                if (SHOW_TRANSACTIONS) logSurface(w,
-                        "POS " + w.mShownFrame.left
-                        + ", " + w.mShownFrame.top, null);
-                w.mSurfaceX = w.mShownFrame.left;
-                w.mSurfaceY = w.mShownFrame.top;
-                w.mSurface.setPosition(w.mShownFrame.left, w.mShownFrame.top);
-            } catch (RuntimeException e) {
-                Slog.w(TAG, "Error positioning surface of " + w
-                        + " pos=(" + w.mShownFrame.left
-                        + "," + w.mShownFrame.top + ")", e);
-                if (!recoveringMemory) {
-                    reclaimSomeSurfaceMemoryLocked(w, "position", true);
-                }
-            }
-        }
-
-        if (surfaceResized) {
-            try {
-                if (SHOW_TRANSACTIONS) logSurface(w,
-                        "SIZE " + width + "x" + height, null);
-                w.mSurfaceResized = true;
-                w.mSurface.setSize(width, height);
-            } catch (RuntimeException e) {
-                // If something goes wrong with the surface (such
-                // as running out of memory), don't take down the
-                // entire system.
-                Slog.e(TAG, "Error resizing surface of " + w
-                        + " size=(" + width + "x" + height + ")", e);
-                if (!recoveringMemory) {
-                    reclaimSomeSurfaceMemoryLocked(w, "size", true);
-                }
-            }
-        }
-
-        updateResizingWindows(w);
-
-        if (w.mAttachedHidden || !w.isReadyForDisplay()) {
-            if (!w.mLastHidden) {
-                //dump();
-                w.mLastHidden = true;
-                if (SHOW_TRANSACTIONS) logSurface(w,
-                        "HIDE (performLayout)", null);
-                if (w.mSurface != null) {
-                    w.mSurfaceShown = false;
-                    try {
-                        w.mSurface.hide();
-                    } catch (RuntimeException e) {
-                        Slog.w(TAG, "Exception hiding surface in " + w);
-                    }
-                }
-            }
-            // If we are waiting for this window to handle an
-            // orientation change, well, it is hidden, so
-            // doesn't really matter.  Note that this does
-            // introduce a potential glitch if the window
-            // becomes unhidden before it has drawn for the
-            // new orientation.
-            if (w.mOrientationChanging) {
-                w.mOrientationChanging = false;
-                if (DEBUG_ORIENTATION) Slog.v(TAG,
-                        "Orientation change skips hidden " + w);
-            }
-        } else if (w.mLastLayer != w.mAnimLayer
-                || w.mLastAlpha != w.mShownAlpha
-                || w.mLastDsDx != w.mDsDx
-                || w.mLastDtDx != w.mDtDx
-                || w.mLastDsDy != w.mDsDy
-                || w.mLastDtDy != w.mDtDy
-                || w.mLastHScale != w.mHScale
-                || w.mLastVScale != w.mVScale
-                || w.mLastHidden) {
-            displayed = true;
-            w.mLastAlpha = w.mShownAlpha;
-            w.mLastLayer = w.mAnimLayer;
-            w.mLastDsDx = w.mDsDx;
-            w.mLastDtDx = w.mDtDx;
-            w.mLastDsDy = w.mDsDy;
-            w.mLastDtDy = w.mDtDy;
-            w.mLastHScale = w.mHScale;
-            w.mLastVScale = w.mVScale;
-            if (SHOW_TRANSACTIONS) logSurface(w,
-                    "alpha=" + w.mShownAlpha + " layer=" + w.mAnimLayer
-                    + " matrix=[" + (w.mDsDx*w.mHScale)
-                    + "," + (w.mDtDx*w.mVScale)
-                    + "][" + (w.mDsDy*w.mHScale)
-                    + "," + (w.mDtDy*w.mVScale) + "]", null);
-            if (w.mSurface != null) {
-                try {
-                    w.mSurfaceAlpha = w.mShownAlpha;
-                    w.mSurface.setAlpha(w.mShownAlpha);
-                    w.mSurfaceLayer = w.mAnimLayer;
-                    w.mSurface.setLayer(w.mAnimLayer);
-                    w.mSurface.setMatrix(
-                            w.mDsDx*w.mHScale, w.mDtDx*w.mVScale,
-                            w.mDsDy*w.mHScale, w.mDtDy*w.mVScale);
-                } catch (RuntimeException e) {
-                    Slog.w(TAG, "Error updating surface in " + w, e);
-                    if (!recoveringMemory) {
-                        reclaimSomeSurfaceMemoryLocked(w, "update", true);
-                    }
-                }
-            }
-
-            if (w.mLastHidden && w.isDrawnLw()
-                    && !w.mReadyToShow) {
-                if (SHOW_TRANSACTIONS) logSurface(w,
-                        "SHOW (performLayout)", null);
-                if (DEBUG_VISIBILITY) Slog.v(TAG, "Showing " + w
-                        + " during relayout");
-                if (showSurfaceRobustlyLocked(w)) {
-                    w.mHasDrawn = true;
-                    w.mLastHidden = false;
-                } else {
-                    w.mOrientationChanging = false;
-                }
-            }
-            if (w.mSurface != null) {
-                w.mToken.hasVisible = true;
-            }
-        } else {
-            displayed = true;
-        }
-
-        if (displayed) {
-            if (w.mOrientationChanging) {
-                if (!w.isDrawnLw()) {
-                    mInnerFields.mOrientationChangeComplete = false;
-                    if (DEBUG_ORIENTATION) Slog.v(TAG,
-                            "Orientation continue waiting for draw in " + w);
-                } else {
-                    w.mOrientationChanging = false;
-                    if (DEBUG_ORIENTATION) Slog.v(TAG,
-                            "Orientation change complete in " + w);
-                }
-            }
-            w.mToken.hasVisible = true;
-        }
-    }
-
-    /**
-     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
-     *
      * @param w WindowState this method is applied to.
      * @param currentTime The time which animations use for calculating transitions.
      * @param innerDw Width of app window.
@@ -8649,65 +8114,6 @@
         }
     }
 
-    private final int performAnimationsLocked(long currentTime, int dw, int dh,
-            int innerDw, int innerDh) {
-        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** ANIM STEP: seq="
-                + mTransactionSequence + " mAnimating="
-                + mInnerFields.mAnimating);
-
-        mInnerFields.mTokenMayBeDrawn = false;
-        mInnerFields.mWallpaperMayChange = false;
-        mInnerFields.mForceHiding = false;
-        mInnerFields.mDetachedWallpaper = null;
-        mInnerFields.mWindowAnimationBackground = null;
-        mInnerFields.mWindowAnimationBackgroundColor = 0;
-
-        int changes = updateWindowsAndWallpaperLocked(currentTime, dw, dh, innerDw, innerDh);
-
-        if (mInnerFields.mTokenMayBeDrawn) {
-            changes |= testTokenMayBeDrawnLocked();
-        }
-
-        // If we are ready to perform an app transition, check through
-        // all of the app tokens to be shown and see if they are ready
-        // to go.
-        if (mAppTransitionReady) {
-            changes |= handleAppTransitionReadyLocked();
-        }
-
-        mInnerFields.mAdjResult = 0;
-
-        if (!mInnerFields.mAnimating && mAppTransitionRunning) {
-            // We have finished the animation of an app transition.  To do
-            // this, we have delayed a lot of operations like showing and
-            // hiding apps, moving apps in Z-order, etc.  The app token list
-            // reflects the correct Z-order, but the window list may now
-            // be out of sync with it.  So here we will just rebuild the
-            // entire app window list.  Fun!
-            changes |= handleAnimatingStoppedAndTransitionLocked();
-        }
-
-        if (mInnerFields.mWallpaperForceHidingChanged && changes == 0 && !mAppTransitionReady) {
-            // At this point, there was a window with a wallpaper that
-            // was force hiding other windows behind it, but now it
-            // is going away.  This may be simple -- just animate
-            // away the wallpaper and its window -- or it may be
-            // hard -- the wallpaper now needs to be shown behind
-            // something that was hidden.
-            changes |= animateAwayWallpaperLocked();
-        }
-
-        changes |= testWallpaperAndBackgroundLocked();
-
-        if (mLayoutNeeded) {
-            changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
-        }
-
-        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** ANIM STEP: changes=0x"
-                + Integer.toHexString(changes));
-        return changes;
-    }
-
     // "Something has changed!  Let's make it correct now."
     private final void performLayoutAndPlaceSurfacesLockedInner(
             boolean recoveringMemory) {
@@ -8745,7 +8151,7 @@
         mInnerFields.mScreenBrightness = -1;
         mInnerFields.mButtonBrightness = -1;
         boolean focusDisplayed = false;
-        mInnerFields.mAnimating = false;
+        mAnimator.mAnimating = false;
         boolean createWatermark = false;
 
         if (mFxSession == null) {
@@ -8855,9 +8261,53 @@
             Surface.closeTransaction();
         }
 
+        // If we are ready to perform an app transition, check through
+        // all of the app tokens to be shown and see if they are ready
+        // to go.
+        if (mAppTransitionReady) {
+            mPendingLayoutChanges |= handleAppTransitionReadyLocked();
+        }
+
+        mInnerFields.mAdjResult = 0;
+
+        if (!mAnimator.mAnimating && mAppTransitionRunning) {
+            // We have finished the animation of an app transition.  To do
+            // this, we have delayed a lot of operations like showing and
+            // hiding apps, moving apps in Z-order, etc.  The app token list
+            // reflects the correct Z-order, but the window list may now
+            // be out of sync with it.  So here we will just rebuild the
+            // entire app window list.  Fun!
+            mPendingLayoutChanges |= handleAnimatingStoppedAndTransitionLocked();
+        }
+
+        if (mInnerFields.mWallpaperForceHidingChanged && mPendingLayoutChanges == 0 &&
+                !mAppTransitionReady) {
+            // At this point, there was a window with a wallpaper that
+            // was force hiding other windows behind it, but now it
+            // is going away.  This may be simple -- just animate
+            // away the wallpaper and its window -- or it may be
+            // hard -- the wallpaper now needs to be shown behind
+            // something that was hidden.
+            mPendingLayoutChanges |= animateAwayWallpaperLocked();
+        }
+
+        mPendingLayoutChanges |= testWallpaperAndBackgroundLocked();
+
+        if (mLayoutNeeded) {
+            mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
+        }
+
+        final int N = mWindows.size();
+        for (i=N-1; i>=0; i--) {
+            WindowState w = mWindows.get(i);
+            // TODO(cmautner): Can this move up to the loop at the end of try/catch above?
+            updateResizingWindows(w);
+        }
+
         // Update animations of all applications, including those
         // associated with exiting/removed apps
-        animateAndUpdateSurfaces(currentTime, dw, dh, innerDw, innerDh, recoveringMemory);
+        mAnimator.animate();
+        mPendingLayoutChanges |= mAnimator.mPendingLayoutChanges;
 
         if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
                 "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
@@ -8961,7 +8411,7 @@
 
         boolean needRelayout = false;
 
-        if (!mInnerFields.mAnimating && mAppTransitionRunning) {
+        if (!mAnimator.mAnimating && mAppTransitionRunning) {
             // We have finished the animation of an app transition.  To do
             // this, we have delayed a lot of operations like showing and
             // hiding apps, moving apps in Z-order, etc.  The app token list
@@ -8991,7 +8441,7 @@
         }
         if (needRelayout) {
             requestTraversalLocked();
-        } else if (mInnerFields.mAnimating) {
+        } else if (mAnimator.mAnimating) {
             scheduleAnimationLocked();
         }
 
@@ -9257,6 +8707,7 @@
                 TAG, "Changing focus from " + mCurrentFocus + " to " + newFocus);
             final WindowState oldFocus = mCurrentFocus;
             mCurrentFocus = newFocus;
+            mAnimator.setCurrentFocus(mCurrentFocus);
             mLosingFocus.remove(newFocus);
             int focusChanged = mPolicy.focusChangedLw(oldFocus, newFocus);
 
@@ -9397,16 +8848,16 @@
         }
 
         if (CUSTOM_SCREEN_ROTATION) {
-            if (mScreenRotationAnimation != null) {
-                mScreenRotationAnimation.kill();
-                mScreenRotationAnimation = null;
+            if (mAnimator.mScreenRotationAnimation != null) {
+                mAnimator.mScreenRotationAnimation.kill();
+                mAnimator.mScreenRotationAnimation = null;
             }
-            if (mScreenRotationAnimation == null) {
-                mScreenRotationAnimation = new ScreenRotationAnimation(mContext,
+            if (mAnimator.mScreenRotationAnimation == null) {
+                mAnimator.mScreenRotationAnimation = new ScreenRotationAnimation(mContext,
                         mFxSession, inTransaction, mCurDisplayWidth, mCurDisplayHeight,
                         mDisplay.getRotation());
             }
-            if (!mScreenRotationAnimation.hasScreenshot()) {
+            if (!mAnimator.mScreenRotationAnimation.hasScreenshot()) {
                 Surface.freezeDisplay(0);
             }
         } else {
@@ -9431,20 +8882,20 @@
 
         boolean updateRotation = false;
         
-        if (CUSTOM_SCREEN_ROTATION && mScreenRotationAnimation != null
-                && mScreenRotationAnimation.hasScreenshot()) {
+        if (CUSTOM_SCREEN_ROTATION && mAnimator.mScreenRotationAnimation != null
+                && mAnimator.mScreenRotationAnimation.hasScreenshot()) {
             if (DEBUG_ORIENTATION) Slog.i(TAG, "**** Dismissing screen rotation animation");
-            if (mScreenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
+            if (mAnimator.mScreenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION,
                     mTransitionAnimationScale, mCurDisplayWidth, mCurDisplayHeight)) {
                 scheduleAnimationLocked();
             } else {
-                mScreenRotationAnimation = null;
+                mAnimator.mScreenRotationAnimation = null;
                 updateRotation = true;
             }
         } else {
-            if (mScreenRotationAnimation != null) {
-                mScreenRotationAnimation.kill();
-                mScreenRotationAnimation = null;
+            if (mAnimator.mScreenRotationAnimation != null) {
+                mAnimator.mScreenRotationAnimation.kill();
+                mAnimator.mScreenRotationAnimation = null;
             }
             updateRotation = true;
         }
@@ -9927,9 +9378,9 @@
             pw.print("  mLastWindowForcedOrientation"); pw.print(mLastWindowForcedOrientation);
                     pw.print(" mForcedAppOrientation="); pw.println(mForcedAppOrientation);
             pw.print("  mDeferredRotationPauseCount="); pw.println(mDeferredRotationPauseCount);
-            if (mScreenRotationAnimation != null) {
+            if (mAnimator.mScreenRotationAnimation != null) {
                 pw.println("  mScreenRotationAnimation:");
-                mScreenRotationAnimation.printTo("    ", pw);
+                mAnimator.mScreenRotationAnimation.printTo("    ", pw);
             }
             pw.print("  mWindowAnimationScale="); pw.print(mWindowAnimationScale);
                     pw.print(" mTransitionWindowAnimationScale="); pw.print(mTransitionAnimationScale);
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index d1a14df3..cf61f7f 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -1227,8 +1227,8 @@
             }
         }
 
-        final boolean screenAnimation = mService.mScreenRotationAnimation != null
-                && mService.mScreenRotationAnimation.isAnimating();
+        final boolean screenAnimation = mService.mAnimator.mScreenRotationAnimation != null
+                && mService.mAnimator.mScreenRotationAnimation.isAnimating();
         if (selfTransformation || attachedTransformation != null
                 || appTransformation != null || screenAnimation) {
             // cache often used attributes locally
@@ -1268,7 +1268,7 @@
             }
             if (screenAnimation) {
                 tmpMatrix.postConcat(
-                        mService.mScreenRotationAnimation.getEnterTransformation().getMatrix());
+                        mService.mAnimator.mScreenRotationAnimation.getEnterTransformation().getMatrix());
             }
 
             // "convert" it into SurfaceFlinger's format
@@ -1311,7 +1311,7 @@
                 }
                 if (screenAnimation) {
                     mShownAlpha *=
-                        mService.mScreenRotationAnimation.getEnterTransformation().getAlpha();
+                        mService.mAnimator.mScreenRotationAnimation.getEnterTransformation().getAlpha();
                 }
             } else {
                 //Slog.i(TAG, "Not applying alpha transform");