First separation of animation from AppWindowToken.

New class AppWindowAnimator pulls animation out of AppWindowToken.

Change-Id: Ic1ccb6ec2bf091f1f901fe3c20cbeb242376ae6b
diff --git a/services/java/com/android/server/wm/AppWindowAnimator.java b/services/java/com/android/server/wm/AppWindowAnimator.java
new file mode 100644
index 0000000..6ba4c35
--- /dev/null
+++ b/services/java/com/android/server/wm/AppWindowAnimator.java
@@ -0,0 +1,288 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+
+package com.android.server.wm;
+
+import android.graphics.Matrix;
+import android.util.Slog;
+import android.view.Surface;
+import android.view.WindowManagerPolicy;
+import android.view.animation.Animation;
+import android.view.animation.Transformation;
+
+import java.io.PrintWriter;
+
+/**
+ *
+ */
+public class AppWindowAnimator {
+
+    final AppWindowToken mAppToken;
+    final WindowManagerService mService;
+    final WindowAnimator mAnimator;
+
+    boolean animating;
+    Animation animation;
+    boolean animInitialized;
+    boolean hasTransformation;
+    final Transformation transformation = new Transformation();
+
+    // Have we been asked to have this token keep the screen frozen?
+    // Protect with mAnimator.
+    boolean freezingScreen;
+
+    // Offset to the window of all layers in the token, for use by
+    // AppWindowToken animations.
+    int animLayerAdjustment;
+
+    // Special surface for thumbnail animation.
+    Surface thumbnail;
+    int thumbnailTransactionSeq;
+    int thumbnailX;
+    int thumbnailY;
+    int thumbnailLayer;
+    Animation thumbnailAnimation;
+    final Transformation thumbnailTransformation = new Transformation();
+
+    public AppWindowAnimator(final WindowManagerService service, final AppWindowToken atoken) {
+        mService = service;
+        mAppToken = atoken;
+        mAnimator = service.mAnimator;
+    }
+
+    public void setAnimation(Animation anim, boolean initialized) {
+        if (WindowManagerService.localLOGV) Slog.v(
+            WindowManagerService.TAG, "Setting animation in " + this + ": " + anim);
+        animation = anim;
+        animating = false;
+        animInitialized = initialized;
+        anim.restrictDuration(WindowManagerService.MAX_ANIMATION_DURATION);
+        anim.scaleCurrentDuration(mService.mTransitionAnimationScale);
+        int zorder = anim.getZAdjustment();
+        int adj = 0;
+        if (zorder == Animation.ZORDER_TOP) {
+            adj = WindowManagerService.TYPE_LAYER_OFFSET;
+        } else if (zorder == Animation.ZORDER_BOTTOM) {
+            adj = -WindowManagerService.TYPE_LAYER_OFFSET;
+        }
+
+        if (animLayerAdjustment != adj) {
+            animLayerAdjustment = adj;
+            updateLayers();
+        }
+        // Start out animation gone if window is gone, or visible if window is visible.
+        transformation.clear();
+        transformation.setAlpha(mAppToken.reportedVisible ? 1 : 0);
+        hasTransformation = true;
+    }
+
+    public void setDummyAnimation() {
+        if (animation == null) {
+            if (WindowManagerService.localLOGV) Slog.v(
+                WindowManagerService.TAG, "Setting dummy animation in " + this);
+            animation = WindowManagerService.sDummyAnimation;
+            animInitialized = false;
+        }
+    }
+
+    public void clearAnimation() {
+        if (animation != null) {
+            animation = null;
+            animating = true;
+            animInitialized = false;
+        }
+        clearThumbnail();
+    }
+
+    public void clearThumbnail() {
+        if (thumbnail != null) {
+            thumbnail.destroy();
+            thumbnail = null;
+        }
+    }
+
+    void updateLayers() {
+        final int N = mAppToken.allAppWindows.size();
+        final int adj = animLayerAdjustment;
+        thumbnailLayer = -1;
+        for (int i=0; i<N; i++) {
+            final WindowState w = mAppToken.allAppWindows.get(i);
+            final WindowStateAnimator winAnimator = w.mWinAnimator;
+            winAnimator.mAnimLayer = w.mLayer + adj;
+            if (winAnimator.mAnimLayer > thumbnailLayer) {
+                thumbnailLayer = winAnimator.mAnimLayer;
+            }
+            if (WindowManagerService.DEBUG_LAYERS) Slog.v(WindowManagerService.TAG, "Updating layer " + w + ": "
+                    + winAnimator.mAnimLayer);
+            if (w == mService.mInputMethodTarget && !mService.mInputMethodTargetWaitingAnim) {
+                mService.setInputMethodAnimLayerAdjustment(adj);
+            }
+            if (w == mService.mWallpaperTarget && mService.mLowerWallpaperTarget == null) {
+                mService.setWallpaperAnimLayerAdjustmentLocked(adj);
+            }
+        }
+    }
+
+    private void stepThumbnailAnimation(long currentTime) {
+        thumbnailTransformation.clear();
+        thumbnailAnimation.getTransformation(currentTime, thumbnailTransformation);
+        thumbnailTransformation.getMatrix().preTranslate(thumbnailX, thumbnailY);
+        final boolean screenAnimation = mAnimator.mScreenRotationAnimation != null
+                && mAnimator.mScreenRotationAnimation.isAnimating();
+        if (screenAnimation) {
+            thumbnailTransformation.postCompose(
+                    mAnimator.mScreenRotationAnimation.getEnterTransformation());
+        }
+        // cache often used attributes locally
+        final float tmpFloats[] = mService.mTmpFloats;
+        thumbnailTransformation.getMatrix().getValues(tmpFloats);
+        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) WindowManagerService.logSurface(thumbnail,
+                "thumbnail", "alpha=" + thumbnailTransformation.getAlpha()
+                + " layer=" + thumbnailLayer
+                + " matrix=[" + tmpFloats[Matrix.MSCALE_X]
+                + "," + tmpFloats[Matrix.MSKEW_Y]
+                + "][" + tmpFloats[Matrix.MSKEW_X]
+                + "," + tmpFloats[Matrix.MSCALE_Y] + "]", null);
+        thumbnail.setAlpha(thumbnailTransformation.getAlpha());
+        // The thumbnail is layered below the window immediately above this
+        // token's anim layer.
+        thumbnail.setLayer(thumbnailLayer + WindowManagerService.WINDOW_LAYER_MULTIPLIER
+                - WindowManagerService.LAYER_OFFSET_THUMBNAIL);
+        thumbnail.setMatrix(tmpFloats[Matrix.MSCALE_X], tmpFloats[Matrix.MSKEW_Y],
+                tmpFloats[Matrix.MSKEW_X], tmpFloats[Matrix.MSCALE_Y]);
+    }
+
+    private boolean stepAnimation(long currentTime) {
+        if (animation == null) {
+            return false;
+        }
+        transformation.clear();
+        final boolean more = animation.getTransformation(currentTime, transformation);
+        if (WindowManagerService.DEBUG_ANIM) Slog.v(
+            WindowManagerService.TAG, "Stepped animation in " + this +
+            ": more=" + more + ", xform=" + transformation);
+        if (!more) {
+            animation = null;
+            clearThumbnail();
+            if (WindowManagerService.DEBUG_ANIM) Slog.v(
+                WindowManagerService.TAG, "Finished animation in " + this +
+                " @ " + currentTime);
+        }
+        hasTransformation = more;
+        return more;
+    }
+
+    // This must be called while inside a transaction.
+    boolean stepAnimationLocked(long currentTime, int dw, int dh) {
+        if (mService.okToDisplay()) {
+            // We will run animations as long as the display isn't frozen.
+
+            if (animation == WindowManagerService.sDummyAnimation) {
+                // This guy is going to animate, but not yet.  For now count
+                // it as not animating for purposes of scheduling transactions;
+                // when it is really time to animate, this will be set to
+                // a real animation and the next call will execute normally.
+                return false;
+            }
+
+            if ((mAppToken.allDrawn || animating || mAppToken.startingDisplayed)
+                    && animation != null) {
+                if (!animating) {
+                    if (WindowManagerService.DEBUG_ANIM) Slog.v(
+                        WindowManagerService.TAG, "Starting animation in " + this +
+                        " @ " + currentTime + ": dw=" + dw + " dh=" + dh
+                        + " scale=" + mService.mTransitionAnimationScale
+                        + " allDrawn=" + mAppToken.allDrawn + " animating=" + animating);
+                    if (!animInitialized) {
+                        animation.initialize(dw, dh, dw, dh);
+                    }
+                    animation.setStartTime(currentTime);
+                    animating = true;
+                    if (thumbnail != null) {
+                        thumbnail.show();
+                        thumbnailAnimation.setStartTime(currentTime);
+                    }
+                }
+                if (stepAnimation(currentTime)) {
+                    // animation isn't over, step any thumbnail and that's
+                    // it for now.
+                    if (thumbnail != null) {
+                        stepThumbnailAnimation(currentTime);
+                    }
+                    return true;
+                }
+            }
+        } else if (animation != null) {
+            // If the display is frozen, and there is a pending animation,
+            // clear it and make sure we run the cleanup code.
+            animating = true;
+            animation = null;
+        }
+
+        hasTransformation = false;
+
+        if (!animating) {
+            return false;
+        }
+
+        mAnimator.mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
+        if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
+            mService.debugLayoutRepeats("AppWindowToken", mAnimator.mPendingLayoutChanges);
+        }
+
+        clearAnimation();
+        animating = false;
+        if (animLayerAdjustment != 0) {
+            animLayerAdjustment = 0;
+            updateLayers();
+        }
+        if (mService.mInputMethodTarget != null
+                && mService.mInputMethodTarget.mAppToken == mAppToken) {
+            mService.moveInputMethodWindowsIfNeededLocked(true);
+        }
+
+        if (WindowManagerService.DEBUG_ANIM) Slog.v(
+                WindowManagerService.TAG, "Animation done in " + this
+                + ": reportedVisible=" + mAppToken.reportedVisible);
+
+        transformation.clear();
+
+        final int N = mAppToken.windows.size();
+        for (int i=0; i<N; i++) {
+            mAppToken.windows.get(i).mWinAnimator.finishExit();
+        }
+        mAppToken.updateReportedVisibilityLocked();
+
+        return false;
+    }
+
+    void dump(PrintWriter pw, String prefix) {
+        if (freezingScreen) {
+            pw.print(prefix); pw.print(" freezingScreen="); pw.println(freezingScreen);
+        }
+        if (animating || animation != null) {
+            pw.print(prefix); pw.print("animating="); pw.print(animating);
+                    pw.print(" animation="); pw.println(animation);
+        }
+        if (hasTransformation) {
+            pw.print(prefix); pw.print("XForm: ");
+                    transformation.printShortString(pw);
+                    pw.println();
+        }
+        if (animLayerAdjustment != 0) {
+            pw.print(prefix); pw.print("animLayerAdjustment="); pw.println(animLayerAdjustment);
+        }
+        if (thumbnail != null) {
+            pw.print(prefix); pw.print("thumbnail="); pw.print(thumbnail);
+                    pw.print(" x="); pw.print(thumbnailX);
+                    pw.print(" y="); pw.print(thumbnailY);
+                    pw.print(" layer="); pw.println(thumbnailLayer);
+            pw.print(prefix); pw.print("thumbnailAnimation="); pw.println(thumbnailAnimation);
+            pw.print(prefix); pw.print("thumbnailTransformation=");
+                    pw.println(thumbnailTransformation.toShortString());
+        }
+    }
+}
diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/java/com/android/server/wm/AppWindowToken.java
index 1c43113..e3d46d8 100644
--- a/services/java/com/android/server/wm/AppWindowToken.java
+++ b/services/java/com/android/server/wm/AppWindowToken.java
@@ -21,17 +21,12 @@
 import com.android.server.wm.WindowManagerService.H;
 
 import android.content.pm.ActivityInfo;
-import android.graphics.Matrix;
 import android.os.Message;
 import android.os.RemoteException;
 import android.util.Slog;
 import android.view.IApplicationToken;
-import android.view.Surface;
 import android.view.View;
 import android.view.WindowManager;
-import android.view.WindowManagerPolicy;
-import android.view.animation.Animation;
-import android.view.animation.Transformation;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -47,6 +42,7 @@
     // All of the windows and child windows that are included in this
     // application token.  Note this list is NOT sorted!
     final ArrayList<WindowState> allAppWindows = new ArrayList<WindowState>();
+    final AppWindowAnimator mAppAnimator;
 
     final WindowAnimator mAnimator;
 
@@ -89,20 +85,6 @@
     // Set to true when the token has been removed from the window mgr.
     boolean removed;
 
-    // Have we been asked to have this token keep the screen frozen?
-    // Protect with mAnimator.
-    boolean freezingScreen;
-
-    boolean animating;
-    Animation animation;
-    boolean animInitialized;
-    boolean hasTransformation;
-    final Transformation transformation = new Transformation();
-
-    // Offset to the window of all layers in the token, for use by
-    // AppWindowToken animations.
-    int animLayerAdjustment;
-
     // Information about an application starting window if displayed.
     StartingData startingData;
     WindowState startingWindow;
@@ -111,15 +93,6 @@
     boolean startingMoved;
     boolean firstWindowDrawn;
 
-    // Special surface for thumbnail animation.
-    Surface thumbnail;
-    int thumbnailTransactionSeq;
-    int thumbnailX;
-    int thumbnailY;
-    int thumbnailLayer;
-    Animation thumbnailAnimation;
-    final Transformation thumbnailTransformation = new Transformation();
-
     // Input application handle used by the input dispatcher.
     final InputApplicationHandle mInputApplicationHandle;
 
@@ -130,79 +103,7 @@
         appToken = _token;
         mInputApplicationHandle = new InputApplicationHandle(this);
         mAnimator = service.mAnimator;
-    }
-
-    public void setAnimation(Animation anim, boolean initialized) {
-        if (WindowManagerService.localLOGV) Slog.v(
-            WindowManagerService.TAG, "Setting animation in " + this + ": " + anim);
-        animation = anim;
-        animating = false;
-        animInitialized = initialized;
-        anim.restrictDuration(WindowManagerService.MAX_ANIMATION_DURATION);
-        anim.scaleCurrentDuration(service.mTransitionAnimationScale);
-        int zorder = anim.getZAdjustment();
-        int adj = 0;
-        if (zorder == Animation.ZORDER_TOP) {
-            adj = WindowManagerService.TYPE_LAYER_OFFSET;
-        } else if (zorder == Animation.ZORDER_BOTTOM) {
-            adj = -WindowManagerService.TYPE_LAYER_OFFSET;
-        }
-
-        if (animLayerAdjustment != adj) {
-            animLayerAdjustment = adj;
-            updateLayers();
-        }
-        // Start out animation gone if window is gone, or visible if window is visible.
-        transformation.clear();
-        transformation.setAlpha(reportedVisible ? 1 : 0);
-        hasTransformation = true;
-    }
-
-    public void setDummyAnimation() {
-        if (animation == null) {
-            if (WindowManagerService.localLOGV) Slog.v(
-                WindowManagerService.TAG, "Setting dummy animation in " + this);
-            animation = WindowManagerService.sDummyAnimation;
-            animInitialized = false;
-        }
-    }
-
-    public void clearAnimation() {
-        if (animation != null) {
-            animation = null;
-            animating = true;
-            animInitialized = false;
-        }
-        clearThumbnail();
-    }
-
-    public void clearThumbnail() {
-        if (thumbnail != null) {
-            thumbnail.destroy();
-            thumbnail = null;
-        }
-    }
-
-    void updateLayers() {
-        final int N = allAppWindows.size();
-        final int adj = animLayerAdjustment;
-        thumbnailLayer = -1;
-        for (int i=0; i<N; i++) {
-            final WindowState w = allAppWindows.get(i);
-            final WindowStateAnimator winAnimator = w.mWinAnimator;
-            winAnimator.mAnimLayer = w.mLayer + adj;
-            if (winAnimator.mAnimLayer > thumbnailLayer) {
-                thumbnailLayer = winAnimator.mAnimLayer;
-            }
-            if (WindowManagerService.DEBUG_LAYERS) Slog.v(WindowManagerService.TAG, "Updating layer " + w + ": "
-                    + winAnimator.mAnimLayer);
-            if (w == service.mInputMethodTarget && !service.mInputMethodTargetWaitingAnim) {
-                service.setInputMethodAnimLayerAdjustment(adj);
-            }
-            if (w == service.mWallpaperTarget && service.mLowerWallpaperTarget == null) {
-                service.setWallpaperAnimLayerAdjustmentLocked(adj);
-            }
-        }
+        mAppAnimator = new AppWindowAnimator(_service, this);
     }
 
     void sendAppVisibilityToClients() {
@@ -235,141 +136,6 @@
         return isAnimating;
     }
 
-    private void stepThumbnailAnimation(long currentTime) {
-        thumbnailTransformation.clear();
-        thumbnailAnimation.getTransformation(currentTime, thumbnailTransformation);
-        thumbnailTransformation.getMatrix().preTranslate(thumbnailX, thumbnailY);
-        final boolean screenAnimation = mAnimator.mScreenRotationAnimation != null
-                && mAnimator.mScreenRotationAnimation.isAnimating();
-        if (screenAnimation) {
-            thumbnailTransformation.postCompose(
-                    mAnimator.mScreenRotationAnimation.getEnterTransformation());
-        }
-        // cache often used attributes locally
-        final float tmpFloats[] = service.mTmpFloats;
-        thumbnailTransformation.getMatrix().getValues(tmpFloats);
-        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) WindowManagerService.logSurface(thumbnail,
-                "thumbnail", "alpha=" + thumbnailTransformation.getAlpha()
-                + " layer=" + thumbnailLayer
-                + " matrix=[" + tmpFloats[Matrix.MSCALE_X]
-                + "," + tmpFloats[Matrix.MSKEW_Y]
-                + "][" + tmpFloats[Matrix.MSKEW_X]
-                + "," + tmpFloats[Matrix.MSCALE_Y] + "]", null);
-        thumbnail.setAlpha(thumbnailTransformation.getAlpha());
-        // The thumbnail is layered below the window immediately above this
-        // token's anim layer.
-        thumbnail.setLayer(thumbnailLayer + WindowManagerService.WINDOW_LAYER_MULTIPLIER
-                - WindowManagerService.LAYER_OFFSET_THUMBNAIL);
-        thumbnail.setMatrix(tmpFloats[Matrix.MSCALE_X], tmpFloats[Matrix.MSKEW_Y],
-                tmpFloats[Matrix.MSKEW_X], tmpFloats[Matrix.MSCALE_Y]);
-    }
-
-    private boolean stepAnimation(long currentTime) {
-        if (animation == null) {
-            return false;
-        }
-        transformation.clear();
-        final boolean more = animation.getTransformation(currentTime, transformation);
-        if (WindowManagerService.DEBUG_ANIM) Slog.v(
-            WindowManagerService.TAG, "Stepped animation in " + this +
-            ": more=" + more + ", xform=" + transformation);
-        if (!more) {
-            animation = null;
-            clearThumbnail();
-            if (WindowManagerService.DEBUG_ANIM) Slog.v(
-                WindowManagerService.TAG, "Finished animation in " + this +
-                " @ " + currentTime);
-        }
-        hasTransformation = more;
-        return more;
-    }
-
-    // This must be called while inside a transaction.
-    boolean stepAnimationLocked(long currentTime, int dw, int dh) {
-        if (service.okToDisplay()) {
-            // We will run animations as long as the display isn't frozen.
-
-            if (animation == WindowManagerService.sDummyAnimation) {
-                // This guy is going to animate, but not yet.  For now count
-                // it as not animating for purposes of scheduling transactions;
-                // when it is really time to animate, this will be set to
-                // a real animation and the next call will execute normally.
-                return false;
-            }
-
-            if ((allDrawn || animating || startingDisplayed) && animation != null) {
-                if (!animating) {
-                    if (WindowManagerService.DEBUG_ANIM) Slog.v(
-                        WindowManagerService.TAG, "Starting animation in " + this +
-                        " @ " + currentTime + ": dw=" + dw + " dh=" + dh
-                        + " scale=" + service.mTransitionAnimationScale
-                        + " allDrawn=" + allDrawn + " animating=" + animating);
-                    if (!animInitialized) {
-                        animation.initialize(dw, dh, dw, dh);
-                    }
-                    animation.setStartTime(currentTime);
-                    animating = true;
-                    if (thumbnail != null) {
-                        thumbnail.show();
-                        thumbnailAnimation.setStartTime(currentTime);
-                    }
-                }
-                if (stepAnimation(currentTime)) {
-                    // animation isn't over, step any thumbnail and that's
-                    // it for now.
-                    if (thumbnail != null) {
-                        stepThumbnailAnimation(currentTime);
-                    }
-                    return true;
-                }
-            }
-        } else if (animation != null) {
-            // If the display is frozen, and there is a pending animation,
-            // clear it and make sure we run the cleanup code.
-            animating = true;
-            animation = null;
-        }
-
-        hasTransformation = false;
-
-        if (!animating) {
-            return false;
-        }
-
-        mAnimator.mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
-        if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
-            service.debugLayoutRepeats("AppWindowToken", mAnimator.mPendingLayoutChanges);
-        }
-
-        clearAnimation();
-        animating = false;
-        if (animLayerAdjustment != 0) {
-            animLayerAdjustment = 0;
-            updateLayers();
-        }
-        if (service.mInputMethodTarget != null && service.mInputMethodTarget.mAppToken == this) {
-            service.moveInputMethodWindowsIfNeededLocked(true);
-        }
-
-        if (WindowManagerService.DEBUG_ANIM) Slog.v(
-                WindowManagerService.TAG, "Animation done in " + this
-                + ": reportedVisible=" + reportedVisible);
-
-        transformation.clear();
-
-        final int N = windows.size();
-        for (int i=0; i<N; i++) {
-            windows.get(i).mWinAnimator.finishExit();
-        }
-        updateReportedVisibilityLocked();
-
-        return false;
-    }
-
     void updateReportedVisibilityLocked() {
         if (appToken == null) {
             return;
@@ -483,9 +249,8 @@
                 pw.print(" willBeHidden="); pw.print(willBeHidden);
                 pw.print(" reportedDrawn="); pw.print(reportedDrawn);
                 pw.print(" reportedVisible="); pw.println(reportedVisible);
-        if (paused || freezingScreen) {
-            pw.print(prefix); pw.print("paused="); pw.print(paused);
-                    pw.print(" freezingScreen="); pw.println(freezingScreen);
+        if (paused) {
+            pw.print(prefix); pw.print("paused="); pw.println(paused);
         }
         if (numInterestingWindows != 0 || numDrawnWindows != 0
                 || inPendingTransaction || allDrawn) {
@@ -495,18 +260,6 @@
                     pw.print(" inPendingTransaction="); pw.print(inPendingTransaction);
                     pw.print(" allDrawn="); pw.println(allDrawn);
         }
-        if (animating || animation != null) {
-            pw.print(prefix); pw.print("animating="); pw.print(animating);
-                    pw.print(" animation="); pw.println(animation);
-        }
-        if (hasTransformation) {
-            pw.print(prefix); pw.print("XForm: ");
-                    transformation.printShortString(pw);
-                    pw.println();
-        }
-        if (animLayerAdjustment != 0) {
-            pw.print(prefix); pw.print("animLayerAdjustment="); pw.println(animLayerAdjustment);
-        }
         if (startingData != null || removed || firstWindowDrawn) {
             pw.print(prefix); pw.print("startingData="); pw.print(startingData);
                     pw.print(" removed="); pw.print(removed);
@@ -519,15 +272,6 @@
                     pw.print(" startingDisplayed="); pw.print(startingDisplayed);
                     pw.print(" startingMoved"); pw.println(startingMoved);
         }
-        if (thumbnail != null) {
-            pw.print(prefix); pw.print("thumbnail="); pw.print(thumbnail);
-                    pw.print(" x="); pw.print(thumbnailX);
-                    pw.print(" y="); pw.print(thumbnailY);
-                    pw.print(" layer="); pw.println(thumbnailLayer);
-            pw.print(prefix); pw.print("thumbnailAnimation="); pw.println(thumbnailAnimation);
-            pw.print(prefix); pw.print("thumbnailTransformation=");
-                    pw.println(thumbnailTransformation.toShortString());
-        }
     }
 
     @Override
diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java
index 722776c..77f94d9 100644
--- a/services/java/com/android/server/wm/WindowAnimator.java
+++ b/services/java/com/android/server/wm/WindowAnimator.java
@@ -24,7 +24,6 @@
 import java.io.PrintWriter;
 
 /**
- * @author cmautner@google.com (Craig Mautner)
  * Singleton class that carries out the animations and Surface operations in a separate task
  * on behalf of WindowManagerService.
  */
@@ -123,16 +122,16 @@
         int i;
         final int NAT = mService.mAppTokens.size();
         for (i=0; i<NAT; i++) {
-            final AppWindowToken appToken = mService.mAppTokens.get(i);
-            final boolean wasAnimating = appToken.animation != null
-                    && appToken.animation != WindowManagerService.sDummyAnimation;
-            if (appToken.stepAnimationLocked(mCurrentTime, mInnerDw, mInnerDh)) {
+            final AppWindowAnimator appAnimator = mService.mAppTokens.get(i).mAppAnimator;
+            final boolean wasAnimating = appAnimator.animation != null
+                    && appAnimator.animation != WindowManagerService.sDummyAnimation;
+            if (appAnimator.stepAnimationLocked(mCurrentTime, mInnerDw, mInnerDh)) {
                 mAnimating = true;
             } else if (wasAnimating) {
                 // stopped animating, do one more pass through the layout
                 mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
                 if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
-                    mService.debugLayoutRepeats("appToken " + appToken + " done",
+                    mService.debugLayoutRepeats("appToken " + appAnimator.mAppToken + " done",
                         mPendingLayoutChanges);
                 }
             }
@@ -140,17 +139,17 @@
 
         final int NEAT = mService.mExitingAppTokens.size();
         for (i=0; i<NEAT; i++) {
-            final AppWindowToken appToken = mService.mExitingAppTokens.get(i);
-            final boolean wasAnimating = appToken.animation != null
-                    && appToken.animation != WindowManagerService.sDummyAnimation;
-            if (appToken.stepAnimationLocked(mCurrentTime, mInnerDw, mInnerDh)) {
+            final AppWindowAnimator appAnimator = mService.mAppTokens.get(i).mAppAnimator;
+            final boolean wasAnimating = appAnimator.animation != null
+                    && appAnimator.animation != WindowManagerService.sDummyAnimation;
+            if (appAnimator.stepAnimationLocked(mCurrentTime, mInnerDw, mInnerDh)) {
                 mAnimating = true;
             } else if (wasAnimating) {
                 // stopped animating, do one more pass through the layout
                 mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
                 if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
-                    mService.debugLayoutRepeats("exiting appToken " + appToken + " done",
-                        mPendingLayoutChanges);
+                    mService.debugLayoutRepeats("exiting appToken " + appAnimator.mAppToken 
+                        + " done", mPendingLayoutChanges);
                 }
             }
         }
@@ -210,13 +209,15 @@
                 // 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) {
+                final AppWindowAnimator appAnimator =
+                        w.mAppToken == null ? null : w.mAppToken.mAppAnimator;
+                if (appAnimator != null && appAnimator.animation != null
+                        && appAnimator.animating) {
                     if ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0
-                            && w.mAppToken.animation.getDetachWallpaper()) {
+                            && appAnimator.animation.getDetachWallpaper()) {
                         mDetachedWallpaper = w;
                     }
-                    final int backgroundColor = w.mAppToken.animation.getBackgroundColor();
+                    final int backgroundColor = appAnimator.animation.getBackgroundColor();
                     if (backgroundColor != 0) {
                         if (mWindowAnimationBackground == null
                                 || (winAnimator.mAnimLayer <
@@ -294,7 +295,7 @@
             }
 
             final AppWindowToken atoken = w.mAppToken;
-            if (atoken != null && (!atoken.allDrawn || atoken.freezingScreen)) {
+            if (atoken != null && (!atoken.allDrawn || atoken.mAppAnimator.freezingScreen)) {
                 if (atoken.lastTransactionSequence != mTransactionSequence) {
                     atoken.lastTransactionSequence = mTransactionSequence;
                     atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
@@ -318,14 +319,14 @@
                         }
                     }
                     if (w != atoken.startingWindow) {
-                        if (!atoken.freezingScreen || !w.mAppFreezing) {
+                        if (!atoken.mAppAnimator.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
+                                        + " freezingScreen=" + atoken.mAppAnimator.freezingScreen
                                         + " mAppFreezing=" + w.mAppFreezing);
                                 mTokenMayBeDrawn = true;
                             }
@@ -343,13 +344,15 @@
                     }
                 }
             }
-            if (atoken != null && atoken.thumbnail != null) {
-                if (atoken.thumbnailTransactionSeq != mTransactionSequence) {
-                    atoken.thumbnailTransactionSeq = mTransactionSequence;
-                    atoken.thumbnailLayer = 0;
+            final AppWindowAnimator appAnimator =
+                    atoken == null ? null : atoken.mAppAnimator;
+            if (appAnimator != null && appAnimator.thumbnail != null) {
+                if (appAnimator.thumbnailTransactionSeq != mTransactionSequence) {
+                    appAnimator.thumbnailTransactionSeq = mTransactionSequence;
+                    appAnimator.thumbnailLayer = 0;
                 }
-                if (atoken.thumbnailLayer < winAnimator.mAnimLayer) {
-                    atoken.thumbnailLayer = winAnimator.mAnimLayer;
+                if (appAnimator.thumbnailLayer < winAnimator.mAnimLayer) {
+                    appAnimator.thumbnailLayer = winAnimator.mAnimLayer;
                 }
             }
         } // end forall windows
@@ -361,7 +364,7 @@
         final int NT = mService.mAppTokens.size();
         for (int i=0; i<NT; i++) {
             AppWindowToken wtoken = mService.mAppTokens.get(i);
-            if (wtoken.freezingScreen) {
+            if (wtoken.mAppAnimator.freezingScreen) {
                 int numInteresting = wtoken.numInterestingWindows;
                 if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
                     if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index b6ef37b..7eca401 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -1265,7 +1265,7 @@
                 AppWindowToken token = curTarget.mAppToken;
                 WindowState highestTarget = null;
                 int highestPos = 0;
-                if (token.animating || token.animation != null) {
+                if (token.mAppAnimator.animating || token.mAppAnimator.animation != null) {
                     int pos = localmWindows.indexOf(curTarget);
                     while (pos >= 0) {
                         WindowState win = localmWindows.get(pos);
@@ -1325,7 +1325,7 @@
                 mInputMethodTarget = w;
                 mInputMethodTargetWaitingAnim = false;
                 if (w.mAppToken != null) {
-                    setInputMethodAnimLayerAdjustment(w.mAppToken.animLayerAdjustment);
+                    setInputMethodAnimLayerAdjustment(w.mAppToken.mAppAnimator.animLayerAdjustment);
                 } else {
                     setInputMethodAnimLayerAdjustment(0);
                 }
@@ -1588,12 +1588,12 @@
         if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper vis: target " + wallpaperTarget + ", obscured="
                 + (wallpaperTarget != null ? Boolean.toString(wallpaperTarget.mObscured) : "??")
                 + " anim=" + ((wallpaperTarget != null && wallpaperTarget.mAppToken != null)
-                        ? wallpaperTarget.mAppToken.animation : null)
+                        ? wallpaperTarget.mAppToken.mAppAnimator.animation : null)
                 + " upper=" + mUpperWallpaperTarget
                 + " lower=" + mLowerWallpaperTarget);
         return (wallpaperTarget != null
                         && (!wallpaperTarget.mObscured || (wallpaperTarget.mAppToken != null
-                                && wallpaperTarget.mAppToken.animation != null)))
+                                && wallpaperTarget.mAppToken.mAppAnimator.animation != null)))
                 || mUpperWallpaperTarget != null
                 || mLowerWallpaperTarget != null;
     }
@@ -1633,7 +1633,7 @@
             if (w != mAnimator.mWindowDetachedWallpaper && w.mAppToken != null) {
                 // If this window's app token is hidden and not animating,
                 // it is of no interest to us.
-                if (w.mAppToken.hidden && w.mAppToken.animation == null) {
+                if (w.mAppToken.hidden && w.mAppToken.mAppAnimator.animation == null) {
                     if (DEBUG_WALLPAPER) Slog.v(TAG,
                             "Skipping not hidden or animating token: " + w);
                     continue;
@@ -1648,7 +1648,7 @@
                 foundW = w;
                 foundI = i;
                 if (w == mWallpaperTarget && ((w.mAppToken != null
-                        && w.mAppToken.animation != null)
+                        && w.mAppToken.mAppAnimator.animation != null)
                         || w.mWinAnimator.mAnimation != null)) {
                     // The current wallpaper target is animating, so we'll
                     // look behind it for another possible target and figure
@@ -1707,9 +1707,11 @@
             // animating, then we are in our super special mode!
             if (foundW != null && oldW != null) {
                 boolean oldAnim = oldW.mWinAnimator.mAnimation != null
-                        || (oldW.mAppToken != null && oldW.mAppToken.animation != null);
+                        || (oldW.mAppToken != null
+                            && oldW.mAppToken.mAppAnimator.animation != null);
                 boolean foundAnim = foundW.mWinAnimator.mAnimation != null
-                        || (foundW.mAppToken != null && foundW.mAppToken.animation != null);
+                        || (foundW.mAppToken != null &&
+                            foundW.mAppToken.mAppAnimator.animation != null);
                 if (DEBUG_WALLPAPER) {
                     Slog.v(TAG, "New animation: " + foundAnim
                             + " old animation: " + oldAnim);
@@ -1762,10 +1764,10 @@
             // Is it time to stop animating?
             boolean lowerAnimating = mLowerWallpaperTarget.mWinAnimator.mAnimation != null
                     || (mLowerWallpaperTarget.mAppToken != null
-                            && mLowerWallpaperTarget.mAppToken.animation != null);
+                            && mLowerWallpaperTarget.mAppToken.mAppAnimator.animation != null);
             boolean upperAnimating = mUpperWallpaperTarget.mWinAnimator.mAnimation != null
                     || (mUpperWallpaperTarget.mAppToken != null
-                            && mUpperWallpaperTarget.mAppToken.animation != null);
+                            && mUpperWallpaperTarget.mAppToken.mAppAnimator.animation != null);
             if (!lowerAnimating || !upperAnimating) {
                 if (DEBUG_WALLPAPER) {
                     Slog.v(TAG, "No longer animating wallpaper targets!");
@@ -1787,7 +1789,7 @@
             // between two wallpaper targets.
             mWallpaperAnimLayerAdjustment =
                     (mLowerWallpaperTarget == null && foundW.mAppToken != null)
-                    ? foundW.mAppToken.animLayerAdjustment : 0;
+                    ? foundW.mAppToken.mAppAnimator.animLayerAdjustment : 0;
 
             final int maxLayer = mPolicy.getMaxWallpaperLayer()
                     * TYPE_LAYER_MULTIPLIER
@@ -2358,7 +2360,7 @@
                 + " mExiting=" + win.mExiting
                 + " isAnimating=" + win.mWinAnimator.isAnimating()
                 + " app-animation="
-                + (win.mAppToken != null ? win.mAppToken.animation : null)
+                + (win.mAppToken != null ? win.mAppToken.mAppAnimator.animation : null)
                 + " inPendingTransaction="
                 + (win.mAppToken != null ? win.mAppToken.inPendingTransaction : false)
                 + " mDisplayFrozen=" + mDisplayFrozen);
@@ -3226,13 +3228,13 @@
                     }
                     Slog.v(TAG, "Loaded animation " + a + " for " + wtoken, e);
                 }
-                wtoken.setAnimation(a, initialized);
+                wtoken.mAppAnimator.setAnimation(a, initialized);
             }
         } else {
-            wtoken.clearAnimation();
+            wtoken.mAppAnimator.clearAnimation();
         }
 
-        return wtoken.animation != null;
+        return wtoken.mAppAnimator.animation != null;
     }
 
     // -------------------------------------------------------------
@@ -3880,14 +3882,16 @@
                             wtoken.clientHidden = ttoken.clientHidden;
                             wtoken.sendAppVisibilityToClients();
                         }
-                        if (ttoken.animation != null) {
-                            wtoken.animation = ttoken.animation;
-                            wtoken.animating = ttoken.animating;
-                            wtoken.animLayerAdjustment = ttoken.animLayerAdjustment;
-                            ttoken.animation = null;
-                            ttoken.animLayerAdjustment = 0;
-                            wtoken.updateLayers();
-                            ttoken.updateLayers();
+                        final AppWindowAnimator tAppAnimator = ttoken.mAppAnimator;
+                        final AppWindowAnimator wAppAnimator = wtoken.mAppAnimator;
+                        if (tAppAnimator.animation != null) {
+                            wAppAnimator.animation = tAppAnimator.animation;
+                            wAppAnimator.animating = tAppAnimator.animating;
+                            wAppAnimator.animLayerAdjustment = tAppAnimator.animLayerAdjustment;
+                            tAppAnimator.animation = null;
+                            tAppAnimator.animLayerAdjustment = 0;
+                            wAppAnimator.updateLayers();
+                            tAppAnimator.updateLayers();
                         }
 
                         updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
@@ -3912,18 +3916,20 @@
                         mH.sendMessageAtFrontOfQueue(m);
                         return;
                     }
-                    if (ttoken.thumbnail != null) {
+                    final AppWindowAnimator tAppAnimator = ttoken.mAppAnimator;
+                    final AppWindowAnimator wAppAnimator = wtoken.mAppAnimator;
+                    if (tAppAnimator.thumbnail != null) {
                         // The old token is animating with a thumbnail, transfer
                         // that to the new token.
-                        if (wtoken.thumbnail != null) {
-                            wtoken.thumbnail.destroy();
+                        if (wAppAnimator.thumbnail != null) {
+                            wAppAnimator.thumbnail.destroy();
                         }
-                        wtoken.thumbnail = ttoken.thumbnail;
-                        wtoken.thumbnailX = ttoken.thumbnailX;
-                        wtoken.thumbnailY = ttoken.thumbnailY;
-                        wtoken.thumbnailLayer = ttoken.thumbnailLayer;
-                        wtoken.thumbnailAnimation = ttoken.thumbnailAnimation;
-                        ttoken.thumbnail = null;
+                        wAppAnimator.thumbnail = tAppAnimator.thumbnail;
+                        wAppAnimator.thumbnailX = tAppAnimator.thumbnailX;
+                        wAppAnimator.thumbnailY = tAppAnimator.thumbnailY;
+                        wAppAnimator.thumbnailLayer = tAppAnimator.thumbnailLayer;
+                        wAppAnimator.thumbnailAnimation = tAppAnimator.thumbnailAnimation;
+                        tAppAnimator.thumbnail = null;
                     }
                 }
             }
@@ -4013,12 +4019,12 @@
             boolean runningAppAnimation = false;
 
             if (transit != WindowManagerPolicy.TRANSIT_UNSET) {
-                if (wtoken.animation == sDummyAnimation) {
-                    wtoken.animation = null;
+                if (wtoken.mAppAnimator.animation == sDummyAnimation) {
+                    wtoken.mAppAnimator.animation = null;
                 }
                 applyAnimationLocked(wtoken, lp, transit, visible);
                 changed = true;
-                if (wtoken.animation != null) {
+                if (wtoken.mAppAnimator.animation != null) {
                     delayed = runningAppAnimation = true;
                 }
             }
@@ -4081,7 +4087,7 @@
             }
         }
 
-        if (wtoken.animation != null) {
+        if (wtoken.mAppAnimator.animation != null) {
             delayed = true;
         }
 
@@ -4126,7 +4132,7 @@
 
                 if (DEBUG_APP_TRANSITIONS) Slog.v(
                         TAG, "Setting dummy animation on: " + wtoken);
-                wtoken.setDummyAnimation();
+                wtoken.mAppAnimator.setDummyAnimation();
                 mOpeningApps.remove(wtoken);
                 mClosingApps.remove(wtoken);
                 wtoken.waitingToShow = wtoken.waitingToHide = false;
@@ -4176,7 +4182,7 @@
 
     void unsetAppFreezingScreenLocked(AppWindowToken wtoken,
             boolean unfreezeSurfaceNow, boolean force) {
-        if (wtoken.freezingScreen) {
+        if (wtoken.mAppAnimator.freezingScreen) {
             if (DEBUG_ORIENTATION) Slog.v(TAG, "Clear freezing of " + wtoken
                     + " force=" + force);
             final int N = wtoken.allAppWindows.size();
@@ -4194,7 +4200,7 @@
             }
             if (force || unfrozeWindows) {
                 if (DEBUG_ORIENTATION) Slog.v(TAG, "No longer freezing: " + wtoken);
-                wtoken.freezingScreen = false;
+                wtoken.mAppAnimator.freezingScreen = false;
                 mAppsFreezingScreen--;
             }
             if (unfreezeSurfaceNow) {
@@ -4217,11 +4223,11 @@
             }
             Slog.i(TAG, "Set freezing of " + wtoken.appToken
                     + ": hidden=" + wtoken.hidden + " freezing="
-                    + wtoken.freezingScreen, e);
+                    + wtoken.mAppAnimator.freezingScreen, e);
         }
         if (!wtoken.hiddenRequested) {
-            if (!wtoken.freezingScreen) {
-                wtoken.freezingScreen = true;
+            if (!wtoken.mAppAnimator.freezingScreen) {
+                wtoken.mAppAnimator.freezingScreen = true;
                 mAppsFreezingScreen++;
                 if (mAppsFreezingScreen == 1) {
                     startFreezingDisplayLocked(false);
@@ -4274,7 +4280,7 @@
             }
             final long origId = Binder.clearCallingIdentity();
             if (DEBUG_ORIENTATION) Slog.v(TAG, "Clear freezing of " + token
-                    + ": hidden=" + wtoken.hidden + " freezing=" + wtoken.freezingScreen);
+                    + ": hidden=" + wtoken.hidden + " freezing=" + wtoken.mAppAnimator.freezingScreen);
             unsetAppFreezingScreenLocked(wtoken, true, force);
             Binder.restoreCallingIdentity(origId);
         }
@@ -4309,8 +4315,8 @@
                 }
                 if (DEBUG_APP_TRANSITIONS) Slog.v(
                         TAG, "Removing app " + wtoken + " delayed=" + delayed
-                        + " animation=" + wtoken.animation
-                        + " animating=" + wtoken.animating);
+                        + " animation=" + wtoken.mAppAnimator.animation
+                        + " animating=" + wtoken.mAppAnimator.animating);
                 if (delayed) {
                     // set the token aside because it has an active animation to be finished
                     if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
@@ -4320,9 +4326,8 @@
                     // Make sure there is no animation running on this token,
                     // so any windows associated with it will be removed as
                     // soon as their animations are complete
-                    wtoken.clearAnimation();
-                    wtoken.animation = null;
-                    wtoken.animating = false;
+                    wtoken.mAppAnimator.clearAnimation();
+                    wtoken.mAppAnimator.animating = false;
                 }
                 if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
                         "removeAppToken: " + wtoken);
@@ -7039,7 +7044,7 @@
                             while (i > 0) {
                                 i--;
                                 AppWindowToken tok = mAppTokens.get(i);
-                                if (tok.freezingScreen) {
+                                if (tok.mAppAnimator.freezingScreen) {
                                     Slog.w(TAG, "Force clearing freeze: " + tok);
                                     unsetAppFreezingScreenLocked(tok, true, true);
                                 }
@@ -7525,9 +7530,11 @@
                 w.mLayer = curLayer;
             }
             if (w.mTargetAppToken != null) {
-                w.mWinAnimator.mAnimLayer = w.mLayer + w.mTargetAppToken.animLayerAdjustment;
+                w.mWinAnimator.mAnimLayer =
+                        w.mLayer + w.mTargetAppToken.mAppAnimator.animLayerAdjustment;
             } else if (w.mAppToken != null) {
-                w.mWinAnimator.mAnimLayer = w.mLayer + w.mAppToken.animLayerAdjustment;
+                w.mWinAnimator.mAnimLayer =
+                        w.mLayer + w.mAppToken.mAppAnimator.animLayerAdjustment;
             } else {
                 w.mWinAnimator.mAnimLayer = w.mLayer;
             }
@@ -7961,10 +7968,10 @@
                 AppWindowToken wtoken = mOpeningApps.get(i);
                 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
                         "Now opening app" + wtoken);
-                wtoken.clearThumbnail();
+                wtoken.mAppAnimator.clearThumbnail();
                 wtoken.reportedVisible = false;
                 wtoken.inPendingTransaction = false;
-                wtoken.animation = null;
+                wtoken.mAppAnimator.animation = null;
                 setTokenVisibilityLocked(wtoken, animLp, true,
                         transit, false);
                 wtoken.updateReportedVisibilityLocked();
@@ -7989,9 +7996,9 @@
                 AppWindowToken wtoken = mClosingApps.get(i);
                 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
                         "Now closing app" + wtoken);
-                wtoken.clearThumbnail();
+                wtoken.mAppAnimator.clearThumbnail();
                 wtoken.inPendingTransaction = false;
-                wtoken.animation = null;
+                wtoken.mAppAnimator.animation = null;
                 setTokenVisibilityLocked(wtoken, animLp, false,
                         transit, false);
                 wtoken.updateReportedVisibilityLocked();
@@ -8003,7 +8010,7 @@
             }
 
             if (mNextAppTransitionThumbnail != null && topOpeningApp != null
-                    && topOpeningApp.animation != null) {
+                    && topOpeningApp.mAppAnimator.animation != null) {
                 // This thumbnail animation is very special, we need to have
                 // an extra surface with the thumbnail included with the animation.
                 Rect dirty = new Rect(0, 0, mNextAppTransitionThumbnail.getWidth(),
@@ -8012,7 +8019,7 @@
                     Surface surface = new Surface(mFxSession, Process.myPid(),
                             "thumbnail anim", 0, dirty.width(), dirty.height(),
                             PixelFormat.TRANSLUCENT, Surface.HIDDEN);
-                    topOpeningApp.thumbnail = surface;
+                    topOpeningApp.mAppAnimator.thumbnail = surface;
                     if (SHOW_TRANSACTIONS) Slog.i(TAG, "  THUMBNAIL "
                             + surface + ": CREATE");
                     Surface drawSurface = new Surface();
@@ -8021,17 +8028,17 @@
                     c.drawBitmap(mNextAppTransitionThumbnail, 0, 0, null);
                     drawSurface.unlockCanvasAndPost(c);
                     drawSurface.release();
-                    topOpeningApp.thumbnailLayer = topOpeningLayer;
+                    topOpeningApp.mAppAnimator.thumbnailLayer = topOpeningLayer;
                     Animation anim = createThumbnailAnimationLocked(transit, true, true);
-                    topOpeningApp.thumbnailAnimation = anim;
+                    topOpeningApp.mAppAnimator.thumbnailAnimation = anim;
                     anim.restrictDuration(MAX_ANIMATION_DURATION);
                     anim.scaleCurrentDuration(mTransitionAnimationScale);
-                    topOpeningApp.thumbnailX = mNextAppTransitionStartX;
-                    topOpeningApp.thumbnailY = mNextAppTransitionStartY;
+                    topOpeningApp.mAppAnimator.thumbnailX = mNextAppTransitionStartX;
+                    topOpeningApp.mAppAnimator.thumbnailY = mNextAppTransitionStartY;
                 } catch (Surface.OutOfResourcesException e) {
                     Slog.e(TAG, "Can't allocate thumbnail surface w=" + dirty.width()
                             + " h=" + dirty.height(), e);
-                    topOpeningApp.clearThumbnail();
+                    topOpeningApp.mAppAnimator.clearThumbnail();
                 }
             }
 
@@ -8632,9 +8639,8 @@
                 // Make sure there is no animation running on this token,
                 // so any windows associated with it will be removed as
                 // soon as their animations are complete
-                token.clearAnimation();
-                token.animation = null;
-                token.animating = false;
+                token.mAppAnimator.clearAnimation();
+                token.mAppAnimator.animating = false;
                 if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
                         "performLayout: App token exiting now removed" + token);
                 mAppTokens.remove(token);
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index 8a17a87..05797a4 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -624,7 +624,7 @@
         }
         final AppWindowToken atoken = mAppToken;
         final boolean animating = atoken != null
-                ? (atoken.animation != null) : false;
+                ? (atoken.mAppAnimator.animation != null) : false;
         return mHasSurface && !mDestroying && !mExiting
                 && (atoken == null ? mPolicyVisibility : !atoken.hiddenRequested)
                 && ((!mAttachedHidden && mViewVisibility == View.VISIBLE
@@ -640,7 +640,7 @@
     public boolean isWinVisibleLw() {
         final AppWindowToken atoken = mAppToken;
         return mHasSurface && mPolicyVisibility && !mAttachedHidden
-                && (atoken == null || !atoken.hiddenRequested || atoken.animating)
+                && (atoken == null || !atoken.hiddenRequested || atoken.mAppAnimator.animating)
                 && !mExiting && !mDestroying;
     }
 
@@ -688,7 +688,7 @@
         final AppWindowToken atoken = mAppToken;
         if (atoken != null) {
             return ((!mAttachedHidden && !atoken.hiddenRequested)
-                            || mWinAnimator.mAnimation != null || atoken.animation != null);
+                            || mWinAnimator.mAnimation != null || atoken.mAppAnimator.animation != null);
         }
         return !mAttachedHidden || mWinAnimator.mAnimation != null;
     }
@@ -706,7 +706,7 @@
                 && ((!mAttachedHidden && mViewVisibility == View.VISIBLE
                                 && !mRootToken.hidden)
                         || mWinAnimator.mAnimation != null
-                        || ((mAppToken != null) && (mAppToken.animation != null)));
+                        || ((mAppToken != null) && (mAppToken.mAppAnimator.animation != null)));
     }
 
     /**
@@ -749,7 +749,7 @@
         return (mAttrs.format == PixelFormat.OPAQUE
                         || mAttrs.type == TYPE_WALLPAPER)
                 && isDrawnLw() && mWinAnimator.mAnimation == null
-                && (mAppToken == null || mAppToken.animation == null);
+                && (mAppToken == null || mAppToken.mAppAnimator.animation == null);
     }
 
     /**
@@ -965,8 +965,9 @@
             pw.print(prefix); pw.print("mBaseLayer="); pw.print(mBaseLayer);
                     pw.print(" mSubLayer="); pw.print(mSubLayer);
                     pw.print(" mAnimLayer="); pw.print(mLayer); pw.print("+");
-                    pw.print((mTargetAppToken != null ? mTargetAppToken.animLayerAdjustment
-                          : (mAppToken != null ? mAppToken.animLayerAdjustment : 0)));
+                    pw.print((mTargetAppToken != null ?
+                            mTargetAppToken.mAppAnimator.animLayerAdjustment
+                          : (mAppToken != null ? mAppToken.mAppAnimator.animLayerAdjustment : 0)));
                     pw.print("="); pw.print(mWinAnimator.mAnimLayer);
                     pw.print(" mLastLayer="); pw.println(mWinAnimator.mLastLayer);
         }
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index 0dec5b2..6d0921e 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -162,7 +162,7 @@
         return mAnimation != null
                 || (attached != null && attached.mWinAnimator.mAnimation != null)
                 || (atoken != null &&
-                        (atoken.animation != null
+                        (atoken.mAppAnimator.animation != null
                                 || atoken.inPendingTransaction));
     }
 
@@ -228,7 +228,7 @@
             }
             mHasLocalTransformation = false;
             if ((!mLocalAnimating || mAnimationIsEntrance) && mWin.mAppToken != null
-                    && mWin.mAppToken.animation != null) {
+                    && mWin.mAppToken.mAppAnimator.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
@@ -616,9 +616,10 @@
         Transformation attachedTransformation =
                 (mAttachedWindow != null && mAttachedWindow.mWinAnimator.mHasLocalTransformation)
                 ? mAttachedWindow.mWinAnimator.mTransformation : null;
-        Transformation appTransformation =
-                (mWin.mAppToken != null && mWin.mAppToken.hasTransformation)
-                ? mWin.mAppToken.transformation : null;
+        final AppWindowAnimator appAnimator =
+                mWin.mAppToken == null ? null : mWin.mAppToken.mAppAnimator;
+        Transformation appTransformation = (appAnimator != null && appAnimator.hasTransformation)
+                ? appAnimator.transformation : null;
 
         // Wallpapers are animated based on the "real" window they
         // are currently targeting.
@@ -632,11 +633,13 @@
                     Slog.v(TAG, "WP target attached xform: " + attachedTransformation);
                 }
             }
-            if (mService.mWallpaperTarget.mAppToken != null &&
-                    mService.mWallpaperTarget.mAppToken.hasTransformation &&
-                    mService.mWallpaperTarget.mAppToken.animation != null &&
-                    !mService.mWallpaperTarget.mAppToken.animation.getDetachWallpaper()) {
-                appTransformation = mService.mWallpaperTarget.mAppToken.transformation;
+            final AppWindowAnimator wpAppAnimator = mService.mWallpaperTarget.mAppToken == null
+                    ? null : mService.mWallpaperTarget.mAppToken.mAppAnimator;
+            if (wpAppAnimator != null &&
+                    wpAppAnimator.hasTransformation &&
+                    wpAppAnimator.animation != null &&
+                    !wpAppAnimator.animation.getDetachWallpaper()) {
+                appTransformation = wpAppAnimator.transformation;
                 if (WindowManagerService.DEBUG_WALLPAPER && appTransformation != null) {
                     Slog.v(TAG, "WP target app xform: " + appTransformation);
                 }
@@ -984,7 +987,7 @@
                     + (mWin.mAppToken != null ? mWin.mAppToken.hidden : false)
                     + " animating=" + mAnimating
                     + " tok animating="
-                    + (mWin.mAppToken != null ? mWin.mAppToken.animating : false));
+                    + (mWin.mAppToken != null ? mWin.mAppToken.mAppAnimator.animating : false));
             if (!showSurfaceRobustlyLocked()) {
                 return false;
             }