Merge "Advise persist threshold outside NPMS lock." 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/app/Notification.java b/core/java/android/app/Notification.java
index 618f1f8..3ced82b 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1689,6 +1689,8 @@
      */
     public static class BigPictureStyle extends Style {
         private Bitmap mPicture;
+        private Bitmap mBigLargeIcon;
+        private boolean mBigLargeIconSet = false;
 
         public BigPictureStyle() {
         }
@@ -1719,6 +1721,16 @@
             return this;
         }
 
+        /**
+         * @hide
+         * Override the large icon when the big notification is shown.
+         */
+        public BigPictureStyle bigLargeIcon(Bitmap b) {
+            mBigLargeIconSet = true;
+            mBigLargeIcon = b;
+            return this;
+        }
+
         private RemoteViews makeBigContentView() {
             RemoteViews contentView = getStandardView(R.layout.notification_template_big_picture);
 
@@ -1731,6 +1743,9 @@
         public Notification build() {
             checkBuilder();
             Notification wip = mBuilder.buildUnstyled();
+            if (mBigLargeIconSet ) {
+                mBuilder.mLargeIcon = mBigLargeIcon;
+            }
             wip.bigContentView = makeBigContentView();
             return wip;
         }
diff --git a/core/java/android/inputmethodservice/KeyboardView.java b/core/java/android/inputmethodservice/KeyboardView.java
index 7257521..4916244 100644
--- a/core/java/android/inputmethodservice/KeyboardView.java
+++ b/core/java/android/inputmethodservice/KeyboardView.java
@@ -855,15 +855,23 @@
                 Key oldKey = keys[oldKeyIndex];
                 oldKey.onReleased(mCurrentKeyIndex == NOT_A_KEY);
                 invalidateKey(oldKeyIndex);
+                final int keyCode = oldKey.codes[0];
                 sendAccessibilityEventForUnicodeCharacter(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT,
-                        oldKey.codes[0]);
+                        keyCode);
+                // TODO: We need to implement AccessibilityNodeProvider for this view.
+                sendAccessibilityEventForUnicodeCharacter(
+                        AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED, keyCode);
             }
             if (mCurrentKeyIndex != NOT_A_KEY && keys.length > mCurrentKeyIndex) {
                 Key newKey = keys[mCurrentKeyIndex];
                 newKey.onPressed();
                 invalidateKey(mCurrentKeyIndex);
+                final int keyCode = newKey.codes[0];
                 sendAccessibilityEventForUnicodeCharacter(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER,
-                        newKey.codes[0]);
+                        keyCode);
+                // TODO: We need to implement AccessibilityNodeProvider for this view.
+                sendAccessibilityEventForUnicodeCharacter(
+                        AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED, keyCode);
             }
         }
         // If key changed and preview is on ...
@@ -1154,20 +1162,17 @@
         if (mAccessibilityManager.isTouchExplorationEnabled() && event.getPointerCount() == 1) {
             final int action = event.getAction();
             switch (action) {
-                case MotionEvent.ACTION_HOVER_ENTER:
-                case MotionEvent.ACTION_HOVER_MOVE:
-                    final int touchX = (int) event.getX() - mPaddingLeft;
-                    int touchY = (int) event.getY() - mPaddingTop;
-                    if (touchY >= -mVerticalCorrection) {
-                        touchY += mVerticalCorrection;
-                    }
-                    final int keyIndex = getKeyIndices(touchX, touchY, null);
-                    showPreview(keyIndex);
-                    break;
-                case MotionEvent.ACTION_HOVER_EXIT:
-                    showPreview(NOT_A_KEY);
-                    break;
+                case MotionEvent.ACTION_HOVER_ENTER: {
+                    event.setAction(MotionEvent.ACTION_DOWN);
+                } break;
+                case MotionEvent.ACTION_HOVER_MOVE: {
+                    event.setAction(MotionEvent.ACTION_MOVE);
+                } break;
+                case MotionEvent.ACTION_HOVER_EXIT: {
+                    event.setAction(MotionEvent.ACTION_UP);
+                } break;
             }
+            return onTouchEvent(event);
         }
         return true;
     }
diff --git a/core/java/android/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index 2c4b8631..79c8f3b 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -16,6 +16,7 @@
 
 package android.os.storage;
 
+import android.content.Context;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -28,7 +29,7 @@
     //private static final String TAG = "StorageVolume";
 
     private final String mPath;
-    private final String mDescription;
+    private final int mDescriptionId;
     private final boolean mRemovable;
     private final boolean mEmulated;
     private final int mMtpReserveSpace;
@@ -42,10 +43,10 @@
     // ACTION_MEDIA_BAD_REMOVAL, ACTION_MEDIA_UNMOUNTABLE and ACTION_MEDIA_EJECT broadcasts.
     public static final String EXTRA_STORAGE_VOLUME = "storage_volume";
 
-    public StorageVolume(String path, String description, boolean removable,
+    public StorageVolume(String path, int descriptionId, boolean removable,
             boolean emulated, int mtpReserveSpace, boolean allowMassStorage, long maxFileSize) {
         mPath = path;
-        mDescription = description;
+        mDescriptionId = descriptionId;
         mRemovable = removable;
         mEmulated = emulated;
         mMtpReserveSpace = mtpReserveSpace;
@@ -54,11 +55,11 @@
     }
 
     // for parcelling only
-    private StorageVolume(String path, String description, boolean removable,
+    private StorageVolume(String path, int descriptionId, boolean removable,
             boolean emulated, int mtpReserveSpace, int storageId,
             boolean allowMassStorage, long maxFileSize) {
         mPath = path;
-        mDescription = description;
+        mDescriptionId = descriptionId;
         mRemovable = removable;
         mEmulated = emulated;
         mMtpReserveSpace = mtpReserveSpace;
@@ -81,8 +82,12 @@
      *
      * @return the volume description
      */
-    public String getDescription() {
-        return mDescription;
+    public String getDescription(Context context) {
+        return context.getResources().getString(mDescriptionId);
+    }
+
+    public int getDescriptionId() {
+        return mDescriptionId;
     }
 
     /**
@@ -172,8 +177,8 @@
 
     @Override
     public String toString() {
-        return "StorageVolume [mAllowMassStorage=" + mAllowMassStorage + ", mDescription="
-                + mDescription + ", mEmulated=" + mEmulated + ", mMaxFileSize=" + mMaxFileSize
+        return "StorageVolume [mAllowMassStorage=" + mAllowMassStorage + ", mDescriptionId="
+                + mDescriptionId + ", mEmulated=" + mEmulated + ", mMaxFileSize=" + mMaxFileSize
                 + ", mMtpReserveSpace=" + mMtpReserveSpace + ", mPath=" + mPath + ", mRemovable="
                 + mRemovable + ", mStorageId=" + mStorageId + "]";
     }
@@ -182,14 +187,14 @@
         new Parcelable.Creator<StorageVolume>() {
         public StorageVolume createFromParcel(Parcel in) {
             String path = in.readString();
-            String description = in.readString();
+            int descriptionId = in.readInt();
             int removable = in.readInt();
             int emulated = in.readInt();
             int storageId = in.readInt();
             int mtpReserveSpace = in.readInt();
             int allowMassStorage = in.readInt();
             long maxFileSize = in.readLong();
-            return new StorageVolume(path, description,
+            return new StorageVolume(path, descriptionId,
                     removable == 1, emulated == 1, mtpReserveSpace,
                     storageId, allowMassStorage == 1, maxFileSize);
         }
@@ -205,7 +210,7 @@
 
     public void writeToParcel(Parcel parcel, int flags) {
         parcel.writeString(mPath);
-        parcel.writeString(mDescription);
+        parcel.writeInt(mDescriptionId);
         parcel.writeInt(mRemovable ? 1 : 0);
         parcel.writeInt(mEmulated ? 1 : 0);
         parcel.writeInt(mStorageId);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 832d575..20eef11 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -6196,23 +6196,23 @@
      * @hide
      */
     public void clearAccessibilityFocus() {
-        ViewRootImpl viewRootImpl = getViewRootImpl();
-        if (viewRootImpl != null) {
-            View focusHost = viewRootImpl.getAccessibilityFocusedHost();
-            if (focusHost != null && focusHost != this
-                    && ViewRootImpl.isViewDescendantOf(focusHost, this)) {
-                viewRootImpl.setAccessibilityFocusedHost(null);
-            }
-        }
         if ((mPrivateFlags2 & ACCESSIBILITY_FOCUSED) != 0) {
             mPrivateFlags2 &= ~ACCESSIBILITY_FOCUSED;
             invalidate();
             sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED);
             notifyAccessibilityStateChanged();
-
             // Clear the text navigation state.
             setAccessibilityCursorPosition(-1);
         }
+        // Clear the global reference of accessibility focus if this
+        // view or any of its descendants had accessibility focus.
+        ViewRootImpl viewRootImpl = getViewRootImpl();
+        if (viewRootImpl != null) {
+            View focusHost = viewRootImpl.getAccessibilityFocusedHost();
+            if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) {
+                viewRootImpl.setAccessibilityFocusedHost(null);
+            }
+        }
     }
 
     private void requestAccessibilityFocusFromHover() {
@@ -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/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 1803352..d2cc2d8 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -283,6 +283,7 @@
      * The InputConnection that was last retrieved from the served view.
      */
     InputConnection mServedInputConnection;
+    ControlledInputConnectionWrapper mServedInputConnectionWrapper;
     /**
      * The completions that were last provided by the served view.
      */
@@ -418,16 +419,22 @@
     
     private static class ControlledInputConnectionWrapper extends IInputConnectionWrapper {
         private final InputMethodManager mParentInputMethodManager;
+        private boolean mActive;
 
         public ControlledInputConnectionWrapper(final Looper mainLooper, final InputConnection conn,
                 final InputMethodManager inputMethodManager) {
             super(mainLooper, conn);
             mParentInputMethodManager = inputMethodManager;
+            mActive = true;
         }
 
         @Override
         public boolean isActive() {
-            return mParentInputMethodManager.mActive;
+            return mParentInputMethodManager.mActive && mActive;
+        }
+
+        void deactivate() {
+            mActive = false;
         }
     }
     
@@ -666,6 +673,10 @@
     void clearConnectionLocked() {
         mCurrentTextBoxAttribute = null;
         mServedInputConnection = null;
+        if (mServedInputConnectionWrapper != null) {
+            mServedInputConnectionWrapper.deactivate();
+            mServedInputConnectionWrapper = null;
+        }
     }
     
     /**
@@ -1060,7 +1071,7 @@
             // Notify the served view that its previous input connection is finished
             notifyInputConnectionFinished();
             mServedInputConnection = ic;
-            IInputContext servedContext;
+            ControlledInputConnectionWrapper servedContext;
             if (ic != null) {
                 mCursorSelStart = tba.initialSelStart;
                 mCursorSelEnd = tba.initialSelEnd;
@@ -1071,6 +1082,10 @@
             } else {
                 servedContext = null;
             }
+            if (mServedInputConnectionWrapper != null) {
+                mServedInputConnectionWrapper.deactivate();
+            }
+            mServedInputConnectionWrapper = servedContext;
             
             try {
                 if (DEBUG) Log.v(TAG, "START INPUT: " + view + " ic="
@@ -1286,6 +1301,7 @@
         // we'll just do a window focus gain and call it a day.
         synchronized (mH) {
             try {
+                if (DEBUG) Log.v(TAG, "Reporting focus gain, without startInput");
                 mService.windowGainedFocus(mClient, rootView.getWindowToken(),
                         controlFlags, softInputMode, windowFlags, null, null);
             } catch (RemoteException e) {
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/FindActionModeCallback.java b/core/java/android/webkit/FindActionModeCallback.java
index 6b7263c..1a4ccfa 100644
--- a/core/java/android/webkit/FindActionModeCallback.java
+++ b/core/java/android/webkit/FindActionModeCallback.java
@@ -34,7 +34,7 @@
 import android.widget.TextView;
 
 class FindActionModeCallback implements ActionMode.Callback, TextWatcher,
-        View.OnLongClickListener, View.OnClickListener {
+        View.OnClickListener {
     private View mCustomView;
     private EditText mEditText;
     private TextView mMatches;
@@ -51,9 +51,7 @@
                 com.android.internal.R.layout.webview_find, null);
         mEditText = (EditText) mCustomView.findViewById(
                 com.android.internal.R.id.edit);
-        // Override long click so that select ActionMode is not opened, which
-        // would exit find ActionMode.
-        mEditText.setOnLongClickListener(this);
+        mEditText.setCustomSelectionActionModeCallback(new NoAction());
         mEditText.setOnClickListener(this);
         setText("");
         mMatches = (TextView) mCustomView.findViewById(
@@ -174,11 +172,6 @@
         mMatches.setVisibility(View.VISIBLE);
     }
 
-    // OnLongClickListener implementation
-
-    @Override
-    public boolean onLongClick(View v) { return true; }
-
     // OnClickListener implementation
 
     @Override
@@ -280,4 +273,24 @@
         return mGlobalVisibleRect.bottom;
     }
 
+    public static class NoAction implements ActionMode.Callback {
+        @Override
+        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+            return false;
+        }
+
+        @Override
+        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+            return false;
+        }
+
+        @Override
+        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+            return false;
+        }
+
+        @Override
+        public void onDestroyActionMode(ActionMode mode) {
+        }
+    }
 }
diff --git a/core/java/android/webkit/WebViewClassic.java b/core/java/android/webkit/WebViewClassic.java
index b4a312d..f03fb86 100644
--- a/core/java/android/webkit/WebViewClassic.java
+++ b/core/java/android/webkit/WebViewClassic.java
@@ -1670,8 +1670,8 @@
             return mWebViewPrivate.super_performAccessibilityAction(action, arguments);
         }
 
-        if (mAccessibilityInjector.supportsAccessibilityAction(action)) {
-            return mAccessibilityInjector.performAccessibilityAction(action, arguments);
+        if (getAccessibilityInjector().supportsAccessibilityAction(action)) {
+            return getAccessibilityInjector().performAccessibilityAction(action, arguments);
         }
 
         switch (action) {
@@ -1722,7 +1722,7 @@
             info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
         }
 
-        mAccessibilityInjector.onInitializeAccessibilityNodeInfo(info);
+        getAccessibilityInjector().onInitializeAccessibilityNodeInfo(info);
     }
 
     @Override
@@ -2069,6 +2069,20 @@
     }
 
     private void destroyImpl() {
+        ViewRootImpl viewRoot = mWebView.getViewRootImpl();
+        if (viewRoot != null) {
+            Log.e(LOGTAG, "Error: WebView.destroy() called while still attached!");
+        }
+
+        if (mWebView.isHardwareAccelerated()) {
+            int drawGLFunction = nativeGetDrawGLFunction(mNativeClass);
+            if (drawGLFunction != 0 && viewRoot != null) {
+                // functor should have been detached in onDetachedFromWindow, do
+                // additionally here for safety
+                viewRoot.detachFunctor(drawGLFunction);
+            }
+        }
+
         mCallbackProxy.blockMessages();
         clearHelpers();
         if (mListBoxDialog != null) {
@@ -7858,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;
@@ -8480,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/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 5fa4ad0..f442912 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1253,13 +1253,13 @@
             unregisterForScrollChanged();
 
             try {
-                mWindowManager.removeView(mPopupView);                
+                mWindowManager.removeViewImmediate(mPopupView);
             } finally {
                 if (mPopupView != mContentView && mPopupView instanceof ViewGroup) {
                     ((ViewGroup) mPopupView).removeView(mContentView);
                 }
                 mPopupView = null;
-    
+
                 if (mOnDismissListener != null) {
                     mOnDismissListener.onDismiss();
                 }
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index f266d50..46ec923 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -614,7 +614,7 @@
                     maxDistIndexNonRequested = i;
                     maxDistNonRequested = dist;
                 }
-                if (dist > maxDist) {
+                if (dist >= maxDist) {
                     // maxDist/maxDistIndex will store the index of the farthest position
                     // regardless of whether it was directly requested or not
                     maxDistIndex = i;
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/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index 2cbd9cc902..234cb71 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -708,7 +708,15 @@
             anim.start();
         } else {
             mTopVisibilityView.setAlpha(1);
-            mContainerView.setTranslationY(0);
+            mTopVisibilityView.setTranslationY(0);
+            if (mContentView != null) {
+                mContentView.setTranslationY(0);
+            }
+            if (mSplitView != null && mContextDisplayMode == CONTEXT_DISPLAY_SPLIT) {
+                mSplitView.setAlpha(1);
+                mSplitView.setTranslationY(0);
+                mSplitView.setVisibility(View.VISIBLE);
+            }
             mShowListener.onAnimationEnd(null);
         }
         if (mOverlayLayout != null) {
diff --git a/core/java/com/android/internal/app/PlatLogoActivity.java b/core/java/com/android/internal/app/PlatLogoActivity.java
index e9db9d9..3a2b647 100644
--- a/core/java/com/android/internal/app/PlatLogoActivity.java
+++ b/core/java/com/android/internal/app/PlatLogoActivity.java
@@ -92,7 +92,7 @@
         getWindowManager().getDefaultDisplay().getMetrics(metrics);
 
         mContent = new ImageView(this);
-        mContent.setImageResource(com.android.internal.R.drawable.platlogo);
+        mContent.setImageResource(com.android.internal.R.drawable.platlogo_alt);
         mContent.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
         
         final int p = (int)(32 * metrics.density);
@@ -102,7 +102,7 @@
             @Override
             public void onClick(View v) {
                 mToast.show();
-                mContent.setImageResource(com.android.internal.R.drawable.platlogo_alt);
+                mContent.setImageResource(com.android.internal.R.drawable.platlogo);
             }
         });
 
diff --git a/core/res/res/drawable-nodpi/platlogo.png b/core/res/res/drawable-nodpi/platlogo.png
index f46c6c6..63b53b8 100644
--- a/core/res/res/drawable-nodpi/platlogo.png
+++ b/core/res/res/drawable-nodpi/platlogo.png
Binary files differ
diff --git a/core/res/res/drawable-nodpi/platlogo_alt.png b/core/res/res/drawable-nodpi/platlogo_alt.png
index 63b53b8..f46c6c6 100644
--- a/core/res/res/drawable-nodpi/platlogo_alt.png
+++ b/core/res/res/drawable-nodpi/platlogo_alt.png
Binary files differ
diff --git a/core/res/res/layout-sw600dp/keyguard_screen_unlock_landscape.xml b/core/res/res/layout-sw600dp/keyguard_screen_unlock_landscape.xml
index 68499f4..3bdc7b6 100644
--- a/core/res/res/layout-sw600dp/keyguard_screen_unlock_landscape.xml
+++ b/core/res/res/layout-sw600dp/keyguard_screen_unlock_landscape.xml
@@ -39,7 +39,16 @@
             android:layout_height="wrap_content"
             android:layout_marginBottom="24dip">
 
-            <!-- Music transport control underneath -->
+            <include layout="@layout/keyguard_screen_status_land"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="50dip"
+                android:layout_marginTop="50dip"
+                android:layout_marginBottom="50dip"
+                android:layout_marginRight="64dip"
+                android:layout_alignParentTop="true"
+                android:layout_alignParentLeft="true"/>
+
             <include android:id="@+id/transport"
                 layout="@layout/keyguard_transport_control"
                 android:layout_row="0"
@@ -51,16 +60,6 @@
                 android:layout_height="512dip"
                 />
 
-            <include layout="@layout/keyguard_screen_status_land"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginLeft="50dip"
-                android:layout_marginTop="50dip"
-                android:layout_marginBottom="50dip"
-                android:layout_marginRight="64dip"
-                android:layout_alignParentTop="true"
-                android:layout_alignParentLeft="true"/>
-
         </RelativeLayout>
 
     </RelativeLayout>
diff --git a/core/res/res/layout-sw600dp/keyguard_screen_unlock_portrait.xml b/core/res/res/layout-sw600dp/keyguard_screen_unlock_portrait.xml
index 086757d..bd9de20 100644
--- a/core/res/res/layout-sw600dp/keyguard_screen_unlock_portrait.xml
+++ b/core/res/res/layout-sw600dp/keyguard_screen_unlock_portrait.xml
@@ -26,7 +26,7 @@
     <!-- top: status -->
     <RelativeLayout
         android:layout_height="0dip"
-        android:layout_weight="1"
+        android:layout_weight="0.40"
         android:layout_width="match_parent"
         android:gravity="center">
 
@@ -35,6 +35,14 @@
             android:layout_height="wrap_content"
             android:gravity="center">
 
+            <include layout="@layout/keyguard_screen_status_land"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="50dip"
+                android:layout_marginTop="50dip"
+                android:layout_alignParentTop="true"
+                android:layout_alignParentLeft="true"/>
+
             <!-- Music transport control -->
             <include android:id="@+id/transport"
                 layout="@layout/keyguard_transport_control"
@@ -47,23 +55,13 @@
                 android:layout_height="512dip"
                 />
 
-            <include layout="@layout/keyguard_screen_status_land"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginLeft="50dip"
-                android:layout_marginTop="50dip"
-                android:layout_marginBottom="100dip"
-                android:layout_marginRight="64dip"
-                android:layout_alignParentTop="true"
-                android:layout_alignParentLeft="true"/>
-
         </RelativeLayout>
 
     </RelativeLayout>
 
     <!-- bottom: lock pattern, emergency dialer and forgot pattern button -->
     <RelativeLayout
-        android:layout_weight="1"
+        android:layout_weight="0.60"
         android:layout_width="match_parent"
         android:layout_height="0dip"
         android:gravity="center">
@@ -77,7 +75,6 @@
             <com.android.internal.widget.LockPatternView android:id="@+id/lockPattern"
                 android:layout_width="354dip"
                 android:layout_height="354dip"
-                android:layout_marginTop="50dip"
             />
 
             <!-- Emergency and forgot pattern buttons. -->
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/core/res/res/layout/notification_template_big_picture.xml b/core/res/res/layout/notification_template_big_picture.xml
index 9b896a4..077616e 100644
--- a/core/res/res/layout/notification_template_big_picture.xml
+++ b/core/res/res/layout/notification_template_big_picture.xml
@@ -38,8 +38,25 @@
         android:scaleType="fitXY"
         android:src="@drawable/title_bar_shadow"
         />
-    <include layout="@layout/notification_template_base" 
+    <include layout="@layout/notification_template_base"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         />
+  <FrameLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="208dp"
+        android:layout_marginLeft="64dp"
+        android:layout_gravity="bottom"
+        android:background="#CC111111"
+        >
+        <include
+            layout="@layout/notification_action_list"
+            android:id="@+id/actions"
+            android:layout_marginLeft="8dp"
+            android:layout_gravity="bottom"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            />
+    </FrameLayout>
 </FrameLayout>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index f1f67eb..a143feb 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -785,6 +785,7 @@
   <java-symbol type="string" name="serviceNotProvisioned" />
   <java-symbol type="string" name="serviceRegistered" />
   <java-symbol type="string" name="setup_autofill" />
+  <java-symbol type="string" name="share" />
   <java-symbol type="string" name="shareactionprovider_share_with" />
   <java-symbol type="string" name="shareactionprovider_share_with_application" />
   <java-symbol type="string" name="short_format_month" />
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index a5f653a..546925e 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -296,7 +296,8 @@
         indent[i] = ' ';
     }
     indent[count] = '\0';
-    ALOGD("%sStart display list (%p, %s)", (char*) indent + 2, this, mName.string());
+    ALOGD("%sStart display list (%p, %s, render=%d)", (char*) indent + 2, this,
+            mName.string(), isRenderable());
 
     ALOGD("%s%s %d", indent, "Save", SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
     int saveCount = renderer.getSaveCount() - 1;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 50f5d57..2a8b32c 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -170,21 +170,32 @@
 
 void OpenGLRenderer::prepareDirty(float left, float top, float right, float bottom, bool opaque) {
     mCaches.clearGarbage();
-    mFunctors.clear();
 
     mSnapshot = new Snapshot(mFirstSnapshot,
             SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
     mSnapshot->fbo = getTargetFbo();
     mSaveCount = 1;
 
-    glViewport(0, 0, mWidth, mHeight);
-    mCaches.setScissor(left, mSnapshot->height - bottom, right - left, bottom - top);
-
     mSnapshot->setClip(left, top, right, bottom);
-    mDirtyClip = false;
+    mDirtyClip = opaque;
+
+    syncState();
 
     if (!opaque) {
+        mCaches.setScissor(left, mSnapshot->height - bottom, right - left, bottom - top);
         glClear(GL_COLOR_BUFFER_BIT);
+    } else {
+        mCaches.resetScissor();
+    }
+}
+
+void OpenGLRenderer::syncState() {
+    glViewport(0, 0, mWidth, mHeight);
+
+    if (mCaches.blend) {
+        glEnable(GL_BLEND);
+    } else {
+        glDisable(GL_BLEND);
     }
 }
 
@@ -291,11 +302,6 @@
         }
     }
 
-    // Restore state possibly changed by the functors in process mode
-    GLboolean value;
-    glGetBooleanv(GL_BLEND, &value);
-    mCaches.blend = value;
-
     mCaches.activeTexture(0);
 
     return result;
@@ -303,6 +309,8 @@
 
 status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) {
     interrupt();
+    detachFunctor(functor);
+
     if (mDirtyClip) {
         setScissorFromClip();
     }
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index bf136ad..ad83b31 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -215,6 +215,12 @@
 
 private:
     /**
+     * Ensures the state of the renderer is the same as the state of
+     * the GL context.
+     */
+    void syncState();
+
+    /**
      * Saves the current state of the renderer as a new snapshot.
      * The new snapshot is saved in mSnapshot and the previous snapshot
      * is linked from mSnapshot->previous.
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 987c0ac..c6c1ccb 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -1444,7 +1444,9 @@
         String where;
         String[] selectionArgs;
         if (mCaseInsensitivePaths) {
-            where = Files.FileColumns.DATA + " LIKE ?";
+            // the 'like' makes it use the index, the 'lower()' makes it correct
+            // when the path contains sqlite wildcard characters
+            where = "_data LIKE ?1 AND lower(_data)=lower(?1)";
             selectionArgs = new String[] { path };
         } else {
             where = Files.FileColumns.DATA + "=?";
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index 18aa4b3..c365e4c 100755
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -932,8 +932,11 @@
             if (format == MtpConstants.FORMAT_ASSOCIATION) {
                 // recursive case - delete all children first
                 Uri uri = Files.getMtpObjectsUri(mVolumeName);
-                int count = mMediaProvider.delete(uri, "_data LIKE ?",
-                        new String[] { path + "/%"});
+                int count = mMediaProvider.delete(uri,
+                        // the 'like' makes it use the index, the 'lower()' makes it correct
+                        // when the path contains sqlite wildcard characters
+                        "_data LIKE ? AND lower(substr(_data,?))=lower(?)",
+                        new String[] { path + "/%", "" + path.length() + 1, path + "/"});
             }
 
             Uri uri = Files.getMtpObjectsUri(mVolumeName, handle);
diff --git a/media/java/android/mtp/MtpStorage.java b/media/java/android/mtp/MtpStorage.java
index da190a6..2f47aad 100644
--- a/media/java/android/mtp/MtpStorage.java
+++ b/media/java/android/mtp/MtpStorage.java
@@ -16,6 +16,7 @@
 
 package android.mtp;
 
+import android.content.Context;
 import android.os.storage.StorageVolume;
 
 /**
@@ -34,10 +35,10 @@
     private final boolean mRemovable;
     private final long mMaxFileSize;
 
-    public MtpStorage(StorageVolume volume) {
+    public MtpStorage(StorageVolume volume, Context context) {
         mStorageId = volume.getStorageId();
         mPath = volume.getPath();
-        mDescription = volume.getDescription();
+        mDescription = context.getResources().getString(volume.getDescriptionId());
         mReserveSpace = volume.getMtpReserveSpace();
         mRemovable = volume.isRemovable();
         mMaxFileSize = volume.getMaxFileSize();
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/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index c9957f5..637c403 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -55,7 +55,7 @@
         android:allowBackup="false"
         android:hardwareAccelerated="true"
         android:label="@string/app_label"
-        android:icon="@drawable/ic_launcher_settings">
+        android:icon="@*android:drawable/platlogo">
 
         <!-- Broadcast receiver that gets the broadcast at boot time and starts
              up everything else.
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_menu_share.png b/packages/SystemUI/res/drawable-hdpi/ic_menu_share.png
new file mode 100644
index 0000000..11ab480
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_menu_share.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_menu_share.png b/packages/SystemUI/res/drawable-mdpi/ic_menu_share.png
new file mode 100644
index 0000000..30e69bb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_menu_share.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_menu_share.png b/packages/SystemUI/res/drawable-xhdpi/ic_menu_share.png
new file mode 100644
index 0000000..af3e112
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_menu_share.png
Binary files differ
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index b1611d1..0b362d1 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -59,7 +59,7 @@
     <dimen name="notification_max_height">256dp</dimen>
 
     <!-- Height of a small notification in the status bar plus glow, padding, etc -->
-    <dimen name="notification_row_min_height">72dp</dimen>
+    <dimen name="notification_row_min_height">70dp</dimen>
 
     <!-- Height of a large notification in the status bar plus glow, padding, etc -->
     <dimen name="notification_row_max_height">260dp</dimen>
@@ -74,7 +74,7 @@
     <dimen name="status_bar_icon_padding">0dp</dimen>
 
     <!-- half the distance between notifications in the panel -->
-    <dimen name="notification_divider_height">4dp</dimen>
+    <dimen name="notification_divider_height">3dp</dimen>
 
     <!-- Notification drawer tuning parameters (phone UI) -->
     <!-- Initial velocity of the shade when expanding on its own -->
diff --git a/packages/SystemUI/src/com/android/systemui/BeanBag.java b/packages/SystemUI/src/com/android/systemui/BeanBag.java
index e4f00d6..616d72f 100644
--- a/packages/SystemUI/src/com/android/systemui/BeanBag.java
+++ b/packages/SystemUI/src/com/android/systemui/BeanBag.java
@@ -81,6 +81,10 @@
             return (float) Math.sqrt(x*x+y*y);
         }
 
+        static float clamp(float x, float a, float b) {
+            return ((x<a)?a:((x>b)?b:x));
+        }
+
         static float dot(float x1, float y1, float x2, float y2) {
             return x1*x2+y1+y2;
         }
@@ -149,6 +153,7 @@
             public boolean grabbed;
             public float grabx, graby;
             public long grabtime;
+            private float grabx_offset, graby_offset;
 
             public Bean(Context context, AttributeSet as) {
                 super(context, as);
@@ -236,17 +241,20 @@
                 switch (e.getAction()) {
                     case MotionEvent.ACTION_DOWN:
                         grabbed = true;
+                        grabx_offset = e.getRawX() - x;
+                        graby_offset = e.getRawY() - y;
                         va = 0;
                         // fall
                     case MotionEvent.ACTION_MOVE:
-                        grabx = e.getRawX();
-                        graby = e.getRawY();
+                        grabx = e.getRawX() - grabx_offset;
+                        graby = e.getRawY() - graby_offset;
                         grabtime = e.getEventTime();
                         break;
                     case MotionEvent.ACTION_CANCEL:
                     case MotionEvent.ACTION_UP:
                         grabbed = false;
-                        va = randfrange(-5,5);
+                        float a = randsign() * clamp(mag(vx, vy) * 0.33f, 0, 1080f);
+                        va = randfrange(a*0.5f, a);
                         break;
                 }
                 return true;
@@ -308,47 +316,6 @@
                             if (!(v2 instanceof Bean)) continue;
                             Bean nv2 = (Bean) v2;
                             final float overlap = nv.overlap(nv2);
-                            if (false && overlap < 0) {
-                                // angle pointing from nv2 to nv
-                                final float dx = nv.x - nv2.x;
-                                final float dy = nv.y - nv2.y;
-                                final float ang = (float) Math.atan2(dx, dy);
-
-                                if (false) {
-                                nv.vx -= Math.cos(ang) * overlap * 0.5f;
-                                nv.vy -= Math.sin(ang) * overlap * 0.5f;
-                                nv2.vx += Math.cos(ang) * overlap * 0.5f;
-                                nv2.vy += Math.sin(ang) * overlap * 0.5f;
-                                }
-
-
-                                // first, move them apart
-                                nv.x -= Math.cos(ang) * overlap/2;
-                                nv.y -= Math.sin(ang) * overlap/2;
-                                nv2.x += Math.cos(ang) * overlap/2;
-                                nv2.y += Math.sin(ang) * overlap/2;
-
-                                // next, figure out velocities
-                                final float sap = 0f; // randfrange(0,0.25f);
-
-                                final float mag1 = mag(nv.vx, nv.vy) * (1f-sap);
-                                final float mag2 = mag(nv2.vx, nv2.vy) * (1f-sap);
-
-
-                                // hacky way to transfer "momentum"
-                                nv.vx = mag2 * (float)Math.cos(ang);
-                                nv.vy = mag2 * (float)Math.sin(ang);
-                                nv2.vx = -mag1 * (float)Math.cos(ang);
-                                nv2.vy = -mag1 * (float)Math.sin(ang);
-
-                                final float totalva = nv.va + nv2.va;
-                                final float frac = randfrange(0.25f,0.75f);
-                                nv.va = totalva * frac;
-                                nv2.va = totalva * (1f-frac);
-//                                nv.va += randfrange(-20,20);
-//                                nv2.va += randfrange(-20,20);
-
-                            }
                         }
 
                         nv.setRotation(nv.a);
@@ -375,17 +342,28 @@
             boardWidth = w;
             boardHeight = h;
 //            android.util.Log.d("Nyandroid", "resized: " + w + "x" + h);
-            post(new Runnable() { public void run() {
-                reset();
-                mAnim.start();
-            } });
         }
 
+        public void startAnimation() {
+            stopAnimation();
+            if (mAnim == null) {
+                post(new Runnable() { public void run() {
+                    reset();
+                    startAnimation();
+                } });
+            } else {
+                mAnim.start();
+            }
+        }
+
+        public void stopAnimation() {
+            if (mAnim != null) mAnim.cancel();
+        }
 
         @Override
         protected void onDetachedFromWindow() {
             super.onDetachedFromWindow();
-            mAnim.cancel();
+            stopAnimation();
         }
 
         @Override
@@ -428,12 +406,19 @@
                   WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
                 | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
                 );
+        mBoard = new Board(this, null);
+        setContentView(mBoard);
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        mBoard.stopAnimation();
     }
 
     @Override
     public void onResume() {
         super.onResume();
-        mBoard = new Board(this, null);
-        setContentView(mBoard);
+        mBoard.startAnimation();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 9a76c14..8795154 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -22,6 +22,7 @@
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.app.Notification;
+import android.app.Notification.BigPictureStyle;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.ContentResolver;
@@ -31,9 +32,13 @@
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
 import android.graphics.Matrix;
+import android.graphics.Paint;
 import android.graphics.PixelFormat;
 import android.graphics.PointF;
+import android.graphics.RectF;
 import android.media.MediaActionSound;
 import android.net.Uri;
 import android.os.AsyncTask;
@@ -85,6 +90,7 @@
     private String mImageFileName;
     private String mImageFilePath;
     private long mImageTime;
+    private BigPictureStyle mNotificationStyle;
 
     // WORKAROUND: We want the same notification across screenshots that we update so that we don't
     // spam a user's notification drawer.  However, we only show the ticker for the saving state
@@ -109,16 +115,22 @@
         // Create the large notification icon
         int imageWidth = data.image.getWidth();
         int imageHeight = data.image.getHeight();
-        int iconWidth = data.iconSize;
-        int iconHeight = data.iconSize;
-        if (imageWidth > imageHeight) {
-            iconWidth = (int) (((float) iconHeight / imageHeight) * imageWidth);
-        } else {
-            iconHeight = (int) (((float) iconWidth / imageWidth) * imageHeight);
-        }
-        Bitmap rawIcon = Bitmap.createScaledBitmap(data.image, iconWidth, iconHeight, true);
-        Bitmap croppedIcon = Bitmap.createBitmap(rawIcon, (iconWidth - data.iconSize) / 2,
-                (iconHeight - data.iconSize) / 2, data.iconSize, data.iconSize);
+        int iconSize = data.iconSize;
+
+        final int shortSide = imageWidth < imageHeight ? imageWidth : imageHeight;
+        Bitmap preview = Bitmap.createBitmap(shortSide, shortSide, data.image.getConfig());
+        Canvas c = new Canvas(preview);
+        Paint paint = new Paint();
+        ColorMatrix desat = new ColorMatrix();
+        desat.setSaturation(0.25f);
+        paint.setColorFilter(new ColorMatrixColorFilter(desat));
+        Matrix matrix = new Matrix();
+        matrix.postTranslate((shortSide - imageWidth) / 2,
+                            (shortSide - imageHeight) / 2);
+        c.drawBitmap(data.image, matrix, paint);
+        c.drawColor(0x40FFFFFF);
+
+        Bitmap croppedIcon = Bitmap.createScaledBitmap(preview, iconSize, iconSize, true);
 
         // Show the intermediate notification
         mTickerAddSpace = !mTickerAddSpace;
@@ -131,7 +143,12 @@
             .setContentText(r.getString(R.string.screenshot_saving_text))
             .setSmallIcon(R.drawable.stat_notify_image)
             .setWhen(System.currentTimeMillis());
-        Notification n = mNotificationBuilder.getNotification();
+
+        mNotificationStyle = new Notification.BigPictureStyle()
+            .bigPicture(preview);
+        mNotificationBuilder.setStyle(mNotificationStyle);
+
+        Notification n = mNotificationBuilder.build();
         n.flags |= Notification.FLAG_NO_CLEAR;
         mNotificationManager.notify(nId, n);
 
@@ -139,6 +156,8 @@
         // on small devices, the large icon is not shown) so defer showing the large icon until
         // we compose the final post-save notification below.
         mNotificationBuilder.setLargeIcon(croppedIcon);
+        // But we still don't set it for the expanded view, allowing the smallIcon to show here.
+        mNotificationStyle.bigLargeIcon(null);
     }
 
     @Override
@@ -151,6 +170,7 @@
 
         Context context = params[0].context;
         Bitmap image = params[0].image;
+        Resources r = context.getResources();
 
         try {
             // Save the screenshot to the MediaStore
@@ -165,6 +185,14 @@
             values.put(MediaStore.Images.ImageColumns.MIME_TYPE, "image/png");
             Uri uri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
 
+            Intent sharingIntent = new Intent(Intent.ACTION_SEND);
+            sharingIntent.setType("image/png");
+            sharingIntent.putExtra(Intent.EXTRA_STREAM, uri);
+            sharingIntent.setFlags(Intent.FLAG_ACTIVITY_CLOSE_SYSTEM_DIALOGS);
+            mNotificationBuilder.addAction(R.drawable.ic_menu_share,
+                     r.getString(com.android.internal.R.string.share),
+                     PendingIntent.getActivity(context, 0, sharingIntent, 0));
+
             OutputStream out = resolver.openOutputStream(uri);
             image.compress(Bitmap.CompressFormat.PNG, 100, out);
             out.flush();
@@ -207,7 +235,7 @@
                 .setWhen(System.currentTimeMillis())
                 .setAutoCancel(true);
 
-            Notification n = mNotificationBuilder.getNotification();
+            Notification n = mNotificationBuilder.build();
             n.flags &= ~Notification.FLAG_NO_CLEAR;
             mNotificationManager.notify(mNotificationId, n);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AutoRotateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AutoRotateController.java
index a31e2a4..3d63781 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AutoRotateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AutoRotateController.java
@@ -18,32 +18,40 @@
 
 import android.content.ContentResolver;
 import android.content.Context;
+import android.database.ContentObserver;
 import android.os.AsyncTask;
+import android.os.Handler;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.provider.Settings;
 import android.util.Log;
-import android.util.Slog;
 import android.view.IWindowManager;
 import android.widget.CompoundButton;
 
-/**
- * TODO: Listen for changes to the setting.
- */
 public class AutoRotateController implements CompoundButton.OnCheckedChangeListener {
     private static final String TAG = "StatusBar.AutoRotateController";
 
-    private Context mContext;
-    private CompoundButton mCheckBox;
+    private final Context mContext;
+    private final CompoundButton mCheckbox;
 
     private boolean mAutoRotation;
 
+    private ContentObserver mAccelerometerRotationObserver = new ContentObserver(new Handler()) {
+        @Override
+        public void onChange(boolean selfChange) {
+            updateCheckbox();
+        }
+    };
+
     public AutoRotateController(Context context, CompoundButton checkbox) {
         mContext = context;
-        mAutoRotation = getAutoRotation();
-        mCheckBox = checkbox;
-        checkbox.setChecked(mAutoRotation);
-        checkbox.setOnCheckedChangeListener(this);
+        mCheckbox = checkbox;
+        updateCheckbox();
+        mCheckbox.setOnCheckedChangeListener(this);
+
+        mContext.getContentResolver().registerContentObserver(
+                Settings.System.getUriFor(Settings.System.ACCELEROMETER_ROTATION), true,
+                mAccelerometerRotationObserver);
     }
 
     public void onCheckedChanged(CompoundButton view, boolean checked) {
@@ -52,6 +60,15 @@
         }
     }
 
+    public void release() {
+        mContext.getContentResolver().unregisterContentObserver(mAccelerometerRotationObserver);
+    }
+
+    private void updateCheckbox() {
+        mAutoRotation = getAutoRotation();
+        mCheckbox.setChecked(mAutoRotation);
+    }
+
     private boolean getAutoRotation() {
         ContentResolver cr = mContext.getContentResolver();
         return 0 != Settings.System.getInt(cr, Settings.System.ACCELEROMETER_ROTATION, 0);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java
index 9ca83e6..46ea940 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java
@@ -75,6 +75,7 @@
         super.onDetachedFromWindow();
         mAirplane.release();
         mDoNotDisturb.release();
+        mRotate.release();
     }
 
     public void onClick(View v) {
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/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index ff14568..48219a4 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -139,6 +139,7 @@
 
     static final int MSG_UNBIND_METHOD = 3000;
     static final int MSG_BIND_METHOD = 3010;
+    static final int MSG_SET_ACTIVE = 3020;
 
     static final int MSG_HARD_KEYBOARD_SWITCH_CHANGED = 4000;
 
@@ -413,13 +414,9 @@
             }
 
             // Inform the current client of the change in active status
-            try {
-                if (mCurClient != null && mCurClient.client != null) {
-                    mCurClient.client.setActive(mScreenOn);
-                }
-            } catch (RemoteException e) {
-                Slog.w(TAG, "Got RemoteException sending 'screen on/off' notification to pid "
-                        + mCurClient.pid + " uid " + mCurClient.uid);
+            if (mCurClient != null && mCurClient.client != null) {
+                executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
+                        MSG_SET_ACTIVE, mScreenOn ? 1 : 0, mCurClient));
             }
         }
     }
@@ -882,17 +879,12 @@
                             MSG_UNBIND_INPUT, mCurMethod));
                 }
             }
+
+            executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
+                    MSG_SET_ACTIVE, 0, mCurClient));
             executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
                     MSG_UNBIND_METHOD, mCurSeq, mCurClient.client));
             mCurClient.sessionRequested = false;
-
-            // Call setActive(false) on the old client
-            try {
-                mCurClient.client.setActive(false);
-            } catch (RemoteException e) {
-                Slog.w(TAG, "Got RemoteException sending setActive(false) notification to pid "
-                        + mCurClient.pid + " uid " + mCurClient.uid);
-            }
             mCurClient = null;
 
             hideInputMethodMenuLocked();
@@ -987,12 +979,8 @@
 
             // If the screen is on, inform the new client it is active
             if (mScreenOn) {
-                try {
-                    cs.client.setActive(mScreenOn);
-                } catch (RemoteException e) {
-                    Slog.w(TAG, "Got RemoteException sending setActive notification to pid "
-                            + cs.pid + " uid " + cs.uid);
-                }
+                executeOrSendMessage(cs.client, mCaller.obtainMessageIO(
+                        MSG_SET_ACTIVE, mScreenOn ? 1 : 0, cs));
             }
         }
 
@@ -1667,7 +1655,8 @@
                 }
 
                 if (mCurFocusedWindow == windowToken) {
-                    Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client);
+                    Slog.w(TAG, "Window already focused, ignoring focus gain of: " + client
+                            + " attribute=" + attribute);
                     if (attribute != null) {
                         return startInputUncheckedLocked(cs, inputContext, attribute,
                                 controlFlags);
@@ -2139,6 +2128,15 @@
                     Slog.w(TAG, "Client died receiving input method " + args.arg2);
                 }
                 return true;
+            case MSG_SET_ACTIVE:
+                try {
+                    ((ClientState)msg.obj).client.setActive(msg.arg1 != 0);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Got RemoteException sending setActive(false) notification to pid "
+                            + ((ClientState)msg.obj).pid + " uid "
+                            + ((ClientState)msg.obj).uid);
+                }
+                return true;
 
             // --------------------------------------------------------------
             case MSG_HARD_KEYBOARD_SWITCH_CHANGED:
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 13ab586..1482d22 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -1065,7 +1065,9 @@
     private static final String TAG_STORAGE_LIST = "StorageList";
     private static final String TAG_STORAGE = "storage";
 
-    private void readStorageList(Resources resources) {
+    private void readStorageList() {
+        Resources resources = mContext.getResources();
+
         int id = com.android.internal.R.xml.storage_list;
         XmlResourceParser parser = resources.getXml(id);
         AttributeSet attrs = Xml.asAttributeSet(parser);
@@ -1084,6 +1086,8 @@
 
                     CharSequence path = a.getText(
                             com.android.internal.R.styleable.Storage_mountPoint);
+                    int descriptionId = a.getResourceId(
+                            com.android.internal.R.styleable.Storage_storageDescription, -1);
                     CharSequence description = a.getText(
                             com.android.internal.R.styleable.Storage_storageDescription);
                     boolean primary = a.getBoolean(
@@ -1110,7 +1114,7 @@
                     } else {
                         String pathString = path.toString();
                         StorageVolume volume = new StorageVolume(pathString,
-                                description.toString(), removable, emulated,
+                                descriptionId, removable, emulated,
                                 mtpReserve, allowMassStorage, maxFileSize);
                         if (primary) {
                             if (mPrimaryVolume == null) {
@@ -1151,8 +1155,7 @@
      */
     public MountService(Context context) {
         mContext = context;
-        Resources resources = context.getResources();
-        readStorageList(resources);
+        readStorageList();
 
         if (mPrimaryVolume != null) {
             mExternalStoragePath = mPrimaryVolume.getPath();
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 2cc2704..38e08ae 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -178,6 +178,8 @@
     static final int ANIM_STEPS = 60; // nominal # of frames at 60Hz
     // Slower animation for autobrightness changes
     static final int AUTOBRIGHTNESS_ANIM_STEPS = 2 * ANIM_STEPS;
+    // Even slower animation for autodimness changes
+    static final int AUTODIMNESS_ANIM_STEPS = 15 * ANIM_STEPS;
     // Number of steps when performing a more immediate brightness change.
     static final int IMMEDIATE_ANIM_STEPS = 4;
 
@@ -1745,7 +1747,6 @@
                             + Integer.toHexString(mPowerState)
                             + " mSkippedScreenOn=" + mSkippedScreenOn);
                 }
-                mScreenBrightnessHandler.removeMessages(ScreenBrightnessAnimator.ANIMATE_LIGHTS);
                 mScreenBrightnessAnimator.animateTo(PowerManager.BRIGHTNESS_OFF, SCREEN_BRIGHT_BIT, 0);
             }
         }
@@ -2159,6 +2160,8 @@
         static final int ANIMATE_POWER_OFF = 11;
         volatile int startValue;
         volatile int endValue;
+        volatile int startSensorValue;
+        volatile int endSensorValue;
         volatile int currentValue;
         private int currentMask;
         private int duration;
@@ -2182,7 +2185,7 @@
                         int value = msg.arg2;
                         long tStart = SystemClock.uptimeMillis();
                         if ((mask & SCREEN_BRIGHT_BIT) != 0) {
-                            if (mDebugLightAnimation) Log.v(TAG, "Set brightness: " + value);
+                            if (mDebugLightAnimation) Slog.v(TAG, "Set brightness: " + value);
                             mLcdLight.setBrightness(value, brightnessMode);
                         }
                         long elapsed = SystemClock.uptimeMillis() - tStart;
@@ -2194,12 +2197,12 @@
                         }
 
                         if (elapsed > 100) {
-                            Log.e(TAG, "Excessive delay setting brightness: " + elapsed
+                            Slog.e(TAG, "Excessive delay setting brightness: " + elapsed
                                     + "ms, mask=" + mask);
                         }
 
                         // Throttle brightness updates to frame refresh rate
-                        int delay = elapsed < NOMINAL_FRAME_TIME_MS ? NOMINAL_FRAME_TIME_MS : 0;
+                        int delay = elapsed < NOMINAL_FRAME_TIME_MS ? NOMINAL_FRAME_TIME_MS : 1;
                         synchronized(this) {
                             currentValue = value;
                         }
@@ -2227,25 +2230,41 @@
                         newValue = startValue + delta * elapsed / duration;
                         newValue = Math.max(PowerManager.BRIGHTNESS_OFF, newValue);
                         newValue = Math.min(PowerManager.BRIGHTNESS_ON, newValue);
+                        // Optimization to delay next step until a change will occur.
+                        if (delay > 0 && newValue == currentValue) {
+                            final int timePerStep = duration / Math.abs(delta);
+                            delay = Math.min(duration - elapsed, timePerStep);
+                            newValue += delta < 0 ? -1 : 1;
+                        }
+                        // adjust the peak sensor value until we get to the target sensor value
+                        delta = endSensorValue - startSensorValue;
+                        mHighestLightSensorValue = startSensorValue + delta * elapsed / duration;
                     } else {
                         newValue = endValue;
+                        mHighestLightSensorValue = endSensorValue;
                         mInitialAnimation = false;
                     }
 
                     if (mDebugLightAnimation) {
-                        Log.v(TAG, "Animating light: " + "start:" + startValue
+                        Slog.v(TAG, "Animating light: " + "start:" + startValue
                                 + ", end:" + endValue + ", elapsed:" + elapsed
                                 + ", duration:" + duration + ", current:" + currentValue
-                                + ", delay:" + delay);
+                                + ", newValue:" + newValue
+                                + ", delay:" + delay
+                                + ", highestSensor:" + mHighestLightSensorValue);
                     }
 
                     if (turningOff && !mHeadless && !mAnimateScreenLights) {
                         int mode = mScreenOffReason == OFF_BECAUSE_OF_PROX_SENSOR
                                 ? 0 : mAnimationSetting;
-                        if (mDebugLightAnimation) Log.v(TAG, "Doing power-off anim, mode=" + mode);
+                        if (mDebugLightAnimation) {
+                            Slog.v(TAG, "Doing power-off anim, mode=" + mode);
+                        }
                         mScreenBrightnessHandler.obtainMessage(ANIMATE_POWER_OFF, mode, 0)
                                 .sendToTarget();
                     }
+                    mScreenBrightnessHandler.removeMessages(
+                            ScreenBrightnessAnimator.ANIMATE_LIGHTS);
                     Message msg = mScreenBrightnessHandler
                             .obtainMessage(ANIMATE_LIGHTS, mask, newValue);
                     mScreenBrightnessHandler.sendMessageDelayed(msg, delay);
@@ -2259,16 +2278,24 @@
         }
 
         public void animateTo(int target, int mask, int animationDuration) {
+            animateTo(target, mHighestLightSensorValue, mask, animationDuration);
+        }
+
+        public void animateTo(int target, int sensorTarget, int mask, int animationDuration) {
             synchronized(this) {
                 startValue = currentValue;
                 endValue = target;
+                startSensorValue = mHighestLightSensorValue;
+                endSensorValue = sensorTarget;
                 currentMask = mask;
                 duration = (int) (mWindowScaleAnimation * animationDuration);
                 startTimeMillis = SystemClock.elapsedRealtime();
                 mInitialAnimation = currentValue == 0 && target > 0;
 
                 if (mDebugLightAnimation) {
-                    Log.v(TAG, "animateTo(target=" + target + ", mask=" + mask
+                    Slog.v(TAG, "animateTo(target=" + target
+                            + ", sensor=" + sensorTarget
+                            + ", mask=" + mask
                             + ", duration=" + animationDuration +")"
                             + ", currentValue=" + currentValue
                             + ", startTime=" + startTimeMillis);
@@ -2612,9 +2639,11 @@
             return;
         }
 
-        // do not allow light sensor value to decrease
-        if (mHighestLightSensorValue < value) {
-            mHighestLightSensorValue = value;
+        final int stepsToTargetLevel;
+        if (mHighestLightSensorValue <= value) {
+            stepsToTargetLevel = AUTOBRIGHTNESS_ANIM_STEPS;
+        } else {
+            stepsToTargetLevel = AUTODIMNESS_ANIM_STEPS;
         }
 
         if (mLightSensorValue != value) {
@@ -2623,9 +2652,7 @@
                 // use maximum light sensor value seen since screen went on for LCD to avoid flicker
                 // we only do this if we are undocked, since lighting should be stable when
                 // stationary in a dock.
-                int lcdValue = getAutoBrightnessValue(
-                        (mIsDocked ? value : mHighestLightSensorValue),
-                        mLcdBacklightValues);
+                int lcdValue = getAutoBrightnessValue(value, mLcdBacklightValues);
                 int buttonValue = getAutoBrightnessValue(value, mButtonBacklightValues);
                 int keyboardValue;
                 if (mKeyboardVisible) {
@@ -2645,9 +2672,8 @@
 
                 if (mAutoBrightessEnabled && mScreenBrightnessOverride < 0) {
                     if (!mSkippedScreenOn && !mInitialAnimation) {
-                        int steps = immediate ? IMMEDIATE_ANIM_STEPS : AUTOBRIGHTNESS_ANIM_STEPS;
-                        mScreenBrightnessAnimator.cancelAnimation();
-                        mScreenBrightnessAnimator.animateTo(lcdValue,
+                        int steps = immediate ? IMMEDIATE_ANIM_STEPS : stepsToTargetLevel;
+                        mScreenBrightnessAnimator.animateTo(lcdValue, value,
                                 SCREEN_BRIGHT_BIT, steps * NOMINAL_FRAME_TIME_MS);
                     }
                 }
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 3a1a85b..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);
+            }
         }
     }
 
@@ -1412,11 +1428,11 @@
                     }
                 }
             }
+            final int flags = (mIncludeNotImportantViews) ?
+                    AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0;
+            final int interrogatingPid = Binder.getCallingPid();
             final long identityToken = Binder.clearCallingIdentity();
             try {
-                final int flags = (mIncludeNotImportantViews) ?
-                        AccessibilityNodeInfo.INCLUDE_NOT_IMPORTANT_VIEWS : 0;
-                final int interrogatingPid = Binder.getCallingPid();
                 connection.performAccessibilityAction(accessibilityNodeId, action, arguments,
                         interactionId, callback, flags, interrogatingPid, interrogatingTid);
             } catch (RemoteException re) {
@@ -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 cf3a5d2..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)) {
@@ -269,9 +270,19 @@
                                 mPendingLayoutChanges);
                         }
                         mService.mFocusMayChange = true;
-                    } else if (win.isReadyForDisplay()) {
+                    }
+                    if (win.isReadyForDisplay()) {
                         mForceHiding = true;
                     }
+                    if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
+                            "Force hide " + mForceHiding
+                            + " hasSurface=" + win.mHasSurface
+                            + " policyVis=" + win.mPolicyVisibility
+                            + " destroying=" + win.mDestroying
+                            + " attHidden=" + win.mAttachedHidden
+                            + " vis=" + win.mViewVisibility
+                            + " hidden=" + win.mRootToken.hidden
+                            + " anim=" + win.mWinAnimator.mAnimation);
                 } else if (mPolicy.canBeForceHidden(win, win.mAttrs)) {
                     final boolean changed;
                     if (mForceHiding) {
@@ -391,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 fbf9256..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);
@@ -1177,7 +1183,9 @@
                 if (!w.isVisibleOrAdding()) {
                     Slog.i(TAG, "  mSurface=" + w.mWinAnimator.mSurface
                             + " relayoutCalled=" + w.mRelayoutCalled + " viewVis=" + w.mViewVisibility
-                            + " policyVis=" + w.mPolicyVisibility + " attachHid=" + w.mAttachedHidden
+                            + " policyVis=" + w.mPolicyVisibility
+                            + " policyVisAfterAnim=" + w.mPolicyVisibilityAfterAnim
+                            + " attachHid=" + w.mAttachedHidden
                             + " exiting=" + w.mExiting + " destroying=" + w.mDestroying);
                     if (w.mAppToken != null) {
                         Slog.i(TAG, "  mAppToken.hiddenRequested=" + w.mAppToken.hiddenRequested);
@@ -1634,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())) {
@@ -1727,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.");
@@ -1870,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
@@ -1924,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);
             }
         }
@@ -3482,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,
@@ -3516,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.
@@ -3833,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) {
@@ -4465,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;
@@ -4496,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--;
@@ -4519,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));
@@ -4528,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--;
@@ -4542,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) {
@@ -4630,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 + ")");
@@ -4642,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);
         }
     }
 
@@ -4700,7 +4753,9 @@
                 assignLayersLocked();
             }
             mLayoutNeeded = true;
-            performLayoutAndPlaceSurfacesLocked();
+            if (!mInLayout) {
+                performLayoutAndPlaceSurfacesLocked();
+            }
             mInputMonitor.updateInputWindowsLw(false /*force*/);
         }
     }
@@ -4756,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()")) {
@@ -4780,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));
@@ -4790,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);
             }
         }
@@ -5246,9 +5306,14 @@
 
     // TODO: more accounting of which pid(s) turned it on, keep count,
     // only allow disables from pids which have count on, etc.
+    @Override
     public void showStrictModeViolation(boolean on) {
         if (mHeadless) return;
+        mH.sendMessage(mH.obtainMessage(H.SHOW_STRICT_MODE_VIOLATION, on ? 1 : 0, 0));
+    }
 
+    private void showStrictModeViolation(int arg) {
+        final boolean on = arg != 0;
         int pid = Binder.getCallingPid();
         synchronized(mWindowMap) {
             // Ignoring requests to enable the red border from clients
@@ -6712,6 +6777,7 @@
         public static final int BOOT_TIMEOUT = 23;
         public static final int WAITING_FOR_DRAWN_TIMEOUT = 24;
         public static final int BULK_UPDATE_PARAMETERS = 25;
+        public static final int SHOW_STRICT_MODE_VIOLATION = 26;
 
         public static final int ANIMATOR_WHAT_OFFSET = 100000;
         public static final int SET_TRANSPARENT_REGION = ANIMATOR_WHAT_OFFSET + 1;
@@ -7002,6 +7068,8 @@
                                     "*** APP TRANSITION TIMEOUT");
                             mAppTransitionReady = true;
                             mAppTransitionTimeout = true;
+                            mAnimatingAppTokens.clear();
+                            mAnimatingAppTokens.addAll(mAppTokens);
                             performLayoutAndPlaceSurfacesLocked();
                         }
                     }
@@ -7177,6 +7245,11 @@
                     break;
                 }
 
+                case SHOW_STRICT_MODE_VIOLATION: {
+                    showStrictModeViolation(msg.arg1);
+                    break;
+                }
+
                 // Animation messages. Move to Window{State}Animator
                 case SET_TRANSPARENT_REGION: {
                     Pair<WindowStateAnimator, Region> pair =
@@ -7234,9 +7307,11 @@
             WindowState imFocus;
             if (idx > 0) {
                 imFocus = mWindows.get(idx-1);
-                //Log.i(TAG, "Desired input method target: " + imFocus);
-                //Log.i(TAG, "Current focus: " + this.mCurrentFocus);
-                //Log.i(TAG, "Last focus: " + this.mLastFocus);
+                if (DEBUG_INPUT_METHOD) {
+                    Slog.i(TAG, "Desired input method target: " + imFocus);
+                    Slog.i(TAG, "Current focus: " + this.mCurrentFocus);
+                    Slog.i(TAG, "Last focus: " + this.mLastFocus);
+                }
                 if (imFocus != null) {
                     // This may be a starting window, in which case we still want
                     // to count it as okay.
@@ -7247,17 +7322,20 @@
                         for (int i=0; i<imFocus.mAppToken.windows.size(); i++) {
                             WindowState w = imFocus.mAppToken.windows.get(i);
                             if (w != imFocus) {
-                                //Log.i(TAG, "Switching to real app window: " + w);
+                                Log.i(TAG, "Switching to real app window: " + w);
                                 imFocus = w;
                                 break;
                             }
                         }
                     }
-                    //Log.i(TAG, "IM target client: " + imFocus.mSession.mClient);
-                    //if (imFocus.mSession.mClient != null) {
-                    //    Log.i(TAG, "IM target client binder: " + imFocus.mSession.mClient.asBinder());
-                    //    Log.i(TAG, "Requesting client binder: " + client.asBinder());
-                    //}
+                    if (DEBUG_INPUT_METHOD) {
+                        Slog.i(TAG, "IM target client: " + imFocus.mSession.mClient);
+                        if (imFocus.mSession.mClient != null) {
+                            Slog.i(TAG, "IM target client binder: "
+                                    + imFocus.mSession.mClient.asBinder());
+                            Slog.i(TAG, "Requesting client binder: " + client.asBinder());
+                        }
+                    }
                     if (imFocus.mSession.mClient != null &&
                             imFocus.mSession.mClient.asBinder() == client.asBinder()) {
                         return true;
@@ -7515,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;
@@ -7537,7 +7615,7 @@
                 }
             }
             Slog.w(TAG, "Current app token list:");
-            dumpAppTokensLocked();
+            dumpAnimatingAppTokensLocked();
             Slog.w(TAG, "Final window list:");
             dumpWindowsLocked();
         }
@@ -7606,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;
         }
 
@@ -7895,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 =
@@ -8137,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
@@ -8224,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;
@@ -8665,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 {
@@ -9012,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;
             }
 
@@ -9415,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);
@@ -9422,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..affe5d49 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);
         }
     }
 
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java
index 0a87a538..63359c1 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -438,6 +438,22 @@
         return doBooleanCommand("SET config_methods " + cfg);
     }
 
+    public boolean setManufacturer(String value) {
+        return doBooleanCommand("SET manufacturer " + value);
+    }
+
+    public boolean setModelName(String value) {
+        return doBooleanCommand("SET model_name " + value);
+    }
+
+    public boolean setModelNumber(String value) {
+        return doBooleanCommand("SET model_number " + value);
+    }
+
+    public boolean setSerialNumber(String value) {
+        return doBooleanCommand("SET serial_number " + value);
+    }
+
     public boolean setP2pSsidPostfix(String postfix) {
         return doBooleanCommand("SET p2p_ssid_postfix " + postfix);
     }
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 2903faa..a0f3281 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -120,6 +120,7 @@
     private ConnectivityManager mCm;
 
     private final boolean mP2pSupported;
+    private final String mPrimaryDeviceType;
 
     /* Scan results handling */
     private List<ScanResult> mScanResults;
@@ -590,6 +591,9 @@
         mBackgroundScanSupported = mContext.getResources().getBoolean(
                 com.android.internal.R.bool.config_wifi_background_scan_support);
 
+        mPrimaryDeviceType = mContext.getResources().getString(
+                com.android.internal.R.string.config_wifi_p2p_device_type);
+
         mContext.registerReceiver(
             new BroadcastReceiver() {
                 @Override
@@ -2214,6 +2218,37 @@
             if (DBG) log(getName() + "\n");
             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
         }
+
+        private void initializeWpsDetails() {
+            String detail;
+            detail = SystemProperties.get("ro.product.name", "");
+            if (!mWifiNative.setDeviceName(detail)) {
+                loge("Failed to set device name " +  detail);
+            }
+            detail = SystemProperties.get("ro.product.manufacturer", "");
+            if (!mWifiNative.setManufacturer(detail)) {
+                loge("Failed to set manufacturer " + detail);
+            }
+            detail = SystemProperties.get("ro.product.model", "");
+            if (!mWifiNative.setModelName(detail)) {
+                loge("Failed to set model name " + detail);
+            }
+            detail = SystemProperties.get("ro.product.model", "");
+            if (!mWifiNative.setModelNumber(detail)) {
+                loge("Failed to set model number " + detail);
+            }
+            detail = SystemProperties.get("ro.serialno", "");
+            if (!mWifiNative.setSerialNumber(detail)) {
+                loge("Failed to set serial number " + detail);
+            }
+            if (!mWifiNative.setConfigMethods("physical_display virtual_push_button keypad")) {
+                loge("Failed to set WPS config methods");
+            }
+            if (!mWifiNative.setDeviceType(mPrimaryDeviceType)) {
+                loge("Failed to set primary device type " + mPrimaryDeviceType);
+            }
+        }
+
         @Override
         public boolean processMessage(Message message) {
             if (DBG) log(getName() + message.toString() + "\n");
@@ -2231,8 +2266,8 @@
                     mLastSignalLevel = -1;
 
                     mWifiInfo.setMacAddress(mWifiNative.getMacAddress());
-
                     mWifiConfigStore.initialize();
+                    initializeWpsDetails();
 
                     sendSupplicantConnectionChangedBroadcast(true);
                     transitionTo(mDriverStartedState);