Merge "Move animation step from layout to animator."
diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java
index e65d5d2..0934ddb 100644
--- a/services/java/com/android/server/wm/WindowAnimator.java
+++ b/services/java/com/android/server/wm/WindowAnimator.java
@@ -14,6 +14,7 @@
 import android.os.SystemClock;
 import android.util.Log;
 import android.util.Slog;
+import android.view.Choreographer;
 import android.view.Surface;
 import android.view.WindowManager;
 import android.view.WindowManagerPolicy;
@@ -35,6 +36,8 @@
     final Context mContext;
     final WindowManagerPolicy mPolicy;
 
+    final Choreographer mChoreographer = Choreographer.getInstance();
+
     ArrayList<WindowStateAnimator> mWinAnimators = new ArrayList<WindowStateAnimator>();
 
     boolean mAnimating;
@@ -50,6 +53,18 @@
     }
     InnerLoopParams mInner = new InnerLoopParams();
 
+    static class LayoutToAnimatorParams {
+        boolean mAnimationScheduled;
+        ArrayList<WindowStateAnimator> mWinAnimators = new ArrayList<WindowStateAnimator>();
+        WindowState mWallpaperTarget;
+    }
+    /** Params from WindowManagerService. Do not modify or read without first locking on
+     * either WindowManagerService.mWindowMap or WindowManagerService.mAnimator.and then on
+     * mLayoutToAnim */
+    final LayoutToAnimatorParams mLayoutToAnim = new LayoutToAnimatorParams();
+
+    final Runnable mAnimationRunnable;
+
     int mAdjResult;
 
     int mPendingLayoutChanges;
@@ -86,11 +101,48 @@
     static final int WALLPAPER_ACTION_PENDING = 1;
     int mPendingActions;
 
+    WindowState mWallpaperTarget = null;
+
     WindowAnimator(final WindowManagerService service, final Context context,
             final WindowManagerPolicy policy) {
         mService = service;
         mContext = context;
         mPolicy = policy;
+
+        mAnimationRunnable = new Runnable() {
+            @Override
+            public void run() {
+                // TODO(cmautner): When full isolation is achieved for animation, the first lock
+                // goes away and only the WindowAnimator.this remains.
+                synchronized(mService.mWindowMap) {
+                    synchronized(WindowAnimator.this) {
+                        copyLayoutToAnimParamsLocked();
+                        animateLocked();
+                    }
+                }
+            }
+        };
+    }
+
+    /** Copy all WindowManagerService params into local params here. Locked on 'this'. */
+    private void copyLayoutToAnimParamsLocked() {
+        final LayoutToAnimatorParams layoutToAnim = mLayoutToAnim;
+        synchronized(layoutToAnim) {
+            layoutToAnim.mAnimationScheduled = false;
+
+            mWinAnimators = new ArrayList<WindowStateAnimator>(layoutToAnim.mWinAnimators);
+            mWallpaperTarget = layoutToAnim.mWallpaperTarget;
+        }
+    }
+
+    /** Note that Locked in this case is on mLayoutToAnim */
+    void scheduleAnimationLocked() {
+        final LayoutToAnimatorParams layoutToAnim = mLayoutToAnim;
+        if (!layoutToAnim.mAnimationScheduled) {
+            layoutToAnim.mAnimationScheduled = true;
+            mChoreographer.postCallback(
+                    Choreographer.CALLBACK_ANIMATION, mAnimationRunnable, null);
+        }
     }
 
     void hideWallpapersLocked(final WindowState w) {
@@ -128,11 +180,11 @@
             if (mService.mWallpaperTarget == target
                     || mService.mLowerWallpaperTarget == target
                     || mService.mUpperWallpaperTarget == target) {
-                final int N = mService.mWindows.size();
+                final int N = mWinAnimators.size();
                 for (int i = 0; i < N; i++) {
-                    WindowState w = mService.mWindows.get(i);
-                    if (w.mIsWallpaper) {
-                        target = w;
+                    WindowStateAnimator winAnimator = mWinAnimators.get(i);
+                    if (winAnimator.mWin.mIsWallpaper) {
+                        target = winAnimator.mWin;
                         break;
                     }
                 }
@@ -479,7 +531,9 @@
         }
     }
 
-    synchronized void animate() {
+    // TODO(cmautner): Change the following comment when no longer locked on mWindowMap */
+    /** Locked on mService.mWindowMap and this. */
+    private void animateLocked() {
         mPendingLayoutChanges = 0;
         mCurrentTime = SystemClock.uptimeMillis();
         mBulkUpdateParams = 0;
@@ -546,7 +600,9 @@
         }
 
         if (mAnimating) {
-            mService.scheduleAnimationLocked();
+            synchronized (mLayoutToAnim) {
+                scheduleAnimationLocked();
+            }
         } else if (wasAnimating) {
             mService.requestTraversalLocked();
         }
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 0ffb510..60ddf05 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -655,33 +655,6 @@
     /** Only do a maximum of 6 repeated layouts. After that quit */
     private int mLayoutRepeatCount;
 
-    private final class AnimationRunnable implements Runnable {
-        @Override
-        public void run() {
-            synchronized(mWindowMap) {
-                mAnimationScheduled = false;
-                // Update animations of all applications, including those
-                // associated with exiting/removed apps
-                synchronized (mAnimator) {
-                    Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmAnimate");
-                    final ArrayList<WindowStateAnimator> winAnimators = mAnimator.mWinAnimators;
-                    winAnimators.clear();
-                    final int N = mWindows.size();
-                    for (int i = 0; i < N; i++) {
-                        final WindowStateAnimator winAnimator = mWindows.get(i).mWinAnimator;
-                        if (winAnimator.mSurface != null) {
-                            winAnimators.add(winAnimator);
-                        }
-                    }
-                    mAnimator.animate();
-                    Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
-                }
-            }
-        }
-    }
-    final AnimationRunnable mAnimationRunnable = new AnimationRunnable();
-    boolean mAnimationScheduled;
-
     final WindowAnimator mAnimator;
 
     final class DragInputEventReceiver extends InputEventReceiver {
@@ -7155,18 +7128,23 @@
                 }
 
                 case FORCE_GC: {
-                    synchronized(mWindowMap) {
-                        if (mAnimationScheduled) {
-                            // If we are animating, don't do the gc now but
-                            // delay a bit so we don't interrupt the animation.
-                            mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
-                                    2000);
-                            return;
-                        }
-                        // If we are currently rotating the display, it will
-                        // schedule a new message when done.
-                        if (mDisplayFrozen) {
-                            return;
+                    synchronized (mWindowMap) {
+                        synchronized (mAnimator) {
+                            // Since we're holding both mWindowMap and mAnimator we don't need to
+                            // hold mAnimator.mLayoutToAnim.
+                            if (mAnimator.mAnimating ||
+                                    mAnimator.mLayoutToAnim.mAnimationScheduled) {
+                                // If we are animating, don't do the gc now but
+                                // delay a bit so we don't interrupt the animation.
+                                mH.sendMessageDelayed(mH.obtainMessage(H.FORCE_GC),
+                                        2000);
+                                return;
+                            }
+                            // If we are currently rotating the display, it will
+                            // schedule a new message when done.
+                            if (mDisplayFrozen) {
+                                return;
+                            }
                         }
                     }
                     Runtime.getRuntime().gc();
@@ -8960,9 +8938,20 @@
     }
 
     void scheduleAnimationLocked() {
-        if (!mAnimationScheduled) {
-            mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, mAnimationRunnable, null);
-            mAnimationScheduled = true;
+        final WindowAnimator.LayoutToAnimatorParams layoutToAnim = mAnimator.mLayoutToAnim;
+        synchronized (layoutToAnim) {
+            // Copy local params to transfer params.
+            ArrayList<WindowStateAnimator> winAnimators = layoutToAnim.mWinAnimators;
+            winAnimators.clear();
+            final int N = mWindows.size();
+            for (int i = 0; i < N; i++) {
+                final WindowStateAnimator winAnimator = mWindows.get(i).mWinAnimator;
+                if (winAnimator.mSurface != null) {
+                    winAnimators.add(winAnimator);
+                }
+            }
+            layoutToAnim.mWallpaperTarget = mWallpaperTarget;
+            mAnimator.scheduleAnimationLocked();
         }
     }