Merge "Defines MediaPlayer APIs to support multiple audio/video/timedtext tracks."
diff --git a/api/current.txt b/api/current.txt
index 6bac58a..93d9d44 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -26377,6 +26377,7 @@
     ctor public EdgeEffect(android.content.Context);
     method public boolean draw(android.graphics.Canvas);
     method public void finish();
+    method public android.graphics.Rect getBounds();
     method public boolean isFinished();
     method public void onAbsorb(int);
     method public void onPull(float);
diff --git a/cmds/system_server/library/Android.mk b/cmds/system_server/library/Android.mk
index 7d08a8c..9f92330 100644
--- a/cmds/system_server/library/Android.mk
+++ b/cmds/system_server/library/Android.mk
@@ -8,10 +8,7 @@
 native = $(LOCAL_PATH)/../../../../native
 
 LOCAL_C_INCLUDES := \
-	$(base)/services/camera/libcameraservice \
-	$(base)/services/audioflinger \
 	$(base)/services/sensorservice \
-	$(base)/media/libmediaplayerservice \
 	$(native)/services/surfaceflinger \
 	$(JNI_H_INCLUDE)
 
@@ -19,9 +16,6 @@
 	libandroid_runtime \
 	libsensorservice \
 	libsurfaceflinger \
-	libaudioflinger \
-    libcameraservice \
-    libmediaplayerservice \
     libinput \
 	libutils \
 	libbinder \
diff --git a/cmds/system_server/library/system_init.cpp b/cmds/system_server/library/system_init.cpp
index bfbc138..745c34a 100644
--- a/cmds/system_server/library/system_init.cpp
+++ b/cmds/system_server/library/system_init.cpp
@@ -15,10 +15,6 @@
 #include <utils/Log.h>
 
 #include <SurfaceFlinger.h>
-#include <AudioFlinger.h>
-#include <CameraService.h>
-#include <AudioPolicyService.h>
-#include <MediaPlayerService.h>
 #include <SensorService.h>
 
 #include <android_runtime/AndroidRuntime.h>
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index f09e29d..dbcea71 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -742,7 +742,8 @@
             url = url.replaceFirst(ANDROID_ASSET, "");
             try {
                 AssetManager assets = mContext.getAssets();
-                return assets.open(url, AssetManager.ACCESS_STREAMING);
+                Uri uri = Uri.parse(url);
+                return assets.open(uri.getPath(), AssetManager.ACCESS_STREAMING);
             } catch (IOException e) {
                 return null;
             }
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 5774440..9e07151 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -88,6 +88,7 @@
         ViewTreeObserver.OnTouchModeChangeListener,
         RemoteViewsAdapter.RemoteAdapterConnectionCallback {
 
+    @SuppressWarnings("UnusedDeclaration")
     private static final String TAG = "AbsListView";
 
     /**
@@ -2429,7 +2430,7 @@
         final ViewTreeObserver treeObserver = getViewTreeObserver();
         treeObserver.removeOnTouchModeChangeListener(this);
         if (mTextFilterEnabled && mPopup != null) {
-            treeObserver.removeGlobalOnLayoutListener(this);
+            treeObserver.removeOnGlobalLayoutListener(this);
             mGlobalLayoutListenerAddedFilter = false;
         }
 
@@ -2943,11 +2944,23 @@
                             mDirection = 0; // Reset when entering overscroll.
                             mTouchMode = TOUCH_MODE_OVERSCROLL;
                             if (rawDeltaY > 0) {
+                                if (!mEdgeGlowTop.isIdle()) {
+                                    invalidate(mEdgeGlowTop.getBounds());
+                                } else {
+                                    invalidate();
+                                }
+
                                 mEdgeGlowTop.onPull((float) overscroll / getHeight());
                                 if (!mEdgeGlowBottom.isFinished()) {
                                     mEdgeGlowBottom.onRelease();
                                 }
                             } else if (rawDeltaY < 0) {
+                                if (!mEdgeGlowBottom.isIdle()) {
+                                    invalidate(mEdgeGlowBottom.getBounds());
+                                } else {
+                                    invalidate();
+                                }
+
                                 mEdgeGlowBottom.onPull((float) overscroll / getHeight());
                                 if (!mEdgeGlowTop.isFinished()) {
                                     mEdgeGlowTop.onRelease();
@@ -2956,7 +2969,6 @@
                         }
                     }
                     mMotionY = y;
-                    invalidate();
                 }
                 mLastY = y;
             }
@@ -2990,26 +3002,26 @@
                             if (!mEdgeGlowBottom.isFinished()) {
                                 mEdgeGlowBottom.onRelease();
                             }
+                            invalidate(mEdgeGlowTop.getBounds());
                         } else if (rawDeltaY < 0) {
                             mEdgeGlowBottom.onPull((float) overScrollDistance / getHeight());
                             if (!mEdgeGlowTop.isFinished()) {
                                 mEdgeGlowTop.onRelease();
                             }
+                            invalidate(mEdgeGlowBottom.getBounds());
                         }
-                        invalidate();
                     }
                 }
 
                 if (incrementalDeltaY != 0) {
                     // Coming back to 'real' list scrolling
-                    mScrollY = 0;
-                    invalidateParentIfNeeded();
-
-                    // No need to do all this work if we're not going to move anyway
-                    if (incrementalDeltaY != 0) {
-                        trackMotionScroll(incrementalDeltaY, incrementalDeltaY);
+                    if (mScrollY != 0) {
+                        mScrollY = 0;
+                        invalidateParentIfNeeded();
                     }
 
+                    trackMotionScroll(incrementalDeltaY, incrementalDeltaY);
+
                     mTouchMode = TOUCH_MODE_SCROLL;
 
                     // We did not scroll the full amount. Treat this essentially like the
@@ -3468,11 +3480,12 @@
                 final int rightPadding = mListPadding.right + mGlowPaddingRight;
                 final int width = getWidth() - leftPadding - rightPadding;
 
-                canvas.translate(leftPadding,
-                        Math.min(0, scrollY + mFirstPositionDistanceGuess));
+                int edgeY = Math.min(0, scrollY + mFirstPositionDistanceGuess);
+                canvas.translate(leftPadding, edgeY);
                 mEdgeGlowTop.setSize(width, getHeight());
                 if (mEdgeGlowTop.draw(canvas)) {
-                    invalidate();
+                    mEdgeGlowTop.setPosition(leftPadding, edgeY);
+                    invalidate(mEdgeGlowTop.getBounds());
                 }
                 canvas.restoreToCount(restoreCount);
             }
@@ -3483,12 +3496,15 @@
                 final int width = getWidth() - leftPadding - rightPadding;
                 final int height = getHeight();
 
-                canvas.translate(-width + leftPadding,
-                        Math.max(height, scrollY + mLastPositionDistanceGuess));
+                int edgeX = -width + leftPadding;
+                int edgeY = Math.max(height, scrollY + mLastPositionDistanceGuess);
+                canvas.translate(edgeX, edgeY);
                 canvas.rotate(180, width, 0);
                 mEdgeGlowBottom.setSize(width, height);
                 if (mEdgeGlowBottom.draw(canvas)) {
-                    invalidate();
+                    // Account for the rotation
+                    mEdgeGlowBottom.setPosition(edgeX + width, edgeY - mEdgeGlowBottom.getHeight());
+                    invalidate(mEdgeGlowBottom.getBounds());
                 }
                 canvas.restoreToCount(restoreCount);
             }
@@ -3874,7 +3890,8 @@
                 }
 
                 // Don't stop just because delta is zero (it could have been rounded)
-                final boolean atEnd = trackMotionScroll(delta, delta) && (delta != 0);
+                final boolean atEdge = trackMotionScroll(delta, delta);
+                final boolean atEnd = atEdge && (delta != 0);
                 if (atEnd) {
                     if (motionView != null) {
                         // Tweak the scroll for how far we overshot
@@ -3889,7 +3906,7 @@
                 }
 
                 if (more && !atEnd) {
-                    invalidate();
+                    if (atEdge) invalidate();
                     mLastFlingY = y;
                     post(this);
                 } else {
@@ -4431,7 +4448,7 @@
     }
 
     private void createScrollingCache() {
-        if (mScrollingCacheEnabled && !mCachingStarted) {
+        if (mScrollingCacheEnabled && !mCachingStarted && !isHardwareAccelerated()) {
             setChildrenDrawnWithCacheEnabled(true);
             setChildrenDrawingCacheEnabled(true);
             mCachingStarted = mCachingActive = true;
@@ -4439,23 +4456,25 @@
     }
 
     private void clearScrollingCache() {
-        if (mClearScrollingCache == null) {
-            mClearScrollingCache = new Runnable() {
-                public void run() {
-                    if (mCachingStarted) {
-                        mCachingStarted = mCachingActive = false;
-                        setChildrenDrawnWithCacheEnabled(false);
-                        if ((mPersistentDrawingCache & PERSISTENT_SCROLLING_CACHE) == 0) {
-                            setChildrenDrawingCacheEnabled(false);
-                        }
-                        if (!isAlwaysDrawnWithCacheEnabled()) {
-                            invalidate();
+        if (!isHardwareAccelerated()) {
+            if (mClearScrollingCache == null) {
+                mClearScrollingCache = new Runnable() {
+                    public void run() {
+                        if (mCachingStarted) {
+                            mCachingStarted = mCachingActive = false;
+                            setChildrenDrawnWithCacheEnabled(false);
+                            if ((mPersistentDrawingCache & PERSISTENT_SCROLLING_CACHE) == 0) {
+                                setChildrenDrawingCacheEnabled(false);
+                            }
+                            if (!isAlwaysDrawnWithCacheEnabled()) {
+                                invalidate();
+                            }
                         }
                     }
-                }
-            };
+                };
+            }
+            post(mClearScrollingCache);
         }
-        post(mClearScrollingCache);
     }
 
     /**
@@ -4599,14 +4618,18 @@
             mRecycler.removeSkippedScrap();
         }
 
+        // invalidate before moving the children to avoid unnecessary invalidate
+        // calls to bubble up from the children all the way to the top
+        if (!awakenScrollBars()) {
+            invalidate();
+        }
+
         offsetChildrenTopAndBottom(incrementalDeltaY);
 
         if (down) {
             mFirstPosition += count;
         }
 
-        invalidate();
-
         final int absIncrementalDeltaY = Math.abs(incrementalDeltaY);
         if (spaceAbove < absIncrementalDeltaY || spaceBelow < absIncrementalDeltaY) {
             fillGap(down);
@@ -4629,7 +4652,6 @@
         mBlockLayoutRequests = false;
 
         invokeOnItemScrollListener();
-        awakenScrollBars();
 
         return false;
     }
diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java
index 83aa8ba..c1f31bb 100644
--- a/core/java/android/widget/EdgeEffect.java
+++ b/core/java/android/widget/EdgeEffect.java
@@ -16,6 +16,7 @@
 
 package android.widget;
 
+import android.graphics.Rect;
 import com.android.internal.R;
 
 import android.content.Context;
@@ -45,6 +46,7 @@
  * {@link #draw(Canvas)} method.</p>
  */
 public class EdgeEffect {
+    @SuppressWarnings("UnusedDeclaration")
     private static final String TAG = "EdgeEffect";
 
     // Time it will take the effect to fully recede in ms
@@ -57,10 +59,7 @@
     private static final int PULL_DECAY_TIME = 1000;
 
     private static final float MAX_ALPHA = 1.f;
-    private static final float HELD_EDGE_ALPHA = 0.7f;
     private static final float HELD_EDGE_SCALE_Y = 0.5f;
-    private static final float HELD_GLOW_ALPHA = 0.5f;
-    private static final float HELD_GLOW_SCALE_Y = 0.5f;
 
     private static final float MAX_GLOW_HEIGHT = 4.f;
 
@@ -76,7 +75,9 @@
     private final Drawable mGlow;
     private int mWidth;
     private int mHeight;
-    private final int MIN_WIDTH = 300;
+    private int mX;
+    private int mY;
+    private static final int MIN_WIDTH = 300;
     private final int mMinWidth;
 
     private float mEdgeAlpha;
@@ -119,6 +120,8 @@
     private int mState = STATE_IDLE;
 
     private float mPullDistance;
+    
+    private final Rect mBounds = new Rect();
 
     /**
      * Construct a new EdgeEffect with a theme appropriate for the provided context.
@@ -145,6 +148,29 @@
     }
 
     /**
+     * Set the position of this edge effect in pixels. This position is
+     * only used by {@link #getBounds()}.
+     * 
+     * @param x The position of the edge effect on the X axis
+     * @param y The position of the edge effect on the Y axis
+     */
+    void setPosition(int x, int y) {
+        mX = x;
+        mY = y;
+    }
+
+    boolean isIdle() {
+        return mState == STATE_IDLE;
+    }
+
+    /**
+     * Returns the height of the effect itself.
+     */
+    int getHeight() {
+        return Math.max(mGlow.getBounds().height(), mEdge.getBounds().height());
+    }
+    
+    /**
      * Reports if this EdgeEffect's animation is finished. If this method returns false
      * after a call to {@link #draw(Canvas)} the host widget should schedule another
      * drawing pass to continue the animation.
@@ -301,7 +327,6 @@
         update();
 
         final int edgeHeight = mEdge.getIntrinsicHeight();
-        final int edgeWidth = mEdge.getIntrinsicWidth();
         final int glowHeight = mGlow.getIntrinsicHeight();
         final int glowWidth = mGlow.getIntrinsicWidth();
 
@@ -334,9 +359,23 @@
         }
         mEdge.draw(canvas);
 
+        if (mState == STATE_RECEDE && glowBottom == 0 && edgeBottom == 0) {
+            mState = STATE_IDLE;
+        }
+
         return mState != STATE_IDLE;
     }
 
+    /**
+     * Returns the bounds of the edge effect.
+     */
+    public Rect getBounds() {
+        mBounds.set(mGlow.getBounds());
+        mBounds.union(mEdge.getBounds());
+        mBounds.offset(mX, mY);
+        return mBounds;
+    }
+
     private void update() {
         final long time = AnimationUtils.currentAnimationTimeMillis();
         final float t = Math.min((time - mStartTime) / mDuration, 1.f);
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index fc08cc5..60dd55c 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -29,8 +29,8 @@
 import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
-
 import com.android.internal.R;
+import android.widget.RemoteViews.RemoteView;
 
 import java.lang.reflect.Array;
 import java.util.ArrayList;
@@ -146,6 +146,7 @@
  * @attr ref android.R.styleable#GridLayout_rowOrderPreserved
  * @attr ref android.R.styleable#GridLayout_columnOrderPreserved
  */
+@RemoteView
 public class GridLayout extends ViewGroup {
 
     // Public constants
@@ -234,7 +235,6 @@
 
     final Axis horizontalAxis = new Axis(true);
     final Axis verticalAxis = new Axis(false);
-    boolean layoutParamsValid = false;
     int orientation = DEFAULT_ORIENTATION;
     boolean useDefaultMargins = DEFAULT_USE_DEFAULT_MARGINS;
     int alignmentMode = DEFAULT_ALIGNMENT_MODE;
@@ -713,12 +713,10 @@
 
             minor = minor + minorSpan;
         }
-        lastLayoutParamsHashCode = computeLayoutParamsHashCode();
-        invalidateStructure();
     }
 
     private void invalidateStructure() {
-        layoutParamsValid = false;
+        lastLayoutParamsHashCode = UNINITIALIZED_HASH;
         horizontalAxis.invalidateStructure();
         verticalAxis.invalidateStructure();
         // This can end up being done twice. Better twice than not at all.
@@ -742,10 +740,6 @@
     }
 
     final LayoutParams getLayoutParams(View c) {
-        if (!layoutParamsValid) {
-            validateLayoutParams();
-            layoutParamsValid = true;
-        }
         return (LayoutParams) c.getLayoutParams();
     }
 
@@ -874,20 +868,22 @@
         return result;
     }
 
-    private void checkForLayoutParamsModification() {
-        int layoutParamsHashCode = computeLayoutParamsHashCode();
-        if (lastLayoutParamsHashCode != UNINITIALIZED_HASH &&
-                lastLayoutParamsHashCode != layoutParamsHashCode) {
-            invalidateStructure();
+    private void consistencyCheck() {
+        if (lastLayoutParamsHashCode == UNINITIALIZED_HASH) {
+            validateLayoutParams();
+            lastLayoutParamsHashCode = computeLayoutParamsHashCode();
+        } else if (lastLayoutParamsHashCode != computeLayoutParamsHashCode()) {
             Log.w(TAG, "The fields of some layout parameters were modified in between layout " +
                     "operations. Check the javadoc for GridLayout.LayoutParams#rowSpec.");
+            invalidateStructure();
+            consistencyCheck();
         }
     }
 
     // Measurement
 
     private void measureChildWithMargins2(View child, int parentWidthSpec, int parentHeightSpec,
-                                          int childWidth, int childHeight) {
+            int childWidth, int childHeight) {
         int childWidthSpec = getChildMeasureSpec(parentWidthSpec,
                 mPaddingLeft + mPaddingRight + getTotalMargin(child, true), childWidth);
         int childHeightSpec = getChildMeasureSpec(parentHeightSpec,
@@ -923,7 +919,7 @@
 
     @Override
     protected void onMeasure(int widthSpec, int heightSpec) {
-        checkForLayoutParamsModification();
+        consistencyCheck();
 
         /** If we have been called by {@link View#measure(int, int)}, one of width or height
          *  is  likely to have changed. We must invalidate if so. */
@@ -993,7 +989,7 @@
      */
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        checkForLayoutParamsModification();
+        consistencyCheck();
 
         int targetWidth = right - left;
         int targetHeight = bottom - top;
@@ -1250,7 +1246,7 @@
         }
 
         private void include(List<Arc> arcs, Interval key, MutableInt size,
-                             boolean ignoreIfAlreadyPresent) {
+                boolean ignoreIfAlreadyPresent) {
             /*
             Remove self referential links.
             These appear:
@@ -1429,8 +1425,8 @@
                 int dst = arc.span.max;
                 int value = arc.value.value;
                 result.append((src < dst) ?
-                        var + dst + " - " + var + src + " > " + value :
-                        var + src + " - " + var + dst + " < " + -value);
+                        var + dst + "-" + var + src + ">=" + value :
+                        var + src + "-" + var + dst + "<=" + -value);
 
             }
             return result.toString();
diff --git a/media/libstagefright/XINGSeeker.cpp b/media/libstagefright/XINGSeeker.cpp
index 2091381..e36d619 100644
--- a/media/libstagefright/XINGSeeker.cpp
+++ b/media/libstagefright/XINGSeeker.cpp
@@ -24,7 +24,7 @@
 static bool parse_xing_header(
         const sp<DataSource> &source, off64_t first_frame_pos,
         int32_t *frame_number = NULL, int32_t *byte_number = NULL,
-        unsigned char *table_of_contents = NULL,
+        unsigned char *table_of_contents = NULL, bool *toc_is_valid = NULL,
         int32_t *quality_indicator = NULL, int64_t *duration = NULL);
 
 // static
@@ -36,7 +36,7 @@
 
     if (!parse_xing_header(
                 source, first_frame_pos,
-                NULL, &seeker->mSizeBytes, seeker->mTableOfContents,
+                NULL, &seeker->mSizeBytes, seeker->mTOC, &seeker->mTOCValid,
                 NULL, &seeker->mDurationUs)) {
         return NULL;
     }
@@ -60,7 +60,7 @@
 }
 
 bool XINGSeeker::getOffsetForTime(int64_t *timeUs, off64_t *pos) {
-    if (mSizeBytes == 0 || mTableOfContents[0] <= 0 || mDurationUs < 0) {
+    if (mSizeBytes == 0 || !mTOCValid || mDurationUs < 0) {
         return false;
     }
 
@@ -76,10 +76,10 @@
         if ( a == 0 ) {
             fa = 0.0f;
         } else {
-            fa = (float)mTableOfContents[a-1];
+            fa = (float)mTOC[a-1];
         }
         if ( a < 99 ) {
-            fb = (float)mTableOfContents[a];
+            fb = (float)mTOC[a];
         } else {
             fb = 256.0f;
         }
@@ -94,7 +94,8 @@
 static bool parse_xing_header(
         const sp<DataSource> &source, off64_t first_frame_pos,
         int32_t *frame_number, int32_t *byte_number,
-        unsigned char *table_of_contents, int32_t *quality_indicator,
+        unsigned char *table_of_contents, bool *toc_valid,
+        int32_t *quality_indicator,
         int64_t *duration) {
     if (frame_number) {
         *frame_number = 0;
@@ -102,8 +103,8 @@
     if (byte_number) {
         *byte_number = 0;
     }
-    if (table_of_contents) {
-        table_of_contents[0] = 0;
+    if (toc_valid) {
+        *toc_valid = false;
     }
     if (quality_indicator) {
         *quality_indicator = 0;
@@ -199,10 +200,13 @@
         offset += 4;
     }
     if (flags & 0x0004) {  // TOC field is present
-       if (table_of_contents) {
+        if (table_of_contents) {
             if (source->readAt(offset + 1, table_of_contents, 99) < 99) {
                 return false;
             }
+            if (toc_valid) {
+                *toc_valid = true;
+            }
         }
         offset += 100;
     }
diff --git a/media/libstagefright/include/XINGSeeker.h b/media/libstagefright/include/XINGSeeker.h
index ec5bd9b..8510979 100644
--- a/media/libstagefright/include/XINGSeeker.h
+++ b/media/libstagefright/include/XINGSeeker.h
@@ -37,7 +37,8 @@
     int32_t mSizeBytes;
 
     // TOC entries in XING header. Skip the first one since it's always 0.
-    unsigned char mTableOfContents[99];
+    unsigned char mTOC[99];
+    bool mTOCValid;
 
     XINGSeeker();
 
diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/java/com/android/server/wm/AppWindowToken.java
index b84fbdb..5ca09e7 100644
--- a/services/java/com/android/server/wm/AppWindowToken.java
+++ b/services/java/com/android/server/wm/AppWindowToken.java
@@ -27,6 +27,7 @@
 import android.view.IApplicationToken;
 import android.view.View;
 import android.view.WindowManager;
+import android.view.WindowManagerPolicy;
 import android.view.animation.Animation;
 import android.view.animation.Transformation;
 
@@ -37,7 +38,7 @@
  * Version of WindowToken that is specifically for a particular application (or
  * really activity) that is displaying windows.
  */
-class AppWindowToken extends WindowToken implements WindowManagerService.StepAnimator {
+class AppWindowToken extends WindowToken {
     // Non-null only for application tokens.
     final IApplicationToken appToken;
 
@@ -195,8 +196,8 @@
         }
     }
 
-    @Override
-    public boolean stepAnimation(long currentTime) {
+
+    private boolean stepAnimation(long currentTime) {
         if (animation == null) {
             return false;
         }
@@ -216,7 +217,7 @@
     }
 
     // This must be called while inside a transaction.
-    boolean startAndFinishAnimationLocked(long currentTime, int dw, int dh) {
+    boolean stepAnimationLocked(long currentTime, int dw, int dh) {
         if (!service.mDisplayFrozen && service.mPolicy.isScreenOnFully()) {
             // We will run animations as long as the display isn't frozen.
 
@@ -240,7 +241,7 @@
                     animating = true;
                 }
                 // we're done!
-                return true;
+                return stepAnimation(currentTime);
             }
         } else if (animation != null) {
             // If the display is frozen, and there is a pending animation,
@@ -255,6 +256,7 @@
             return false;
         }
 
+        service.mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
         clearAnimation();
         animating = false;
         if (animLayerAdjustment != 0) {
diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/java/com/android/server/wm/ScreenRotationAnimation.java
index 7b5bf08..58187b6 100644
--- a/services/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -29,7 +29,7 @@
 import android.view.animation.AnimationUtils;
 import android.view.animation.Transformation;
 
-class ScreenRotationAnimation implements WindowManagerService.StepAnimator {
+class ScreenRotationAnimation {
     static final String TAG = "ScreenRotationAnimation";
     static final boolean DEBUG_STATE = false;
     static final boolean DEBUG_TRANSFORMS = false;
@@ -540,8 +540,7 @@
                 || mRotateFrameAnimation != null;
     }
 
-    @Override
-    public boolean stepAnimation(long now) {
+    private boolean stepAnimation(long now) {
 
         if (mFinishAnimReady && mFinishAnimStartTime < 0) {
             if (DEBUG_STATE) Slog.v(TAG, "Step: finish anim now ready");
@@ -725,7 +724,7 @@
         setSnapshotTransform(mSnapshotFinalMatrix, mExitTransformation.getAlpha());
     }
     
-    public boolean startAndFinishAnimationLocked(long now) {
+    public boolean stepAnimationLocked(long now) {
         if (!isAnimating()) {
             if (DEBUG_STATE) Slog.v(TAG, "Step: no animations running");
             mFinishAnimReady = false;
@@ -763,8 +762,8 @@
             }
             mAnimRunning = true;
         }
-        
-        return true;
+
+        return stepAnimation(now);
     }
 
     public Transformation getEnterTransformation() {
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 22949f3..4f55217 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -461,6 +461,7 @@
             = new ArrayList<IRotationWatcher>();
     int mDeferredRotationPauseCount;
 
+    int mPendingLayoutChanges = 0;
     boolean mLayoutNeeded = true;
     boolean mTraversalScheduled = false;
     boolean mDisplayFrozen = false;
@@ -617,18 +618,6 @@
     final AnimationRunnable mAnimationRunnable = new AnimationRunnable();
     boolean mAnimationScheduled;
 
-    interface StepAnimator {
-        /**
-         * Continue the stepping of an ongoing animation. When the animation completes this method
-         * must disable the animation on the StepAnimator. 
-         * @param currentTime Animation time in milliseconds. Use SystemClock.uptimeMillis().
-         * @return True if the animation is still going on, false if the animation has completed
-         *      and stepAnimation has cleared the animation locally.
-         */
-        boolean stepAnimation(long currentTime);
-    }
-    final ArrayList<StepAnimator> mStepAnimators = new ArrayList<StepAnimator>();
-    
     final class DragInputEventReceiver extends InputEventReceiver {
         public DragInputEventReceiver(InputChannel inputChannel, Looper looper) {
             super(inputChannel, looper);
@@ -2995,15 +2984,27 @@
     }
 
     void applyEnterAnimationLocked(WindowState win) {
-        int transit = WindowManagerPolicy.TRANSIT_SHOW;
+        final int transit;
         if (win.mEnterAnimationPending) {
             win.mEnterAnimationPending = false;
             transit = WindowManagerPolicy.TRANSIT_ENTER;
+        } else {
+            transit = WindowManagerPolicy.TRANSIT_SHOW;
         }
 
         applyAnimationLocked(win, transit, true);
     }
 
+    /**
+     * Choose the correct animation and set it to the passed WindowState.
+     * @param win The window to add the animation to.
+     * @param transit If WindowManagerPolicy.TRANSIT_PREVIEW_DONE and the app window has been drawn
+     *      then the animation will be app_starting_exit. Any other value loads the animation from
+     *      the switch statement below.
+     * @param isEntrance The animation type the last time this was called. Used to keep from
+     *      loading the same animation twice.
+     * @return true if an animation has been loaded.
+     */
     boolean applyAnimationLocked(WindowState win,
             int transit, boolean isEntrance) {
         if (win.mLocalAnimating && win.mAnimationIsEntrance == isEntrance) {
@@ -7643,20 +7644,6 @@
     }
 
     /**
-     * Run through each of the animating objects saved in mStepAnimators.
-     */
-    private void stepAnimations() {
-        final long currentTime = SystemClock.uptimeMillis();
-        for (final StepAnimator stepAnimator : mStepAnimators) {
-            final boolean more = stepAnimator.stepAnimation(currentTime);
-            if (DEBUG_ANIM) {
-                Slog.v(TAG, "stepAnimations: " + currentTime + ": Stepped " + stepAnimator
-                        + (more ? " more" : " done"));
-            }
-        }
-    }
-    
-    /**
      * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
      * Update animations of all applications, including those associated with exiting/removed apps.
      *
@@ -7670,16 +7657,14 @@
         final int NAT = mAppTokens.size();
         for (i=0; i<NAT; i++) {
             final AppWindowToken appToken = mAppTokens.get(i);
-            if (appToken.startAndFinishAnimationLocked(currentTime, innerDw, innerDh)) {
-                mStepAnimators.add(appToken);
+            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.startAndFinishAnimationLocked(currentTime, innerDw, innerDh)) {
-                mStepAnimators.add(appToken);
+            if (appToken.stepAnimationLocked(currentTime, innerDw, innerDh)) {
                 mInnerFields.mAnimating = true;
             }
         }
@@ -7687,10 +7672,9 @@
         if (mScreenRotationAnimation != null) {
             if (mScreenRotationAnimation.isAnimating() ||
                     mScreenRotationAnimation.mFinishAnimReady) {
-                if (mScreenRotationAnimation.startAndFinishAnimationLocked(currentTime)) {
+                if (mScreenRotationAnimation.stepAnimationLocked(currentTime)) {
                     mInnerFields.mUpdateRotation = false;
                     mInnerFields.mAnimating = true;
-                    mStepAnimators.add(mScreenRotationAnimation);
                 } else {
                     mInnerFields.mUpdateRotation = true;
                     mScreenRotationAnimation.kill();
@@ -7711,9 +7695,7 @@
      */
     private int updateWindowsAndWallpaperLocked(final long currentTime, final int dw, final int dh,
                                                 final int innerDw, final int innerDh) {
-
-        mPolicy.beginAnimationLw(dw, dh);
-
+        int changes = 0;
         for (int i = mWindows.size() - 1; i >= 0; i--) {
             WindowState w = mWindows.get(i);
 
@@ -7727,6 +7709,7 @@
                         if (DEBUG_WALLPAPER) Slog.v(TAG,
                                 "First draw done in potential wallpaper target " + w);
                         mInnerFields.mWallpaperMayChange = true;
+                        changes |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
                     }
                 }
 
@@ -7749,13 +7732,7 @@
                 }
 
                 final boolean wasAnimating = w.mWasAnimating;
-                
-                
-                final boolean nowAnimating = w.startAndFinishAnimationLocked(currentTime);
-                if (nowAnimating) {
-                    mStepAnimators.add(w);
-                    mInnerFields.mAnimating = true;
-                }
+                final boolean nowAnimating = w.stepAnimationLocked(currentTime);
 
                 if (DEBUG_WALLPAPER) {
                     Slog.v(TAG, w + ": wasAnimating=" + wasAnimating +
@@ -7806,6 +7783,7 @@
 
                 if (wasAnimating && !w.mAnimating && mWallpaperTarget == w) {
                     mInnerFields.mWallpaperMayChange = true;
+                    changes |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
                 }
 
                 if (mPolicy.doesForceHide(w, attrs)) {
@@ -7814,6 +7792,7 @@
                                 "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;
@@ -7852,10 +7831,9 @@
                     if (changed && (attrs.flags
                             & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) {
                         mInnerFields.mWallpaperMayChange = true;
+                        changes |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
                     }
                 }
-
-                mPolicy.animatingWindowLw(w, attrs);
             }
 
             final AppWindowToken atoken = w.mAppToken;
@@ -7900,10 +7878,11 @@
                 }
             } else if (w.mReadyToShow) {
                 w.performShowLocked();
+                changes |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
             }
         } // end forall windows
 
-        return mPolicy.finishAnimationLw();
+        return changes;
     }
 
     /**
@@ -8322,6 +8301,72 @@
         return changes;
     }
 
+    private void updateResizingWindows(final WindowState w) {
+        if (!w.mAppFreezing && w.mLayoutSeq == mLayoutSeq) {
+            w.mContentInsetsChanged |=
+                !w.mLastContentInsets.equals(w.mContentInsets);
+            w.mVisibleInsetsChanged |=
+                !w.mLastVisibleInsets.equals(w.mVisibleInsets);
+            boolean configChanged =
+                w.mConfiguration != mCurConfiguration
+                && (w.mConfiguration == null
+                        || mCurConfiguration.diff(w.mConfiguration) != 0);
+            if (DEBUG_CONFIGURATION && configChanged) {
+                Slog.v(TAG, "Win " + w + " config changed: "
+                        + mCurConfiguration);
+            }
+            if (localLOGV) Slog.v(TAG, "Resizing " + w
+                    + ": configChanged=" + configChanged
+                    + " last=" + w.mLastFrame + " frame=" + w.mFrame);
+            w.mLastFrame.set(w.mFrame);
+            if (w.mContentInsetsChanged
+                    || w.mVisibleInsetsChanged
+                    || w.mSurfaceResized
+                    || configChanged) {
+                if (DEBUG_RESIZE || DEBUG_ORIENTATION) {
+                    Slog.v(TAG, "Resize reasons: "
+                            + " contentInsetsChanged=" + w.mContentInsetsChanged
+                            + " visibleInsetsChanged=" + w.mVisibleInsetsChanged
+                            + " surfaceResized=" + w.mSurfaceResized
+                            + " configChanged=" + configChanged);
+                }
+
+                w.mLastContentInsets.set(w.mContentInsets);
+                w.mLastVisibleInsets.set(w.mVisibleInsets);
+                makeWindowFreezingScreenIfNeededLocked(w);
+                // If the orientation is changing, then we need to
+                // hold off on unfreezing the display until this
+                // window has been redrawn; to do that, we need
+                // to go through the process of getting informed
+                // by the application when it has finished drawing.
+                if (w.mOrientationChanging) {
+                    if (DEBUG_ORIENTATION) Slog.v(TAG,
+                            "Orientation start waiting for draw in "
+                            + w + ", surface " + w.mSurface);
+                    w.mDrawPending = true;
+                    w.mCommitDrawPending = false;
+                    w.mReadyToShow = false;
+                    if (w.mAppToken != null) {
+                        w.mAppToken.allDrawn = false;
+                    }
+                }
+                if (!mResizingWindows.contains(w)) {
+                    if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
+                            "Resizing window " + w + " to " + w.mSurfaceW
+                            + "x" + w.mSurfaceH);
+                    mResizingWindows.add(w);
+                }
+            } else if (w.mOrientationChanging) {
+                if (!w.mDrawPending && !w.mCommitDrawPending) {
+                    if (DEBUG_ORIENTATION) Slog.v(TAG,
+                            "Orientation not waiting for draw in "
+                            + w + ", surface " + w.mSurface);
+                    w.mOrientationChanging = false;
+                }
+            }
+        }
+    }
+
     /**
      * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
      *
@@ -8407,69 +8452,7 @@
             }
         }
 
-        if (!w.mAppFreezing && w.mLayoutSeq == mLayoutSeq) {
-            w.mContentInsetsChanged |=
-                !w.mLastContentInsets.equals(w.mContentInsets);
-            w.mVisibleInsetsChanged |=
-                !w.mLastVisibleInsets.equals(w.mVisibleInsets);
-            boolean configChanged =
-                w.mConfiguration != mCurConfiguration
-                && (w.mConfiguration == null
-                        || mCurConfiguration.diff(w.mConfiguration) != 0);
-            if (DEBUG_CONFIGURATION && configChanged) {
-                Slog.v(TAG, "Win " + w + " config changed: "
-                        + mCurConfiguration);
-            }
-            if (localLOGV) Slog.v(TAG, "Resizing " + w
-                    + ": configChanged=" + configChanged
-                    + " last=" + w.mLastFrame + " frame=" + w.mFrame);
-            w.mLastFrame.set(w.mFrame);
-            if (w.mContentInsetsChanged
-                    || w.mVisibleInsetsChanged
-                    || w.mSurfaceResized
-                    || configChanged) {
-                if (DEBUG_RESIZE || DEBUG_ORIENTATION) {
-                    Slog.v(TAG, "Resize reasons: "
-                            + " contentInsetsChanged=" + w.mContentInsetsChanged
-                            + " visibleInsetsChanged=" + w.mVisibleInsetsChanged
-                            + " surfaceResized=" + w.mSurfaceResized
-                            + " configChanged=" + configChanged);
-                }
-
-                w.mLastContentInsets.set(w.mContentInsets);
-                w.mLastVisibleInsets.set(w.mVisibleInsets);
-                makeWindowFreezingScreenIfNeededLocked(w);
-                // If the orientation is changing, then we need to
-                // hold off on unfreezing the display until this
-                // window has been redrawn; to do that, we need
-                // to go through the process of getting informed
-                // by the application when it has finished drawing.
-                if (w.mOrientationChanging) {
-                    if (DEBUG_ORIENTATION) Slog.v(TAG,
-                            "Orientation start waiting for draw in "
-                            + w + ", surface " + w.mSurface);
-                    w.mDrawPending = true;
-                    w.mCommitDrawPending = false;
-                    w.mReadyToShow = false;
-                    if (w.mAppToken != null) {
-                        w.mAppToken.allDrawn = false;
-                    }
-                }
-                if (!mResizingWindows.contains(w)) {
-                    if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG,
-                            "Resizing window " + w + " to " + w.mSurfaceW
-                            + "x" + w.mSurfaceH);
-                    mResizingWindows.add(w);
-                }
-            } else if (w.mOrientationChanging) {
-                if (!w.mDrawPending && !w.mCommitDrawPending) {
-                    if (DEBUG_ORIENTATION) Slog.v(TAG,
-                            "Orientation not waiting for draw in "
-                            + w + ", surface " + w.mSurface);
-                    w.mOrientationChanging = false;
-                }
-            }
-        }
+        updateResizingWindows(w);
 
         if (w.mAttachedHidden || !w.isReadyForDisplay()) {
             if (!w.mLastHidden) {
@@ -8678,6 +8661,67 @@
         }
     }
 
+    private final int performAnimationsLocked(long currentTime, int dw, int dh,
+            int innerDw, int innerDh) {
+        ++mTransactionSequence;
+
+        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) {
@@ -8741,7 +8785,6 @@
         try {
             mInnerFields.mWallpaperForceHidingChanged = false;
             int repeats = 0;
-            int changes = 0;
             
             do {
                 repeats++;
@@ -8751,20 +8794,20 @@
                     break;
                 }
 
-                if ((changes & WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
+                if ((mPendingLayoutChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
                     if ((adjustWallpaperWindowsLocked()&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
                         assignLayersLocked();
                         mLayoutNeeded = true;
                     }
                 }
-                if ((changes & WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) {
+                if ((mPendingLayoutChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) {
                     if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
                     if (updateOrientationFromAppTokensLocked(true)) {
                         mLayoutNeeded = true;
                         mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
                     }
                 }
-                if ((changes & WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
+                if ((mPendingLayoutChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
                     mLayoutNeeded = true;
                 }
 
@@ -8775,71 +8818,26 @@
                     Slog.w(TAG, "Layout repeat skipped after too many iterations");
                 }
 
-                ++mTransactionSequence;
-
-                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;
-
-                mStepAnimators.clear();
-                changes = updateWindowsAndWallpaperLocked(currentTime, dw, dh, innerDw, innerDh);
-
-                if (mInnerFields.mTokenMayBeDrawn) {
-                    changes |= testTokenMayBeDrawnLocked();
+                // FIRST AND ONE HALF LOOP: Make WindowManagerPolicy think
+                // it is animating.
+                mPendingLayoutChanges = 0;
+                mPolicy.beginAnimationLw(dw, dh);
+                for (i = mWindows.size() - 1; i >= 0; i--) {
+                    WindowState w = mWindows.get(i);
+                    if (w.mSurface != null) {
+                        mPolicy.animatingWindowLw(w, w.mAttrs);
+                    }
                 }
-
-                // 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));
-            } while (changes != 0);
+                mPendingLayoutChanges |= mPolicy.finishAnimationLw();
+                
+            } while (mPendingLayoutChanges != 0);
 
             // Update animations of all applications, including those
             // associated with exiting/removed apps
 
+            mPendingLayoutChanges = performAnimationsLocked(currentTime, dw, dh,
+                    innerDw, innerDh);
             updateWindowsAppsAndRotationAnimationsLocked(currentTime, innerDw, innerDh);
-            
-            stepAnimations();
 
             // THIRD LOOP: Update the surfaces of all windows.
 
@@ -9049,6 +9047,13 @@
         if (wallpaperDestroyed) {
             needRelayout = adjustWallpaperWindowsLocked() != 0;
         }
+        if ((mPendingLayoutChanges & (
+                WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER |
+                ADJUST_WALLPAPER_LAYERS_CHANGED |
+                WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG |
+                WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT)) != 0) {
+            needRelayout = true;
+        }
         if (needRelayout) {
             requestTraversalLocked();
         } else if (mInnerFields.mAnimating) {
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index e11c87a..48788e7 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -54,8 +54,7 @@
 /**
  * A window in the window manager.
  */
-final class WindowState implements WindowManagerPolicy.WindowState,
-        WindowManagerService.StepAnimator {
+final class WindowState implements WindowManagerPolicy.WindowState {
     static final boolean DEBUG_VISIBILITY = WindowManagerService.DEBUG_VISIBILITY;
     static final boolean SHOW_TRANSACTIONS = WindowManagerService.SHOW_TRANSACTIONS;
     static final boolean SHOW_LIGHT_TRANSACTIONS = WindowManagerService.SHOW_LIGHT_TRANSACTIONS;
@@ -995,8 +994,7 @@
         return true;
     }
 
-    @Override
-    public boolean stepAnimation(long currentTime) {
+    private boolean stepAnimation(long currentTime) {
         if ((mAnimation == null) || !mLocalAnimating || (mAnimState != ANIM_STATE_RUNNING)) {
             return false;
         }
@@ -1013,7 +1011,7 @@
 
     // This must be called while inside a transaction.  Returns true if
     // there is more animation to run.
-    boolean startAndFinishAnimationLocked(long currentTime) {
+    boolean stepAnimationLocked(long currentTime) {
         // Save the animation state as it was before this step so WindowManagerService can tell if
         // we just started or just stopped animating by comparing mWasAnimating with isAnimating().
         mWasAnimating = mAnimating;
@@ -1038,7 +1036,7 @@
                 }
                 if ((mAnimation != null) && mLocalAnimating && 
                         (mAnimState != ANIM_STATE_STOPPING)) {
-                    return true;
+                    return stepAnimation(currentTime);
                 }
                 if (WindowManagerService.DEBUG_ANIM) Slog.v(
                     WindowManagerService.TAG, "Finished animation in " + this +
@@ -1133,6 +1131,7 @@
         }
 
         finishExit();
+        mService.mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
 
         if (mAppToken != null) {
             mAppToken.updateReportedVisibilityLocked();
@@ -1608,6 +1607,7 @@
 
     boolean showLw(boolean doAnimation, boolean requestAnim) {
         if (mPolicyVisibility && mPolicyVisibilityAfterAnim) {
+            // Already showing.
             return false;
         }
         if (DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, "Policy visibility true: " + this);
@@ -1647,6 +1647,7 @@
         boolean current = doAnimation ? mPolicyVisibilityAfterAnim
                 : mPolicyVisibility;
         if (!current) {
+            // Already hiding.
             return false;
         }
         if (doAnimation) {