Merge "Use setCustomSelectActionModeCallback to disallow action bar." into jb-dev
diff --git a/core/java/android/animation/LayoutTransition.java b/core/java/android/animation/LayoutTransition.java
index c643137..bdcb2af 100644
--- a/core/java/android/animation/LayoutTransition.java
+++ b/core/java/android/animation/LayoutTransition.java
@@ -1208,6 +1208,9 @@
      * affect CHANGE_APPEARING or CHANGE_DISAPPEARING animations.
      */
     private void addChild(ViewGroup parent, View child, boolean changesLayout) {
+        if (parent.getWindowVisibility() != View.VISIBLE) {
+            return;
+        }
         if ((mTransitionTypes & FLAG_APPEARING) == FLAG_APPEARING) {
             // Want disappearing animations to finish up before proceeding
             cancel(DISAPPEARING);
@@ -1243,6 +1246,9 @@
      * @hide
      */
     public void layoutChange(ViewGroup parent) {
+        if (parent.getWindowVisibility() != View.VISIBLE) {
+            return;
+        }
         if ((mTransitionTypes & FLAG_CHANGING) == FLAG_CHANGING  && !isRunning()) {
             // This method is called for all calls to layout() in the container, including
             // those caused by add/remove/hide/show events, which will already have set up
@@ -1301,6 +1307,9 @@
      * affect CHANGE_APPEARING or CHANGE_DISAPPEARING animations.
      */
     private void removeChild(ViewGroup parent, View child, boolean changesLayout) {
+        if (parent.getWindowVisibility() != View.VISIBLE) {
+            return;
+        }
         if ((mTransitionTypes & FLAG_DISAPPEARING) == FLAG_DISAPPEARING) {
             // Want appearing animations to finish up before proceeding
             cancel(APPEARING);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index a74a0ef..20eef11 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -12725,6 +12725,7 @@
         if (!initialized) {
             a.initialize(mRight - mLeft, mBottom - mTop, parent.getWidth(), parent.getHeight());
             a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop);
+            if (mAttachInfo != null) a.setListenerHandler(mAttachInfo.mHandler);
             onAnimationStart();
         }
 
@@ -12738,6 +12739,7 @@
         } else {
             invalidationTransform = parent.mChildTransformation;
         }
+
         if (more) {
             if (!a.willChangeBounds()) {
                 if ((flags & (parent.FLAG_OPTIMIZE_INVALIDATE | parent.FLAG_ANIMATION_DONE)) ==
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 421109f..a243c73 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3154,8 +3154,12 @@
     }
 
     /**
-     * Adds a child view. If no layout parameters are already set on the child, the
-     * default parameters for this ViewGroup are set on the child.
+     * <p>Adds a child view. If no layout parameters are already set on the child, the
+     * default parameters for this ViewGroup are set on the child.</p>
+     * 
+     * <p><strong>Note:</strong> do not invoke this method from
+     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
+     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
      *
      * @param child the child view to add
      *
@@ -3168,6 +3172,10 @@
     /**
      * Adds a child view. If no layout parameters are already set on the child, the
      * default parameters for this ViewGroup are set on the child.
+     * 
+     * <p><strong>Note:</strong> do not invoke this method from
+     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
+     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
      *
      * @param child the child view to add
      * @param index the position at which to add the child
@@ -3189,6 +3197,10 @@
      * Adds a child view with this ViewGroup's default layout parameters and the
      * specified width and height.
      *
+     * <p><strong>Note:</strong> do not invoke this method from
+     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
+     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
+     *
      * @param child the child view to add
      */
     public void addView(View child, int width, int height) {
@@ -3201,6 +3213,10 @@
     /**
      * Adds a child view with the specified layout parameters.
      *
+     * <p><strong>Note:</strong> do not invoke this method from
+     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
+     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
+     *
      * @param child the child view to add
      * @param params the layout parameters to set on the child
      */
@@ -3211,6 +3227,10 @@
     /**
      * Adds a child view with the specified layout parameters.
      *
+     * <p><strong>Note:</strong> do not invoke this method from
+     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
+     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
+     *
      * @param child the child view to add
      * @param index the position at which to add the child
      * @param params the layout parameters to set on the child
@@ -3528,6 +3548,10 @@
 
     /**
      * {@inheritDoc}
+     * 
+     * <p><strong>Note:</strong> do not invoke this method from
+     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
+     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
      */
     public void removeView(View view) {
         removeViewInternal(view);
@@ -3539,6 +3563,10 @@
      * Removes a view during layout. This is useful if in your onLayout() method,
      * you need to remove more views.
      *
+     * <p><strong>Note:</strong> do not invoke this method from
+     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
+     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
+     * 
      * @param view the view to remove from the group
      */
     public void removeViewInLayout(View view) {
@@ -3549,6 +3577,10 @@
      * Removes a range of views during layout. This is useful if in your onLayout() method,
      * you need to remove more views.
      *
+     * <p><strong>Note:</strong> do not invoke this method from
+     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
+     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
+     *
      * @param start the index of the first view to remove from the group
      * @param count the number of views to remove from the group
      */
@@ -3559,6 +3591,10 @@
     /**
      * Removes the view at the specified position in the group.
      *
+     * <p><strong>Note:</strong> do not invoke this method from
+     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
+     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
+     * 
      * @param index the position in the group of the view to remove
      */
     public void removeViewAt(int index) {
@@ -3570,6 +3606,10 @@
     /**
      * Removes the specified range of views from the group.
      *
+     * <p><strong>Note:</strong> do not invoke this method from
+     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
+     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
+     *
      * @param start the first position in the group of the range of views to remove
      * @param count the number of views to remove
      */
@@ -3715,6 +3755,10 @@
     /**
      * Call this method to remove all child views from the
      * ViewGroup.
+     * 
+     * <p><strong>Note:</strong> do not invoke this method from
+     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
+     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
      */
     public void removeAllViews() {
         removeAllViewsInLayout();
@@ -3730,6 +3774,10 @@
      * that can currently fit inside the object on screen. Do not call
      * this method unless you are extending ViewGroup and understand the
      * view measuring and layout pipeline.
+     *
+     * <p><strong>Note:</strong> do not invoke this method from
+     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
+     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
      */
     public void removeAllViewsInLayout() {
         final int count = mChildrenCount;
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index d92ebcd..85d77cb 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.RectF;
+import android.os.Handler;
 import android.os.SystemProperties;
 import android.util.AttributeSet;
 import android.util.TypedValue;
@@ -207,6 +208,11 @@
 
     private final CloseGuard guard = CloseGuard.get();
 
+    private Handler mListenerHandler;
+    private Runnable mOnStart;
+    private Runnable mOnRepeat;
+    private Runnable mOnEnd;
+
     /**
      * Creates a new animation with a duration of 0ms, the default interpolator, with
      * fillBefore set to true and fillAfter set to false
@@ -275,6 +281,7 @@
         mRepeated = 0;
         mMore = true;
         mOneMoreTime = true;
+        mListenerHandler = null;
     }
 
     /**
@@ -290,7 +297,7 @@
      */
     public void cancel() {
         if (mStarted && !mEnded) {
-            if (mListener != null) mListener.onAnimationEnd(this);
+            fireAnimationEnd();
             mEnded = true;
             guard.close();
         }
@@ -306,7 +313,7 @@
         if (mStarted && !mEnded) {
             mEnded = true;
             guard.close();
-            if (mListener != null) mListener.onAnimationEnd(this);
+            fireAnimationEnd();
         }
     }
 
@@ -341,6 +348,38 @@
     }
 
     /**
+     * Sets the handler used to invoke listeners.
+     * 
+     * @hide
+     */
+    public void setListenerHandler(Handler handler) {
+        if (mListenerHandler == null) {
+            mOnStart = new Runnable() {
+                public void run() {
+                    if (mListener != null) {
+                        mListener.onAnimationStart(Animation.this);
+                    }
+                }
+            };
+            mOnRepeat = new Runnable() {
+                public void run() {
+                    if (mListener != null) {
+                        mListener.onAnimationRepeat(Animation.this);
+                    }
+                }
+            };
+            mOnEnd = new Runnable() {
+                public void run() {
+                    if (mListener != null) {
+                        mListener.onAnimationEnd(Animation.this);
+                    }
+                }
+            };
+        }
+        mListenerHandler = handler;
+    }
+
+    /**
      * Sets the acceleration curve for this animation. The interpolator is loaded as
      * a resource from the specified context.
      *
@@ -792,7 +831,6 @@
      * @return True if the animation is still running
      */
     public boolean getTransformation(long currentTime, Transformation outTransformation) {
-
         if (mStartTime == -1) {
             mStartTime = currentTime;
         }
@@ -815,9 +853,7 @@
 
         if ((normalizedTime >= 0.0f || mFillBefore) && (normalizedTime <= 1.0f || mFillAfter)) {
             if (!mStarted) {
-                if (mListener != null) {
-                    mListener.onAnimationStart(this);
-                }
+                fireAnimationStart();
                 mStarted = true;
                 if (USE_CLOSEGUARD) {
                     guard.open("cancel or detach or getTransformation");
@@ -839,9 +875,7 @@
                 if (!mEnded) {
                     mEnded = true;
                     guard.close();
-                    if (mListener != null) {
-                        mListener.onAnimationEnd(this);
-                    }
+                    fireAnimationEnd();
                 }
             } else {
                 if (mRepeatCount > 0) {
@@ -855,9 +889,7 @@
                 mStartTime = -1;
                 mMore = true;
 
-                if (mListener != null) {
-                    mListener.onAnimationRepeat(this);
-                }
+                fireAnimationRepeat();
             }
         }
 
@@ -868,7 +900,28 @@
 
         return mMore;
     }
-    
+
+    private void fireAnimationStart() {
+        if (mListener != null) {
+            if (mListenerHandler == null) mListener.onAnimationStart(this);
+            else mListenerHandler.postAtFrontOfQueue(mOnStart);
+        }
+    }
+
+    private void fireAnimationRepeat() {
+        if (mListener != null) {
+            if (mListenerHandler == null) mListener.onAnimationRepeat(this);
+            else mListenerHandler.postAtFrontOfQueue(mOnRepeat);
+        }
+    }
+
+    private void fireAnimationEnd() {
+        if (mListener != null) {
+            if (mListenerHandler == null) mListener.onAnimationEnd(this);
+            else mListenerHandler.postAtFrontOfQueue(mOnEnd);
+        }
+    }
+
     /**
      * Gets the transformation to apply at a specified point in time. Implementations of this
      * method should always replace the specified Transformation or document they are doing
diff --git a/core/java/android/view/textservice/SpellCheckerSubtype.java b/core/java/android/view/textservice/SpellCheckerSubtype.java
index f235295..c753188 100644
--- a/core/java/android/view/textservice/SpellCheckerSubtype.java
+++ b/core/java/android/view/textservice/SpellCheckerSubtype.java
@@ -146,7 +146,10 @@
         return false;
     }
 
-    private static Locale constructLocaleFromString(String localeStr) {
+    /**
+     * @hide
+     */
+    public static Locale constructLocaleFromString(String localeStr) {
         if (TextUtils.isEmpty(localeStr))
             return null;
         String[] localeParams = localeStr.split("_", 3);
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index 58dd82e..f03fb86 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -7872,7 +7872,7 @@
         nativeSetTextSelection(mNativeClass, data.mSelectTextPtr);
 
         if ((data.mSelectionReason == TextSelectionData.REASON_ACCESSIBILITY_INJECTOR)
-                || (!mSelectingText
+                || (!mSelectingText && data.mStart != data.mEnd
                         && data.mSelectionReason != TextSelectionData.REASON_SELECT_WORD)) {
             selectionDone();
             mShowTextSelectionExtra = true;
@@ -8494,6 +8494,11 @@
         mWebView.postInvalidate();
     }
 
+    // Note: must be called before first WebViewClassic is created.
+    public static void setShouldMonitorWebCoreThread() {
+        WebViewCore.setShouldMonitorWebCoreThread();
+    }
+
     private native void     nativeCreate(int ptr, String drawableDir, boolean isHighEndGfx);
     private native void     nativeDebugDump();
     private native void     nativeDestroy();
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index af7914e..ba42ff5 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -144,6 +144,11 @@
     private int mChromeCanFocusDirection;
     private int mTextSelectionChangeReason = TextSelectionData.REASON_UNKNOWN;
 
+    // Used to determine if we should monitor the WebCore thread for responsiveness.
+    // If it "hangs", for example a web page enters a while(true) loop, we will
+    // prompt the user with a dialog allowing them to terminate the process.
+    private static boolean sShouldMonitorWebCoreThread;
+
     // The thread name used to identify the WebCore thread and for use in
     // debugging other classes that require operation within the WebCore thread.
     /* package */ static final String THREAD_NAME = "WebViewCoreThread";
@@ -176,9 +181,13 @@
                     Log.e(LOGTAG, Log.getStackTraceString(e));
                 }
 
-                // Start the singleton watchdog which will monitor the WebCore thread
-                // to verify it's still processing messages.
-                WebCoreThreadWatchdog.start(sWebCoreHandler);
+                if (sShouldMonitorWebCoreThread) {
+                    // Start the singleton watchdog which will monitor the WebCore thread
+                    // to verify it's still processing messages. Note that this is the only
+                    // time we need to check the value as all the other public methods on
+                    // the WebCoreThreadWatchdog are no-ops if start() is not called.
+                    WebCoreThreadWatchdog.start(sWebCoreHandler);
+                }
             }
             // Make sure the Watchdog is aware of this new WebView.
             WebCoreThreadWatchdog.registerWebView(w);
@@ -3061,6 +3070,10 @@
         return mDeviceOrientationService;
     }
 
+    static void setShouldMonitorWebCoreThread() {
+        sShouldMonitorWebCoreThread = true;
+    }
+
     private native void nativeSetIsPaused(int nativeClass, boolean isPaused);
     private native void nativePause(int nativeClass);
     private native void nativeResume(int nativeClass);
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 6cee0f3..9abe72b 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -579,6 +579,7 @@
     private InputConnectionWrapper mPublicInputConnection;
 
     private Runnable mClearScrollingCache;
+    Runnable mPositionScrollAfterLayout;
     private int mMinimumVelocity;
     private int mMaximumVelocity;
     private float mVelocityScale = 1.0f;
@@ -1910,6 +1911,7 @@
         removeAllViewsInLayout();
         mFirstPosition = 0;
         mDataChanged = false;
+        mPositionScrollAfterLayout = null;
         mNeedSync = false;
         mOldSelectedPosition = INVALID_POSITION;
         mOldSelectedRowId = INVALID_ROW_ID;
@@ -4248,11 +4250,11 @@
 
             if (mDataChanged) {
                 // Wait until we're back in a stable state to try this.
-                post(new Runnable() {
+                mPositionScrollAfterLayout = new Runnable() {
                     @Override public void run() {
                         start(position);
                     }
-                });
+                };
                 return;
             }
 
@@ -4299,11 +4301,11 @@
 
             if (mDataChanged) {
                 // Wait until we're back in a stable state to try this.
-                post(new Runnable() {
+                mPositionScrollAfterLayout = new Runnable() {
                     @Override public void run() {
                         start(position, boundPosition);
                     }
-                });
+                };
                 return;
             }
 
@@ -4376,11 +4378,11 @@
             if (mDataChanged) {
                 // Wait until we're back in a stable state to try this.
                 final int postOffset = offset;
-                post(new Runnable() {
+                mPositionScrollAfterLayout = new Runnable() {
                     @Override public void run() {
                         startWithOffset(position, postOffset, duration);
                     }
-                });
+                };
                 return;
             }
 
diff --git a/core/java/android/widget/ActivityChooserView.java b/core/java/android/widget/ActivityChooserView.java
index be6b4e2..4eb169b 100644
--- a/core/java/android/widget/ActivityChooserView.java
+++ b/core/java/android/widget/ActivityChooserView.java
@@ -400,6 +400,9 @@
         if (viewTreeObserver.isAlive()) {
             viewTreeObserver.removeOnGlobalLayoutListener(mOnGlobalLayoutListener);
         }
+        if (isShowingPopup()) {
+            dismissPopup();
+        }
         mIsAttachedToWindow = false;
     }
 
@@ -420,9 +423,7 @@
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         mActivityChooserContent.layout(0, 0, right - left, bottom - top);
-        if (getListPopupWindow().isShowing()) {
-            showPopupUnchecked(mAdapter.getMaxActivityCount());
-        } else {
+        if (!isShowingPopup()) {
             dismissPopup();
         }
     }
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index 0a40d5e..8975109 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -1275,6 +1275,10 @@
 
             mLayoutMode = LAYOUT_NORMAL;
             mDataChanged = false;
+            if (mPositionScrollAfterLayout != null) {
+                post(mPositionScrollAfterLayout);
+                mPositionScrollAfterLayout = null;
+            }
             mNeedSync = false;
             setNextSelectedPositionInt(mSelectedPosition);
 
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index c62b62b..d2e55d9 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -1691,6 +1691,10 @@
             
             mLayoutMode = LAYOUT_NORMAL;
             mDataChanged = false;
+            if (mPositionScrollAfterLayout != null) {
+                post(mPositionScrollAfterLayout);
+                mPositionScrollAfterLayout = null;
+            }
             mNeedSync = false;
             setNextSelectedPositionInt(mSelectedPosition);
 
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 81a44fd..bd19f00 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -7678,7 +7678,7 @@
                 mContext.getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE);
         final SpellCheckerSubtype subtype = textServicesManager.getCurrentSpellCheckerSubtype(true);
         if (subtype != null) {
-            locale = new Locale(subtype.getLocale());
+            locale = SpellCheckerSubtype.constructLocaleFromString(subtype.getLocale());
         }
         return locale;
     }
diff --git a/core/res/res/layout/keyguard_screen_unlock_portrait.xml b/core/res/res/layout/keyguard_screen_unlock_portrait.xml
index 35b8665..c235289 100644
--- a/core/res/res/layout/keyguard_screen_unlock_portrait.xml
+++ b/core/res/res/layout/keyguard_screen_unlock_portrait.xml
@@ -173,12 +173,11 @@
     <RelativeLayout
         android:id="@+id/faceLockAreaView"
         android:visibility="invisible"
-        android:layout_row="3"
+        android:layout_row="4"
         android:layout_column="0"
-        android:layout_rowSpan="2"
+        android:layout_rowSpan="1"
         android:layout_columnSpan="1"
         android:layout_gravity="fill"
-        android:layout_marginTop="4dip"
         android:layout_marginBottom="4dip"
         android:layout_width="0dip"
         android:layout_height="0dip"
diff --git a/media/mca/filterpacks/java/android/filterpacks/videosink/MediaEncoderFilter.java b/media/mca/filterpacks/java/android/filterpacks/videosink/MediaEncoderFilter.java
index d8aa40f..8bb653b 100644
--- a/media/mca/filterpacks/java/android/filterpacks/videosink/MediaEncoderFilter.java
+++ b/media/mca/filterpacks/java/android/filterpacks/videosink/MediaEncoderFilter.java
@@ -111,12 +111,12 @@
     /** Frame width to be encoded, defaults to 320.
      * Actual received frame size has to match this */
     @GenerateFieldPort(name = "width", hasDefault = true)
-    private int mWidth = 320;
+    private int mWidth = 0;
 
     /** Frame height to to be encoded, defaults to 240.
      * Actual received frame size has to match */
     @GenerateFieldPort(name = "height", hasDefault = true)
-    private int mHeight = 240;
+    private int mHeight = 0;
 
     /** Stream framerate to encode the frames at.
      * By default, frames are encoded at 30 FPS*/
@@ -245,6 +245,11 @@
         if (mProfile != null) {
             mMediaRecorder.setProfile(mProfile);
             mFps = mProfile.videoFrameRate;
+            // If width and height are set larger than 0, then those
+            // overwrite the ones in the profile.
+            if (mWidth > 0 && mHeight > 0) {
+                mMediaRecorder.setVideoSize(mWidth, mHeight);
+            }
         } else {
             mMediaRecorder.setOutputFormat(mOutputFormat);
             mMediaRecorder.setVideoEncoder(mVideoEncoder);
@@ -298,7 +303,10 @@
         screenFormat.setBytesPerSample(4);
 
         int width, height;
-        if (mProfile != null) {
+        boolean widthHeightSpecified = mWidth > 0 && mHeight > 0;
+        // If width and height are specified, then use those instead
+        // of that in the profile.
+        if (mProfile != null && !widthHeightSpecified) {
             width = mProfile.videoFrameWidth;
             height = mProfile.videoFrameHeight;
         } else {
@@ -410,7 +418,6 @@
         // And swap buffers
         glEnv.swapBuffers();
         mNumFramesEncoded++;
-        if (mLogVerbose) Log.v(TAG, "numFramesEncoded = " + mNumFramesEncoded);
     }
 
     private void stopRecording(FilterContext context) {
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 29de5c1..4ee0d25 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -33,6 +33,7 @@
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.content.res.TypedArray;
 import android.database.ContentObserver;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
@@ -1434,8 +1435,9 @@
                 && attrs.type != WindowManager.LayoutParams.TYPE_NAVIGATION_BAR
                 && attrs.type != WindowManager.LayoutParams.TYPE_WALLPAPER;
     }
-    
+
     /** {@inheritDoc} */
+    @Override
     public View addStartingWindow(IBinder appToken, String packageName, int theme,
             CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes,
             int icon, int windowFlags) {
@@ -1445,7 +1447,7 @@
         if (packageName == null) {
             return null;
         }
-        
+
         try {
             Context context = mContext;
             //Log.i(TAG, "addStartingWindow " + packageName + ": nonLocalizedLabel="
@@ -1458,16 +1460,19 @@
                     // Ignore
                 }
             }
-            
+
             Window win = PolicyManager.makeNewWindow(context);
-            if (win.getWindowStyle().getBoolean(
-                    com.android.internal.R.styleable.Window_windowDisablePreview, false)) {
+            final TypedArray ta = win.getWindowStyle();
+            if (ta.getBoolean(
+                        com.android.internal.R.styleable.Window_windowDisablePreview, false)
+                || ta.getBoolean(
+                        com.android.internal.R.styleable.Window_windowShowWallpaper,false)) {
                 return null;
             }
-            
+
             Resources r = context.getResources();
             win.setTitle(r.getText(labelRes, nonLocalizedLabel));
-    
+
             win.setType(
                 WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
             // Force the window flags: this is a fake window, so it is not really
@@ -1483,14 +1488,14 @@
                 WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE|
                 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
                 WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
-    
+
             if (!compatInfo.supportsScreen()) {
                 win.addFlags(WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW);
             }
 
             win.setLayout(WindowManager.LayoutParams.MATCH_PARENT,
                     WindowManager.LayoutParams.MATCH_PARENT);
-    
+
             final WindowManager.LayoutParams params = win.getAttributes();
             params.token = appToken;
             params.packageName = packageName;
@@ -1512,7 +1517,7 @@
                 // earlier.)
                 return null;
             }
-            
+
             if (localLOGV) Log.v(
                 TAG, "Adding starting window for " + packageName
                 + " / " + appToken + ": "
diff --git a/services/java/com/android/server/TextServicesManagerService.java b/services/java/com/android/server/TextServicesManagerService.java
index 499ff7a..c7b336f 100644
--- a/services/java/com/android/server/TextServicesManagerService.java
+++ b/services/java/com/android/server/TextServicesManagerService.java
@@ -254,10 +254,8 @@
                         return scs;
                     } else if (candidate == null) {
                         final String scsLocale = scs.getLocale();
-                        if (candidateLocale.length() >= 2
-                                && scsLocale.length() >= 2
-                                && candidateLocale.substring(0, 2).equals(
-                                        scsLocale.substring(0, 2))) {
+                        if (candidateLocale.length() >= 2 && scsLocale.length() >= 2
+                                && candidateLocale.startsWith(scsLocale)) {
                             // Fall back to the applicable language
                             candidate = scs;
                         }
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index 5e2f494..039efbd 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -191,8 +191,11 @@
             @Override
             public void onSomePackagesChanged() {
                 synchronized (mLock) {
-                    populateAccessibilityServiceListLocked();
-                    manageServicesLocked();
+                    // We will update when the automation service dies.
+                    if (mUiAutomationService == null) {
+                        populateAccessibilityServiceListLocked();
+                        manageServicesLocked();
+                    }
                 }
             }
 
@@ -242,11 +245,14 @@
             public void onReceive(Context context, Intent intent) {
                 if (intent.getAction() == Intent.ACTION_BOOT_COMPLETED) {
                     synchronized (mLock) {
-                        populateAccessibilityServiceListLocked();
-                        handleAccessibilityEnabledSettingChangedLocked();
-                        handleTouchExplorationEnabledSettingChangedLocked();
-                        updateInputFilterLocked();
-                        sendStateToClientsLocked();
+                        // We will update when the automation service dies.
+                        if (mUiAutomationService == null) {
+                            populateAccessibilityServiceListLocked();
+                            handleAccessibilityEnabledSettingChangedLocked();
+                            handleTouchExplorationEnabledSettingChangedLocked();
+                            updateInputFilterLocked();
+                            sendStateToClientsLocked();
+                        }
                     }
 
                     return;
@@ -294,9 +300,12 @@
                 public void onChange(boolean selfChange) {
                     super.onChange(selfChange);
                     synchronized (mLock) {
-                        handleAccessibilityEnabledSettingChangedLocked();
-                        updateInputFilterLocked();
-                        sendStateToClientsLocked();
+                        // We will update when the automation service dies.
+                        if (mUiAutomationService == null) {
+                            handleAccessibilityEnabledSettingChangedLocked();
+                            updateInputFilterLocked();
+                            sendStateToClientsLocked();
+                        }
                     }
                 }
             });
@@ -309,9 +318,12 @@
                     public void onChange(boolean selfChange) {
                         super.onChange(selfChange);
                         synchronized (mLock) {
-                            handleTouchExplorationEnabledSettingChangedLocked();
-                            updateInputFilterLocked();
-                            sendStateToClientsLocked();
+                            // We will update when the automation service dies.
+                            if (mUiAutomationService == null) {
+                                handleTouchExplorationEnabledSettingChangedLocked();
+                                updateInputFilterLocked();
+                                sendStateToClientsLocked();
+                            }
                         }
                     }
                 });
@@ -324,7 +336,10 @@
                 public void onChange(boolean selfChange) {
                     super.onChange(selfChange);
                     synchronized (mLock) {
-                        manageServicesLocked();
+                        // We will update when the automation service dies.
+                        if (mUiAutomationService == null) {
+                            manageServicesLocked();
+                        }
                     }
                 }
             });
@@ -747,10 +762,6 @@
      * Manages services by starting enabled ones and stopping disabled ones.
      */
     private void manageServicesLocked() {
-        // While the UI automation service is running it takes over.
-        if (mUiAutomationService != null) {
-            return;
-        }
         populateEnabledServicesLocked(mEnabledServices);
         final int enabledInstalledServicesCount = updateServicesStateLocked(mInstalledServices,
                 mEnabledServices);
@@ -926,8 +937,13 @@
 
     private void tryEnableTouchExploration(final Service service) {
         if (!mIsTouchExplorationEnabled && service.mRequestTouchExplorationMode) {
-            mMainHandler.obtainMessage(MSG_SHOW_ENABLE_TOUCH_EXPLORATION_DIALOG,
-                    service).sendToTarget();
+            if (!service.mIsAutomation) {
+                mMainHandler.obtainMessage(MSG_SHOW_ENABLE_TOUCH_EXPLORATION_DIALOG,
+                        service).sendToTarget();
+            } else {
+                Settings.Secure.putInt(mContext.getContentResolver(),
+                        Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1);
+            }
         }
     }
 
@@ -1479,10 +1495,15 @@
                 // the state based on values in the settings database.
                 if (mIsAutomation) {
                     mUiAutomationService = null;
+
                     handleAccessibilityEnabledSettingChangedLocked();
+                    sendStateToClientsLocked();
+
                     handleTouchExplorationEnabledSettingChangedLocked();
                     updateInputFilterLocked();
-                    sendStateToClientsLocked();
+
+                    populateAccessibilityServiceListLocked();
+                    manageServicesLocked();
                 }
             }
         }
diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java
index 97f65ad8..d6954a5 100644
--- a/services/java/com/android/server/wm/WindowAnimator.java
+++ b/services/java/com/android/server/wm/WindowAnimator.java
@@ -134,10 +134,11 @@
     }
 
     private void updateWindowsAppsAndRotationAnimationsLocked() {
+        final ArrayList<AppWindowToken> appTokens = mService.mAnimatingAppTokens;
         int i;
-        final int NAT = mService.mAppTokens.size();
+        final int NAT = appTokens.size();
         for (i=0; i<NAT; i++) {
-            final AppWindowAnimator appAnimator = mService.mAppTokens.get(i).mAppAnimator;
+            final AppWindowAnimator appAnimator = appTokens.get(i).mAppAnimator;
             final boolean wasAnimating = appAnimator.animation != null
                     && appAnimator.animation != AppWindowAnimator.sDummyAnimation;
             if (appAnimator.stepAnimationLocked(mCurrentTime, mInnerDw, mInnerDh)) {
@@ -401,9 +402,10 @@
     private void testTokenMayBeDrawnLocked() {
         // See if any windows have been drawn, so they (and others
         // associated with them) can now be shown.
-        final int NT = mService.mAppTokens.size();
+        final ArrayList<AppWindowToken> appTokens = mService.mAnimatingAppTokens;
+        final int NT = appTokens.size();
         for (int i=0; i<NT; i++) {
-            AppWindowToken wtoken = mService.mAppTokens.get(i);
+            AppWindowToken wtoken = appTokens.get(i);
             if (wtoken.mAppAnimator.freezingScreen) {
                 int numInteresting = wtoken.numInterestingWindows;
                 if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 895b5c1..d9e0ec6 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -351,13 +351,20 @@
     final ArrayList<WindowToken> mExitingTokens = new ArrayList<WindowToken>();
 
     /**
-     * Z-ordered (bottom-most first) list of all application tokens, for
-     * controlling the ordering of windows in different applications.  This
-     * contains AppWindowToken objects.
+     * List controlling the ordering of windows in different applications which must
+     * be kept in sync with ActivityManager.
      */
     final ArrayList<AppWindowToken> mAppTokens = new ArrayList<AppWindowToken>();
 
     /**
+     * AppWindowTokens in the Z order they were in at the start of an animation. Between
+     * animations this list is maintained in the exact order of mAppTokens. If tokens
+     * are added to mAppTokens during an animation an attempt is made to insert them at the same
+     * logical location in this list. Note that this list is always in sync with mWindows.
+     */
+    ArrayList<AppWindowToken> mAnimatingAppTokens = new ArrayList<AppWindowToken>();
+
+    /**
      * Application tokens that are in the process of exiting, but still
      * on screen for animations.
      */
@@ -529,8 +536,6 @@
     boolean mSkipAppTransitionAnimation = false;
     final ArrayList<AppWindowToken> mOpeningApps = new ArrayList<AppWindowToken>();
     final ArrayList<AppWindowToken> mClosingApps = new ArrayList<AppWindowToken>();
-    final ArrayList<AppWindowToken> mToTopApps = new ArrayList<AppWindowToken>();
-    final ArrayList<AppWindowToken> mToBottomApps = new ArrayList<AppWindowToken>();
 
     Display mDisplay;
 
@@ -1010,10 +1015,10 @@
                         + client.asBinder() + " (token=" + token + ")");
                     // Figure out where the window should go, based on the
                     // order of applications.
-                    final int NA = mAppTokens.size();
+                    final int NA = mAnimatingAppTokens.size();
                     WindowState pos = null;
                     for (i=NA-1; i>=0; i--) {
-                        AppWindowToken t = mAppTokens.get(i);
+                        AppWindowToken t = mAnimatingAppTokens.get(i);
                         if (t == token) {
                             i--;
                             break;
@@ -1046,7 +1051,7 @@
                         // Continue looking down until we find the first
                         // token that has windows.
                         while (i >= 0) {
-                            AppWindowToken t = mAppTokens.get(i);
+                            AppWindowToken t = mAnimatingAppTokens.get(i);
                             final int NW = t.windows.size();
                             if (NW > 0) {
                                 pos = t.windows.get(NW-1);
@@ -1167,6 +1172,7 @@
         }
     }
 
+    /** TODO(cmautner): Is this the same as {@link WindowState#canReceiveKeys()} */
     static boolean canBeImeTarget(WindowState w) {
         final int fl = w.mAttrs.flags
                 & (FLAG_NOT_FOCUSABLE|FLAG_ALT_FOCUSABLE_IM);
@@ -1636,7 +1642,7 @@
                     continue;
                 }
             }
-            if (DEBUG_WALLPAPER) Slog.v(TAG, "Win " + w + ": readyfordisplay="
+            if (DEBUG_WALLPAPER) Slog.v(TAG, "Win #" + i + " " + w + ": readyfordisplay="
                     + w.isReadyForDisplay() + " mDrawState=" + w.mWinAnimator.mDrawState);
             if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0 && w.isReadyForDisplay()
                     && (mWallpaperTarget == w || w.isDrawnLw())) {
@@ -1729,12 +1735,15 @@
                                 Slog.v(TAG, "Old wallpaper still the target.");
                             }
                             mWallpaperTarget = oldW;
-                        }
-
+                            foundW = oldW;
+                            foundI = oldI;
+                            mLowerWallpaperTarget = null;
+                            mUpperWallpaperTarget = null;
+                        } 
                         // Now set the upper and lower wallpaper targets
                         // correctly, and make sure that we are positioning
                         // the wallpaper below the lower.
-                        if (foundI > oldI) {
+                        else if (foundI > oldI) {
                             // The new target is on top of the old one.
                             if (DEBUG_WALLPAPER) {
                                 Slog.v(TAG, "Found target above old target.");
@@ -1872,7 +1881,7 @@
                 }
 
                 wallpaper.mWinAnimator.mAnimLayer = wallpaper.mLayer + mWallpaperAnimLayerAdjustment;
-                if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper win "
+                if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG, "adjustWallpaper win "
                         + wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer);
 
                 // First, if this window is at the current index, then all
@@ -1926,7 +1935,7 @@
                 curWallpaperIndex--;
                 WindowState wallpaper = token.windows.get(curWallpaperIndex);
                 wallpaper.mWinAnimator.mAnimLayer = wallpaper.mLayer + adj;
-                if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper win "
+                if (DEBUG_LAYERS || DEBUG_WALLPAPER) Slog.v(TAG, "setWallpaper win "
                         + wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer);
             }
         }
@@ -3484,6 +3493,25 @@
         Binder.restoreCallingIdentity(origId);
     }
 
+    /**
+     *  Find the location to insert a new AppWindowToken into the window-ordered app token list.
+     *  Note that mAppTokens.size() == mAnimatingAppTokens.size() + 1.
+     * @param addPos The location the token was inserted into in mAppTokens.
+     * @param wtoken The token to insert.
+     */
+    private void addAppTokenToAnimating(final int addPos, final AppWindowToken wtoken) {
+        if (addPos == 0 || addPos == mAnimatingAppTokens.size()) {
+            // It was inserted into the beginning or end of mAppTokens. Honor that.
+            mAnimatingAppTokens.add(addPos, wtoken);
+            return;
+        }
+        // Find the item immediately above the mAppTokens insertion point and put the token
+        // immediately below that one in mAnimatingAppTokens.
+        final AppWindowToken aboveAnchor = mAppTokens.get(addPos + 1);
+        mAnimatingAppTokens.add(mAnimatingAppTokens.indexOf(aboveAnchor), wtoken);
+    }
+
+    @Override
     public void addAppToken(int addPos, IApplicationToken token,
             int groupId, int requestedOrientation, boolean fullscreen) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
@@ -3518,6 +3546,7 @@
             wtoken.requestedOrientation = requestedOrientation;
             if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG, "addAppToken: " + wtoken);
             mAppTokens.add(addPos, wtoken);
+            addAppTokenToAnimating(addPos, wtoken);
             mTokenMap.put(token.asBinder(), wtoken);
 
             // Application tokens start out hidden.
@@ -3835,7 +3864,7 @@
             if (DEBUG_APP_TRANSITIONS) Slog.v(
                     TAG, "Prepare app transition: transit=" + transit
                     + " mNextAppTransition=" + mNextAppTransition
-                    + "\nCallers=" + Debug.getCallers(3));
+                    + " Callers=" + Debug.getCallers(3));
             if (okToDisplay()) {
                 if (mNextAppTransition == WindowManagerPolicy.TRANSIT_UNSET
                         || mNextAppTransition == WindowManagerPolicy.TRANSIT_NONE) {
@@ -4467,6 +4496,7 @@
                 if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
                         "removeAppToken: " + wtoken);
                 mAppTokens.remove(wtoken);
+                mAnimatingAppTokens.remove(wtoken);
                 wtoken.removed = true;
                 if (wtoken.startingData != null) {
                     startingToken = wtoken;
@@ -4498,11 +4528,13 @@
 
     private boolean tmpRemoveAppWindowsLocked(WindowToken token) {
         final int NW = token.windows.size();
+        if (NW > 0) {
+            mWindowsChanged = true;
+        }
         for (int i=0; i<NW; i++) {
             WindowState win = token.windows.get(i);
             if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Tmp removing app window " + win);
             mWindows.remove(win);
-            mWindowsChanged = true;
             int j = win.mChildWindows.size();
             while (j > 0) {
                 j--;
@@ -4521,6 +4553,12 @@
         }
     }
 
+    void dumpAnimatingAppTokensLocked() {
+        for (int i=mAnimatingAppTokens.size()-1; i>=0; i--) {
+            Slog.v(TAG, "  #" + i + ": " + mAnimatingAppTokens.get(i).token);
+        }
+    }
+
     void dumpWindowsLocked() {
         for (int i=mWindows.size()-1; i>=0; i--) {
             Slog.v(TAG, "  #" + i + ": " + mWindows.get(i));
@@ -4530,7 +4568,7 @@
     private int findWindowOffsetLocked(int tokenPos) {
         final int NW = mWindows.size();
 
-        if (tokenPos >= mAppTokens.size()) {
+        if (tokenPos >= mAnimatingAppTokens.size()) {
             int i = NW;
             while (i > 0) {
                 i--;
@@ -4544,7 +4582,7 @@
         while (tokenPos > 0) {
             // Find the first app token below the new position that has
             // a window displayed.
-            final AppWindowToken wtoken = mAppTokens.get(tokenPos-1);
+            final AppWindowToken wtoken = mAnimatingAppTokens.get(tokenPos-1);
             if (DEBUG_REORDER) Slog.v(TAG, "Looking for lower windows @ "
                     + tokenPos + " -- " + wtoken.token);
             if (wtoken.sendingToBottom) {
@@ -4632,9 +4670,16 @@
             if (DEBUG_REORDER) Slog.v(TAG, "Initial app tokens:");
             if (DEBUG_REORDER) dumpAppTokensLocked();
             final AppWindowToken wtoken = findAppWindowToken(token);
+            final int oldIndex = mAppTokens.indexOf(wtoken);
             if (DEBUG_TOKEN_MOVEMENT || DEBUG_REORDER) Slog.v(TAG,
                     "Start moving token " + wtoken + " initially at "
-                    + mAppTokens.indexOf(wtoken));
+                    + oldIndex);
+            if (oldIndex > index && mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET
+                        && !mAppTransitionRunning) {
+                // animation towards back has not started, copy old list for duration of animation.
+                mAnimatingAppTokens.clear();
+                mAnimatingAppTokens.addAll(mAppTokens);
+            }
             if (wtoken == null || !mAppTokens.remove(wtoken)) {
                 Slog.w(TAG, "Attempting to reorder token that doesn't exist: "
                       + token + " (" + wtoken + ")");
@@ -4644,24 +4689,30 @@
             if (DEBUG_REORDER) Slog.v(TAG, "Moved " + token + " to " + index + ":");
             else if (DEBUG_TOKEN_MOVEMENT) Slog.v(TAG, "Moved " + token + " to " + index);
             if (DEBUG_REORDER) dumpAppTokensLocked();
+            if (mNextAppTransition == WindowManagerPolicy.TRANSIT_UNSET && !mAppTransitionRunning) {
+                // Not animating, bring animating app list in line with mAppTokens.
+                mAnimatingAppTokens.clear();
+                mAnimatingAppTokens.addAll(mAppTokens);
 
-            final long origId = Binder.clearCallingIdentity();
-            if (DEBUG_REORDER) Slog.v(TAG, "Removing windows in " + token + ":");
-            if (DEBUG_REORDER) dumpWindowsLocked();
-            if (tmpRemoveAppWindowsLocked(wtoken)) {
-                if (DEBUG_REORDER) Slog.v(TAG, "Adding windows back in:");
+                // Bring window ordering, window focus and input window in line with new app token
+                final long origId = Binder.clearCallingIdentity();
+                if (DEBUG_REORDER) Slog.v(TAG, "Removing windows in " + token + ":");
                 if (DEBUG_REORDER) dumpWindowsLocked();
-                reAddAppWindowsLocked(findWindowOffsetLocked(index), wtoken);
-                if (DEBUG_REORDER) Slog.v(TAG, "Final window list:");
-                if (DEBUG_REORDER) dumpWindowsLocked();
-                updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
-                        false /*updateInputWindows*/);
-                mLayoutNeeded = true;
-                mInputMonitor.setUpdateInputWindowsNeededLw();
-                performLayoutAndPlaceSurfacesLocked();
-                mInputMonitor.updateInputWindowsLw(false /*force*/);
+                if (tmpRemoveAppWindowsLocked(wtoken)) {
+                    if (DEBUG_REORDER) Slog.v(TAG, "Adding windows back in:");
+                    if (DEBUG_REORDER) dumpWindowsLocked();
+                    reAddAppWindowsLocked(findWindowOffsetLocked(index), wtoken);
+                    if (DEBUG_REORDER) Slog.v(TAG, "Final window list:");
+                    if (DEBUG_REORDER) dumpWindowsLocked();
+                    updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
+                            false /*updateInputWindows*/);
+                    mLayoutNeeded = true;
+                    mInputMonitor.setUpdateInputWindowsNeededLw();
+                    performLayoutAndPlaceSurfacesLocked();
+                    mInputMonitor.updateInputWindowsLw(false /*force*/);
+                }
+                Binder.restoreCallingIdentity(origId);
             }
-            Binder.restoreCallingIdentity(origId);
         }
     }
 
@@ -4702,7 +4753,9 @@
                 assignLayersLocked();
             }
             mLayoutNeeded = true;
-            performLayoutAndPlaceSurfacesLocked();
+            if (!mInLayout) {
+                performLayoutAndPlaceSurfacesLocked();
+            }
             mInputMonitor.updateInputWindowsLw(false /*force*/);
         }
     }
@@ -4758,22 +4811,22 @@
                             "Adding next to top: " + wt);
                     mAppTokens.add(wt);
                     if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
-                        mToTopApps.remove(wt);
-                        mToBottomApps.remove(wt);
-                        mToTopApps.add(wt);
                         wt.sendingToBottom = false;
-                        wt.sendingToTop = true;
                     }
                 }
             }
 
-            if (mNextAppTransition == WindowManagerPolicy.TRANSIT_UNSET) {
+            if (mNextAppTransition == WindowManagerPolicy.TRANSIT_UNSET
+                    && !mAppTransitionRunning) {
+                mAnimatingAppTokens.clear();
+                mAnimatingAppTokens.addAll(mAppTokens);
                 moveAppWindowsLocked(tokens, mAppTokens.size());
             }
         }
         Binder.restoreCallingIdentity(origId);
     }
 
+    @Override
     public void moveAppTokensToBottom(List<IBinder> tokens) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                 "moveAppTokensToBottom()")) {
@@ -4782,8 +4835,14 @@
 
         final long origId = Binder.clearCallingIdentity();
         synchronized(mWindowMap) {
-            removeAppTokensLocked(tokens);
             final int N = tokens.size();
+            if (N > 0 && mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET
+                    && !mAppTransitionRunning) {
+                // animating towards back, hang onto old list for duration of animation.
+                mAnimatingAppTokens.clear();
+                mAnimatingAppTokens.addAll(mAppTokens);
+            }
+            removeAppTokensLocked(tokens);
             int pos = 0;
             for (int i=0; i<N; i++) {
                 AppWindowToken wt = findAppWindowToken(tokens.get(i));
@@ -4792,17 +4851,16 @@
                             "Adding next to bottom: " + wt + " at " + pos);
                     mAppTokens.add(pos, wt);
                     if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
-                        mToTopApps.remove(wt);
-                        mToBottomApps.remove(wt);
-                        mToBottomApps.add(i, wt);
-                        wt.sendingToTop = false;
                         wt.sendingToBottom = true;
                     }
                     pos++;
                 }
             }
 
-            if (mNextAppTransition == WindowManagerPolicy.TRANSIT_UNSET) {
+            if (mNextAppTransition == WindowManagerPolicy.TRANSIT_UNSET
+                    && !mAppTransitionRunning) {
+                mAnimatingAppTokens.clear();
+                mAnimatingAppTokens.addAll(mAppTokens);
                 moveAppWindowsLocked(tokens, 0);
             }
         }
@@ -7010,6 +7068,8 @@
                                     "*** APP TRANSITION TIMEOUT");
                             mAppTransitionReady = true;
                             mAppTransitionTimeout = true;
+                            mAnimatingAppTokens.clear();
+                            mAnimatingAppTokens.addAll(mAppTokens);
                             performLayoutAndPlaceSurfacesLocked();
                         }
                     }
@@ -7533,9 +7593,9 @@
         }
 
         // And add in the still active app tokens in Z order.
-        NT = mAppTokens.size();
+        NT = mAnimatingAppTokens.size();
         for (int j=0; j<NT; j++) {
-            i = reAddAppWindowsLocked(i, mAppTokens.get(j));
+            i = reAddAppWindowsLocked(i, mAnimatingAppTokens.get(j));
         }
 
         i -= lastWallpaper;
@@ -7555,7 +7615,7 @@
                 }
             }
             Slog.w(TAG, "Current app token list:");
-            dumpAppTokensLocked();
+            dumpAnimatingAppTokensLocked();
             Slog.w(TAG, "Final window list:");
             dumpWindowsLocked();
         }
@@ -7624,7 +7684,8 @@
             if (DEBUG) {
                 throw new RuntimeException("Recursive call!");
             }
-            Slog.w(TAG, "performLayoutAndPlaceSurfacesLocked called while in layout");
+            Slog.w(TAG, "performLayoutAndPlaceSurfacesLocked called while in layout. Callers="
+                    + Debug.getCallers(3));
             return;
         }
 
@@ -7913,22 +7974,7 @@
 
             mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
 
-            // If there are applications waiting to come to the
-            // top of the stack, now is the time to move their windows.
-            // (Note that we don't do apps going to the bottom
-            // here -- we want to keep their windows in the old
-            // Z-order until the animation completes.)
-            if (mToTopApps.size() > 0) {
-                NN = mAppTokens.size();
-                for (i=0; i<NN; i++) {
-                    AppWindowToken wtoken = mAppTokens.get(i);
-                    if (wtoken.sendingToTop) {
-                        wtoken.sendingToTop = false;
-                        moveAppWindowsLocked(wtoken, NN, false);
-                    }
-                }
-                mToTopApps.clear();
-            }
+            rebuildAppWindowListLocked();
 
             // if wallpaper is animating in or out set oldWallpaper to null else to wallpaper
             WindowState oldWallpaper =
@@ -8155,13 +8201,14 @@
         int changes = 0;
 
         mAppTransitionRunning = false;
-        // Clear information about apps that were moving.
-        mToBottomApps.clear();
-
+        // Restore window app tokens to the ActivityManager views
+        mAnimatingAppTokens.clear();
+        mAnimatingAppTokens.addAll(mAppTokens);
         rebuildAppWindowListLocked();
+
         changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
         mInnerFields.mAdjResult |= ADJUST_WALLPAPER_LAYERS_CHANGED;
-        moveInputMethodWindowsIfNeededLocked(false);
+        moveInputMethodWindowsIfNeededLocked(true);
         mInnerFields.mWallpaperMayChange = true;
         // Since the window list has been rebuilt, focus might
         // have to be recomputed since the actual order of windows
@@ -8242,7 +8289,7 @@
                 // to go through the process of getting informed
                 // by the application when it has finished drawing.
                 if (w.mOrientationChanging) {
-                    if (DEBUG_ANIM || DEBUG_ORIENTATION) Slog.v(TAG,
+                    if (DEBUG_SURFACE_TRACE || DEBUG_ANIM || DEBUG_ORIENTATION) Slog.v(TAG,
                             "Orientation start waiting for draw mDrawState=DRAW_PENDING in "
                             + w + ", surface " + winAnimator.mSurface);
                     winAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING;
@@ -8683,25 +8730,11 @@
                 if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
                         "performLayout: App token exiting now removed" + token);
                 mAppTokens.remove(token);
+                mAnimatingAppTokens.remove(token);
                 mExitingAppTokens.remove(i);
             }
         }
 
-        if (!mAnimator.mAnimating && mAppTransitionRunning) {
-            // We have finished the animation of an app transition.  To do
-            // this, we have delayed a lot of operations like showing and
-            // hiding apps, moving apps in Z-order, etc.  The app token list
-            // reflects the correct Z-order, but the window list may now
-            // be out of sync with it.  So here we will just rebuild the
-            // entire app window list.  Fun!
-            mAppTransitionRunning = false;
-            mLayoutNeeded = true;
-            rebuildAppWindowListLocked();
-            assignLayersLocked();
-            // Clear information about apps that were moving.
-            mToBottomApps.clear();
-        }
-
         if (!mAnimator.mAnimating && mRelayoutWhileAnimating.size() > 0) {
             for (int j=mRelayoutWhileAnimating.size()-1; j>=0; j--) {
                 try {
@@ -9030,7 +9063,7 @@
             AppWindowToken thisApp = win.mAppToken;
 
             // If this window's application has been removed, just skip it.
-            if (thisApp != null && thisApp.removed) {
+            if (thisApp != null && (thisApp.removed || thisApp.sendingToBottom)) {
                 continue;
             }
 
@@ -9433,6 +9466,21 @@
                 }
             }
         }
+        if (mAppTransitionRunning && mAnimatingAppTokens.size() > 0) {
+            pw.println();
+            pw.println("  Application tokens during animation:");
+            for (int i=mAnimatingAppTokens.size()-1; i>=0; i--) {
+                WindowToken token = mAnimatingAppTokens.get(i);
+                pw.print("  App moving to bottom #"); pw.print(i);
+                        pw.print(' '); pw.print(token);
+                if (dumpAll) {
+                    pw.println(':');
+                    token.dump(pw, "    ");
+                } else {
+                    pw.println();
+                }
+            }
+        }
         pw.println();
         if (mOpeningApps.size() > 0) {
             pw.print("  mOpeningApps="); pw.println(mOpeningApps);
@@ -9440,12 +9488,6 @@
         if (mClosingApps.size() > 0) {
             pw.print("  mClosingApps="); pw.println(mClosingApps);
         }
-        if (mToTopApps.size() > 0) {
-            pw.print("  mToTopApps="); pw.println(mToTopApps);
-        }
-        if (mToBottomApps.size() > 0) {
-            pw.print("  mToBottomApps="); pw.println(mToBottomApps);
-        }
     }
 
     void dumpSessionsLocked(FileDescriptor fd, PrintWriter pw, boolean dumpAll) {
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index e2a904f..8f2ef76 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -841,7 +841,9 @@
         }
     }
 
-    /** Returns true if this window desires key events. */
+    /** Returns true if this window desires key events.
+     * TODO(cmautner): Is this the same as {@link WindowManagerService#canBeImeTarget}
+     */
     public final boolean canReceiveKeys() {
         return     isVisibleOrAdding()
                 && (mViewVisibility == View.VISIBLE)
diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java
index 355db6e..affe5d4 100644
--- a/services/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/java/com/android/server/wm/WindowStateAnimator.java
@@ -403,8 +403,8 @@
 
     boolean finishDrawingLocked() {
         if (mDrawState == DRAW_PENDING) {
-            if (DEBUG_ANIM || SHOW_TRANSACTIONS || DEBUG_ORIENTATION) Slog.v(
-                TAG, "finishDrawingLocked: mDrawState=COMMIT_DRAW_PENDING " + this + " in "
+            if (DEBUG_SURFACE_TRACE || DEBUG_ANIM || SHOW_TRANSACTIONS || DEBUG_ORIENTATION)
+                Slog.v(TAG, "finishDrawingLocked: mDrawState=COMMIT_DRAW_PENDING " + this + " in "
                         + mSurface);
             mDrawState = COMMIT_DRAW_PENDING;
             return true;
@@ -417,7 +417,7 @@
         if (mDrawState != COMMIT_DRAW_PENDING) {
             return false;
         }
-        if (DEBUG_ANIM)
+        if (DEBUG_SURFACE_TRACE || DEBUG_ANIM)
             Slog.i(TAG, "commitFinishDrawingLocked: mDrawState=READY_TO_SHOW " + mSurface);
         mDrawState = READY_TO_SHOW;
         final boolean starting = mWin.mAttrs.type == TYPE_APPLICATION_STARTING;
@@ -504,7 +504,9 @@
         @Override
         public void setWindowCrop(Rect crop) {
             super.setWindowCrop(crop);
-            mWindowCrop.set(crop);
+            if (crop != null) {
+                mWindowCrop.set(crop);
+            }
             Slog.v(SURFACE_TAG, "setWindowCrop: " + this + ". Called by "
                     + Debug.getCallers(3));
         }
@@ -1232,7 +1234,8 @@
 
             // Force the show in the next prepareSurfaceLocked() call.
             mLastAlpha = -1;
-            if (DEBUG_ANIM) Slog.v(TAG, "performShowLocked: mDrawState=HAS_DRAWN");
+            if (DEBUG_SURFACE_TRACE || DEBUG_ANIM)
+                Slog.v(TAG, "performShowLocked: mDrawState=HAS_DRAWN in " + this);
             mDrawState = HAS_DRAWN;
             mService.scheduleAnimationLocked();
 
diff --git a/services/java/com/android/server/wm/WindowToken.java b/services/java/com/android/server/wm/WindowToken.java
index 3cd256e..5ec151b 100644
--- a/services/java/com/android/server/wm/WindowToken.java
+++ b/services/java/com/android/server/wm/WindowToken.java
@@ -71,10 +71,6 @@
     // windows will be put to the bottom of the list.
     boolean sendingToBottom;
 
-    // Set to true when this token is in a pending transaction where its
-    // windows will be put to the top of the list.
-    boolean sendingToTop;
-
     WindowToken(WindowManagerService _service, IBinder _token, int type, boolean _explicit) {
         service = _service;
         token = _token;
@@ -88,11 +84,10 @@
         pw.print(prefix); pw.print("windowType="); pw.print(windowType);
                 pw.print(" hidden="); pw.print(hidden);
                 pw.print(" hasVisible="); pw.println(hasVisible);
-        if (waitingToShow || waitingToHide || sendingToBottom || sendingToTop) {
+        if (waitingToShow || waitingToHide || sendingToBottom) {
             pw.print(prefix); pw.print("waitingToShow="); pw.print(waitingToShow);
                     pw.print(" waitingToHide="); pw.print(waitingToHide);
                     pw.print(" sendingToBottom="); pw.print(sendingToBottom);
-                    pw.print(" sendingToTop="); pw.println(sendingToTop);
         }
     }