Merge "Fix "pm list permissions GROUP""
diff --git a/api/current.txt b/api/current.txt
index 77c64d7..c3a4a0c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -24962,6 +24962,7 @@
   public static class CallLog.Calls implements android.provider.BaseColumns {
     ctor public CallLog.Calls();
     method public static java.lang.String getLastOutgoingCall(android.content.Context);
+    field public static final int BLOCKED_TYPE = 6; // 0x6
     field public static final java.lang.String CACHED_FORMATTED_NUMBER = "formatted_number";
     field public static final java.lang.String CACHED_LOOKUP_URI = "lookup_uri";
     field public static final java.lang.String CACHED_MATCHED_NUMBER = "matched_number";
@@ -25000,6 +25001,7 @@
     field public static final int PRESENTATION_PAYPHONE = 4; // 0x4
     field public static final int PRESENTATION_RESTRICTED = 2; // 0x2
     field public static final int PRESENTATION_UNKNOWN = 3; // 0x3
+    field public static final int REJECTED_TYPE = 5; // 0x5
     field public static final java.lang.String TRANSCRIPTION = "transcription";
     field public static final java.lang.String TYPE = "type";
     field public static final int VOICEMAIL_TYPE = 4; // 0x4
diff --git a/api/system-current.txt b/api/system-current.txt
index cff0055..325aa28b 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -26918,6 +26918,7 @@
   public static class CallLog.Calls implements android.provider.BaseColumns {
     ctor public CallLog.Calls();
     method public static java.lang.String getLastOutgoingCall(android.content.Context);
+    field public static final int BLOCKED_TYPE = 6; // 0x6
     field public static final java.lang.String CACHED_FORMATTED_NUMBER = "formatted_number";
     field public static final java.lang.String CACHED_LOOKUP_URI = "lookup_uri";
     field public static final java.lang.String CACHED_MATCHED_NUMBER = "matched_number";
@@ -26956,6 +26957,7 @@
     field public static final int PRESENTATION_PAYPHONE = 4; // 0x4
     field public static final int PRESENTATION_RESTRICTED = 2; // 0x2
     field public static final int PRESENTATION_UNKNOWN = 3; // 0x3
+    field public static final int REJECTED_TYPE = 5; // 0x5
     field public static final java.lang.String TRANSCRIPTION = "transcription";
     field public static final java.lang.String TYPE = "type";
     field public static final int VOICEMAIL_TYPE = 4; // 0x4
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 5c9fd51..4a13136 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -44,6 +44,7 @@
 import android.content.pm.IPackageManager;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ResolveInfo;
+import android.content.pm.UserInfo;
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.net.Uri;
@@ -63,6 +64,7 @@
 import android.view.IWindowManager;
 
 import com.android.internal.os.BaseCommand;
+import com.android.internal.util.Preconditions;
 
 import java.io.BufferedReader;
 import java.io.File;
@@ -168,6 +170,7 @@
                 "       am get-inactive [--user <USER_ID>] <PACKAGE>\n" +
                 "       am send-trim-memory [--user <USER_ID>] <PROCESS>\n" +
                 "               [HIDDEN|RUNNING_MODERATE|BACKGROUND|RUNNING_LOW|MODERATE|RUNNING_CRITICAL|COMPLETE]\n" +
+                "       am get-current-user\n" +
                 "\n" +
                 "am start: start an Activity.  Options are:\n" +
                 "    -D: enable debugging\n" +
@@ -334,7 +337,9 @@
                 "\n" +
                 "am get-inactive: returns the inactive state of an app.\n" +
                 "\n" +
-                "am send-trim-memory: Send a memory trim event to a <PROCESS>.\n" +
+                "am send-trim-memory: send a memory trim event to a <PROCESS>.\n" +
+                "\n" +
+                "am get-current-user: returns id of the current foreground user.\n" +
                 "\n" +
                 "<INTENT> specifications include these flags and arguments:\n" +
                 "    [-a <ACTION>] [-d <DATA_URI>] [-t <MIME_TYPE>]\n" +
@@ -464,6 +469,8 @@
             runGetInactive();
         } else if (op.equals("send-trim-memory")) {
             runSendTrimMemory();
+        } else if (op.equals("get-current-user")) {
+            runGetCurrentUser();
         } else {
             showError("Error: unknown command '" + op + "'");
         }
@@ -2712,6 +2719,12 @@
         }
     }
 
+    private void runGetCurrentUser() throws Exception {
+        UserInfo currentUser = Preconditions.checkNotNull(mAm.getCurrentUser(),
+                "Current user not set");
+        System.out.println(currentUser.id);
+    }
+
     /**
      * Open the given file for sending into the system process. This verifies
      * with SELinux that the system will have access to the file.
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index 16f825d..d444638 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -603,7 +603,17 @@
         createDependencyGraph();
 
         // Now that all dependencies are set up, start the animations that should be started.
-        start(mRootNode);
+        boolean setIsEmpty = false;
+        if (mStartDelay > 0) {
+            start(mRootNode);
+        } else if (mNodes.size() > 1) {
+            // No delay, but there are other animators in the set
+            onChildAnimatorEnded(mDelayAnim);
+        } else {
+            // Set is empty, no delay, no other animation. Skip to end in this case
+            setIsEmpty = true;
+        }
+
         if (mListeners != null) {
             ArrayList<AnimatorListener> tmpListeners =
                     (ArrayList<AnimatorListener>) mListeners.clone();
@@ -612,18 +622,9 @@
                 tmpListeners.get(i).onAnimationStart(this);
             }
         }
-        if (mNodes.size() == 0 && mStartDelay == 0) {
-            // Handle unusual case where empty AnimatorSet is started - should send out
-            // end event immediately since the event will not be sent out at all otherwise
-            mStarted = false;
-            if (mListeners != null) {
-                ArrayList<AnimatorListener> tmpListeners =
-                        (ArrayList<AnimatorListener>) mListeners.clone();
-                int numListeners = tmpListeners.size();
-                for (int i = 0; i < numListeners; ++i) {
-                    tmpListeners.get(i).onAnimationEnd(this);
-                }
-            }
+        if (setIsEmpty) {
+            // In the case of empty AnimatorSet, we will trigger the onAnimationEnd() right away.
+            onChildAnimatorEnded(mDelayAnim);
         }
     }
 
@@ -751,44 +752,7 @@
         public void onAnimationEnd(Animator animation) {
             animation.removeListener(this);
             mAnimatorSet.mPlayingSet.remove(animation);
-            Node animNode = mAnimatorSet.mNodeMap.get(animation);
-            animNode.mEnded = true;
-
-            if (!mAnimatorSet.mTerminated) {
-                List<Node> children = animNode.mChildNodes;
-                // Start children animations, if any.
-                int childrenSize = children == null ? 0 : children.size();
-                for (int i = 0; i < childrenSize; i++) {
-                    if (children.get(i).mLatestParent == animNode) {
-                        mAnimatorSet.start(children.get(i));
-                    }
-                }
-                // Listeners are already notified of the AnimatorSet ending in cancel() or
-                // end(); the logic below only kicks in when animations end normally
-                boolean allDone = true;
-                // Traverse the tree and find if there's any unfinished node
-                int size = mAnimatorSet.mNodes.size();
-                for (int i = 0; i < size; i++) {
-                    if (!mAnimatorSet.mNodes.get(i).mEnded) {
-                        allDone = false;
-                        break;
-                    }
-                }
-                if (allDone) {
-                    // If this was the last child animation to end, then notify listeners that this
-                    // AnimatorSet has ended
-                    if (mAnimatorSet.mListeners != null) {
-                        ArrayList<AnimatorListener> tmpListeners =
-                                (ArrayList<AnimatorListener>) mAnimatorSet.mListeners.clone();
-                        int numListeners = tmpListeners.size();
-                        for (int i = 0; i < numListeners; ++i) {
-                            tmpListeners.get(i).onAnimationEnd(mAnimatorSet);
-                        }
-                    }
-                    mAnimatorSet.mStarted = false;
-                    mAnimatorSet.mPaused = false;
-                }
-            }
+            mAnimatorSet.onChildAnimatorEnded(animation);
         }
 
         // Nothing to do
@@ -801,6 +765,47 @@
 
     }
 
+    private void onChildAnimatorEnded(Animator animation) {
+        Node animNode = mNodeMap.get(animation);
+        animNode.mEnded = true;
+
+        if (!mTerminated) {
+            List<Node> children = animNode.mChildNodes;
+            // Start children animations, if any.
+            int childrenSize = children == null ? 0 : children.size();
+            for (int i = 0; i < childrenSize; i++) {
+                if (children.get(i).mLatestParent == animNode) {
+                    start(children.get(i));
+                }
+            }
+            // Listeners are already notified of the AnimatorSet ending in cancel() or
+            // end(); the logic below only kicks in when animations end normally
+            boolean allDone = true;
+            // Traverse the tree and find if there's any unfinished node
+            int size = mNodes.size();
+            for (int i = 0; i < size; i++) {
+                if (!mNodes.get(i).mEnded) {
+                    allDone = false;
+                    break;
+                }
+            }
+            if (allDone) {
+                // If this was the last child animation to end, then notify listeners that this
+                // AnimatorSet has ended
+                if (mListeners != null) {
+                    ArrayList<AnimatorListener> tmpListeners =
+                            (ArrayList<AnimatorListener>) mListeners.clone();
+                    int numListeners = tmpListeners.size();
+                    for (int i = 0; i < numListeners; ++i) {
+                        tmpListeners.get(i).onAnimationEnd(this);
+                    }
+                }
+                mStarted = false;
+                mPaused = false;
+            }
+        }
+    }
+
     /**
      * @hide
      */
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index 5af6504..1995ef5 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -932,6 +932,13 @@
         updateScaledDuration(); // in case the scale factor has changed since creation time
         AnimationHandler animationHandler = AnimationHandler.getInstance();
         animationHandler.addAnimationFrameCallback(this, mStartDelay);
+
+        if (mStartDelay == 0) {
+            // If there's no start delay, init the animation and notify start listeners right away
+            // Otherwise, postpone this until the first frame after the start delay.
+            startAnimation();
+            setCurrentFraction(mSeekFraction == -1 ? 0 : mSeekFraction);
+        }
     }
 
     @Override
@@ -1075,6 +1082,7 @@
         mStartListenersCalled = false;
         mPlayingBackwards = false;
         mReversing = false;
+        mLastFrameTime = 0;
         mCurrentIteration = 0;
         if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
             Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, getNameForTrace(),
@@ -1184,12 +1192,13 @@
      * @hide
      */
     public final void doAnimationFrame(long frameTime) {
-        mLastFrameTime = frameTime;
         AnimationHandler handler = AnimationHandler.getInstance();
-        if (!mRunning) {
+        if (mLastFrameTime == 0) {
             // First frame
             handler.addOneShotCommitCallback(this);
-            startAnimation();
+            if (mStartDelay > 0) {
+                startAnimation();
+            }
             if (mSeekFraction < 0) {
                 mStartTime = frameTime;
             } else {
@@ -1199,6 +1208,7 @@
             }
             mStartTimeCommitted = false; // allow start time to be compensated for jank
         }
+        mLastFrameTime = frameTime;
         if (mPaused) {
             if (mPauseTime < 0) {
                 mPauseTime = frameTime;
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index e965d65..3f566eb 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -1545,7 +1545,7 @@
     /**
      * <p>Whether video stabilization is
      * active.</p>
-     * <p>Video stabilization automatically translates and scales images from
+     * <p>Video stabilization automatically warps images from
      * the camera in order to stabilize motion between consecutive frames.</p>
      * <p>If enabled, video stabilization can modify the
      * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} to keep the video stream stabilized.</p>
@@ -1555,6 +1555,15 @@
      * the video stabilization modes in the first several capture results may
      * still be "OFF", and it will become "ON" when the initialization is
      * done.</p>
+     * <p>In addition, not all recording sizes or frame rates may be supported for
+     * stabilization by a device that reports stabilization support. It is guaranteed
+     * that an output targeting a MediaRecorder or MediaCodec will be stabilized if
+     * the recording resolution is less than or equal to 1920 x 1080 (width less than
+     * or equal to 1920, height less than or equal to 1080), and the recording
+     * frame rate is less than or equal to 30fps.  At other sizes, the CaptureResult
+     * {@link CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE android.control.videoStabilizationMode} field will return
+     * OFF if the recording output is not stabilized, or if there are no output
+     * Surface types that can be stabilized.</p>
      * <p>If a camera device supports both this mode and OIS
      * ({@link CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE android.lens.opticalStabilizationMode}), turning both modes on may
      * produce undesirable interaction, so it is recommended not to enable
@@ -1566,6 +1575,7 @@
      * </ul></p>
      * <p>This key is available on all devices.</p>
      *
+     * @see CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE
      * @see CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE
      * @see CaptureRequest#SCALER_CROP_REGION
      * @see #CONTROL_VIDEO_STABILIZATION_MODE_OFF
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 46eddb3..b3acf2b 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2056,7 +2056,7 @@
     /**
      * <p>Whether video stabilization is
      * active.</p>
-     * <p>Video stabilization automatically translates and scales images from
+     * <p>Video stabilization automatically warps images from
      * the camera in order to stabilize motion between consecutive frames.</p>
      * <p>If enabled, video stabilization can modify the
      * {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} to keep the video stream stabilized.</p>
@@ -2066,6 +2066,15 @@
      * the video stabilization modes in the first several capture results may
      * still be "OFF", and it will become "ON" when the initialization is
      * done.</p>
+     * <p>In addition, not all recording sizes or frame rates may be supported for
+     * stabilization by a device that reports stabilization support. It is guaranteed
+     * that an output targeting a MediaRecorder or MediaCodec will be stabilized if
+     * the recording resolution is less than or equal to 1920 x 1080 (width less than
+     * or equal to 1920, height less than or equal to 1080), and the recording
+     * frame rate is less than or equal to 30fps.  At other sizes, the CaptureResult
+     * {@link CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE android.control.videoStabilizationMode} field will return
+     * OFF if the recording output is not stabilized, or if there are no output
+     * Surface types that can be stabilized.</p>
      * <p>If a camera device supports both this mode and OIS
      * ({@link CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE android.lens.opticalStabilizationMode}), turning both modes on may
      * produce undesirable interaction, so it is recommended not to enable
@@ -2077,6 +2086,7 @@
      * </ul></p>
      * <p>This key is available on all devices.</p>
      *
+     * @see CaptureRequest#CONTROL_VIDEO_STABILIZATION_MODE
      * @see CaptureRequest#LENS_OPTICAL_STABILIZATION_MODE
      * @see CaptureRequest#SCALER_CROP_REGION
      * @see #CONTROL_VIDEO_STABILIZATION_MODE_OFF
diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java
index c373308..cd483b1 100644
--- a/core/java/android/os/BaseBundle.java
+++ b/core/java/android/os/BaseBundle.java
@@ -19,6 +19,7 @@
 import android.annotation.Nullable;
 import android.util.ArrayMap;
 import android.util.Log;
+import android.util.MathUtils;
 
 import java.io.Serializable;
 import java.util.ArrayList;
@@ -1345,18 +1346,19 @@
      */
     void readFromParcelInner(Parcel parcel) {
         int length = parcel.readInt();
-        if (length < 0) {
-            throw new RuntimeException("Bad length in parcel: " + length);
-        }
         readFromParcelInner(parcel, length);
     }
 
     private void readFromParcelInner(Parcel parcel, int length) {
-        if (length == 0) {
+        if (length < 0) {
+            throw new RuntimeException("Bad length in parcel: " + length);
+
+        } else if (length == 0) {
             // Empty Bundle or end of data.
             mParcelledData = EMPTY_PARCEL;
             return;
         }
+
         int magic = parcel.readInt();
         if (magic != BUNDLE_MAGIC) {
             //noinspection ThrowableInstanceNeverThrown
@@ -1366,7 +1368,7 @@
 
         // Advance within this Parcel
         int offset = parcel.dataPosition();
-        parcel.setDataPosition(offset + length);
+        parcel.setDataPosition(MathUtils.addOrThrow(offset, length));
 
         Parcel p = Parcel.obtain();
         p.setDataPosition(0);
diff --git a/core/java/android/os/ParcelableParcel.java b/core/java/android/os/ParcelableParcel.java
index 11785f1..5bbe6488 100644
--- a/core/java/android/os/ParcelableParcel.java
+++ b/core/java/android/os/ParcelableParcel.java
@@ -16,6 +16,8 @@
 
 package android.os;
 
+import android.util.MathUtils;
+
 /**
  * Parcelable containing a raw Parcel of data.
  * @hide
@@ -33,9 +35,13 @@
         mParcel = Parcel.obtain();
         mClassLoader = loader;
         int size = src.readInt();
+        if (size < 0) {
+            throw new IllegalArgumentException("Negative size read from parcel");
+        }
+
         int pos = src.dataPosition();
-        mParcel.appendFrom(src, src.dataPosition(), size);
-        src.setDataPosition(pos + size);
+        src.setDataPosition(MathUtils.addOrThrow(pos, size));
+        mParcel.appendFrom(src, pos, size);
     }
 
     public Parcel getParcel() {
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 4f880b1..342f8c7 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -153,6 +153,18 @@
         /**
          * The type of the call (incoming, outgoing or missed).
          * <P>Type: INTEGER (int)</P>
+         *
+         * <p>
+         * Allowed values:
+         * <ul>
+         * <li>{@link #INCOMING_TYPE}</li>
+         * <li>{@link #OUTGOING_TYPE}</li>
+         * <li>{@link #MISSED_TYPE}</li>
+         * <li>{@link #VOICEMAIL_TYPE}</li>
+         * <li>{@link #REJECTED_TYPE}</li>
+         * <li>{@link #BLOCKED_TYPE}</li>
+         * </ul>
+         * </p>
          */
         public static final String TYPE = "type";
 
@@ -164,6 +176,10 @@
         public static final int MISSED_TYPE = 3;
         /** Call log type for voicemails. */
         public static final int VOICEMAIL_TYPE = 4;
+        /** Call log type for calls rejected by direct user action. */
+        public static final int REJECTED_TYPE = 5;
+        /** Call log type for calls blocked automatically. */
+        public static final int BLOCKED_TYPE = 6;
 
         /**
          * Bit-mask describing features of the call (e.g. video).
diff --git a/core/java/android/util/MathUtils.java b/core/java/android/util/MathUtils.java
index 8b57d3d..32aac13 100644
--- a/core/java/android/util/MathUtils.java
+++ b/core/java/android/util/MathUtils.java
@@ -156,6 +156,27 @@
         return start + (stop - start) * amount;
     }
 
+    /**
+     * Returns an interpolated angle in degrees between a set of start and end
+     * angles.
+     * <p>
+     * Unlike {@link #lerp(float, float, float)}, the direction and distance of
+     * travel is determined by the shortest angle between the start and end
+     * angles. For example, if the starting angle is 0 and the ending angle is
+     * 350, then the interpolated angle will be in the range [0,-10] rather
+     * than [0,350].
+     *
+     * @param start the starting angle in degrees
+     * @param end the ending angle in degrees
+     * @param amount the position between start and end in the range [0,1]
+     *               where 0 is the starting angle and 1 is the ending angle
+     * @return the interpolated angle in degrees
+     */
+    public static float lerpDeg(float start, float end, float amount) {
+        final float minAngle = (((end - start) + 180) % 360) - 180;
+        return minAngle * amount + start;
+    }
+
     public static float norm(float start, float stop, float value) {
         return (value - start) / (stop - start);
     }
@@ -185,4 +206,24 @@
     public static void randomSeed(long seed) {
         sRandom.setSeed(seed);
     }
+
+    /**
+     * Returns the sum of the two parameters, or throws an exception if the resulting sum would
+     * cause an overflow or underflow.
+     * @throws IllegalArgumentException when overflow or underflow would occur.
+     */
+    public static int addOrThrow(int a, int b) throws IllegalArgumentException {
+        if (b == 0) {
+            return a;
+        }
+
+        if (b > 0 && a <= (Integer.MAX_VALUE - b)) {
+            return a + b;
+        }
+
+        if (b < 0 && a >= (Integer.MIN_VALUE - b)) {
+            return a + b;
+        }
+        throw new IllegalArgumentException("Addition overflow: " + a + " + " + b);
+    }
 }
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index dcef142..304e9c0 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -349,7 +349,7 @@
      * @param right The right side of the protected bounds.
      * @param bottom The bottom side of the protected bounds.
      */
-    public void setContentOverdrawProtectionBounds(int left, int top, int right, int bottom) {
+    public void setContentDrawBounds(int left, int top, int right, int bottom) {
         mStagedContentBounds.set(left, top, right, bottom);
     }
 
@@ -370,9 +370,9 @@
         // renderer.
         if (!mCurrentContentBounds.equals(mStagedContentBounds)) {
             mCurrentContentBounds.set(mStagedContentBounds);
-            nSetContentOverdrawProtectionBounds(mNativeProxy, mCurrentContentBounds.left,
-                mCurrentContentBounds.top, mCurrentContentBounds.right,
-            mCurrentContentBounds.bottom);
+            nSetContentDrawBounds(mNativeProxy, mCurrentContentBounds.left,
+                    mCurrentContentBounds.top, mCurrentContentBounds.right,
+                    mCurrentContentBounds.bottom);
         }
 
         attachInfo.mIgnoreDirtyState = false;
@@ -600,6 +600,6 @@
              boolean placeFront);
     private static native void nRemoveRenderNode(long nativeProxy, long rootRenderNode);
     private static native void nDrawRenderNode(long nativeProxy, long rootRenderNode);
-    private static native void nSetContentOverdrawProtectionBounds(long nativeProxy, int left,
+    private static native void nSetContentDrawBounds(long nativeProxy, int left,
              int top, int right, int bottom);
 }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index f6c60ed..7cf23e7 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -73,6 +73,7 @@
 import android.view.animation.Interpolator;
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputMethodManager;
+import android.view.WindowCallbacks;
 import android.widget.Scroller;
 
 import com.android.internal.R;
@@ -115,6 +116,12 @@
     private static final boolean DEBUG_INPUT_STAGES = false || LOCAL_LOGV;
 
     /**
+     * Set to false if we do not want to use the multi threaded renderer. Note that by disabling
+     * this, WindowCallbacks will not fire.
+     */
+    private static final boolean USE_MT_RENDERER = true;
+
+    /**
      * Set this system property to true to force the view hierarchy to render
      * at 60 Hz. This can be used to measure the potential framerate.
      */
@@ -132,11 +139,11 @@
 
     static final ThreadLocal<HandlerActionQueue> sRunQueues = new ThreadLocal<HandlerActionQueue>();
 
-    static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList<Runnable>();
+    static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList();
     static boolean sFirstDrawComplete = false;
+    static final ArrayList<WindowCallbacks> sWindowCallbacks = new ArrayList();
 
-    static final ArrayList<ComponentCallbacks> sConfigCallbacks
-            = new ArrayList<ComponentCallbacks>();
+    static final ArrayList<ComponentCallbacks> sConfigCallbacks = new ArrayList();
 
     final Context mContext;
     final IWindowSession mWindowSession;
@@ -417,6 +424,22 @@
         }
     }
 
+    public static void addWindowCallbacks(WindowCallbacks callback) {
+        if (USE_MT_RENDERER) {
+            synchronized (sWindowCallbacks) {
+                sWindowCallbacks.add(callback);
+            }
+        }
+    }
+
+    public static void removeWindowCallbacks(WindowCallbacks callback) {
+        if (USE_MT_RENDERER) {
+            synchronized (sWindowCallbacks) {
+                sWindowCallbacks.remove(callback);
+            }
+        }
+    }
+
     // FIXME for perf testing only
     private boolean mProfile = false;
 
@@ -1378,6 +1401,7 @@
             mAttachInfo.mWindowVisibility = viewVisibility;
             host.dispatchWindowVisibilityChanged(viewVisibility);
             if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
+                endDragResizing();
                 destroyHardwareResources();
             }
             if (viewVisibility == View.GONE) {
@@ -1701,14 +1725,20 @@
                 final boolean dragResizing = (relayoutResult
                         & WindowManagerGlobal.RELAYOUT_RES_DRAG_RESIZING) != 0;
                 if (mDragResizing != dragResizing) {
-                    mDragResizing = dragResizing;
-                    mFullRedrawNeeded = true;
+                    if (dragResizing) {
+                        startDragResizing(frame);
+                    } else {
+                        // We shouldn't come here, but if we come we should end the resize.
+                        endDragResizing();
+                    }
                 }
-                if (dragResizing) {
-                    mCanvasOffsetX = mWinFrame.left;
-                    mCanvasOffsetY = mWinFrame.top;
-                } else {
-                    mCanvasOffsetX = mCanvasOffsetY = 0;
+                if (!USE_MT_RENDERER) {
+                    if (dragResizing) {
+                        mCanvasOffsetX = mWinFrame.left;
+                        mCanvasOffsetY = mWinFrame.top;
+                    } else {
+                        mCanvasOffsetX = mCanvasOffsetY = 0;
+                    }
                 }
             } catch (RemoteException e) {
             }
@@ -6635,6 +6665,15 @@
                 Configuration newConfig) {
             final ViewRootImpl viewAncestor = mViewAncestor.get();
             if (viewAncestor != null) {
+                // Tell all listeners that we are resizing the window so that the chrome can get
+                // updated as fast as possible on a separate thread,
+                if (mViewAncestor.get().mDragResizing) {
+                    synchronized (sWindowCallbacks) {
+                        for (int i = sWindowCallbacks.size() - 1; i >= 0; i--) {
+                            sWindowCallbacks.get(i).onWindowSizeIsChanging(frame);
+                        }
+                    }
+                }
                 viewAncestor.dispatchResized(frame, overscanInsets, contentInsets,
                         visibleInsets, stableInsets, outsets, reportDraw, newConfig);
             }
@@ -6804,6 +6843,36 @@
     }
 
     /**
+     * Start a drag resizing which will inform all listeners that a window resize is taking place.
+     */
+    private void startDragResizing(Rect initialBounds) {
+        if (!mDragResizing) {
+            mDragResizing = true;
+            synchronized (sWindowCallbacks) {
+                for (int i = sWindowCallbacks.size() - 1; i >= 0; i--) {
+                    sWindowCallbacks.get(i).onWindowDragResizeStart(initialBounds);
+                }
+            }
+            mFullRedrawNeeded = true;
+        }
+    }
+
+    /**
+     * End a drag resize which will inform all listeners that a window resize has ended.
+     */
+    private void endDragResizing() {
+        if (mDragResizing) {
+            mDragResizing = false;
+            synchronized (sWindowCallbacks) {
+                for (int i = sWindowCallbacks.size() - 1; i >= 0; i--) {
+                    sWindowCallbacks.get(i).onWindowDragResizeEnd();
+                }
+            }
+            mFullRedrawNeeded = true;
+        }
+    }
+
+    /**
      * Class for managing the accessibility interaction connection
      * based on the global accessibility state.
      */
diff --git a/core/java/android/view/WindowCallbacks.java b/core/java/android/view/WindowCallbacks.java
new file mode 100644
index 0000000..cb6e983
--- /dev/null
+++ b/core/java/android/view/WindowCallbacks.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.graphics.Rect;
+
+/**
+ * These callbacks are used to communicate window configuration changes while the user is performing
+ * window changes.
+ * @hide
+ */
+public interface WindowCallbacks {
+    /**
+     * Called by the system when the window got changed by the user, before the layouter got called.
+     * It can be used to perform a "quick and dirty" resize which should never take more then 4ms to
+     * complete.
+     *
+     * <p>At the time the layouting has not happened yet.
+     *
+     * @param newBounds The new window frame bounds.
+     */
+    void onWindowSizeIsChanging(Rect newBounds);
+
+    /**
+     * Called when a drag resize starts.
+     * @param initialBounds The initial bounds where the window will be.
+     */
+    void onWindowDragResizeStart(Rect initialBounds);
+
+    /**
+     * Called when a drag resize ends.
+     */
+    void onWindowDragResizeEnd();
+}
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 72971e8..81ec330 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -88,6 +88,9 @@
     /** @hide */
     public static final int DALTONIZER_CORRECT_DEUTERANOMALY = 12;
 
+    /** @hide */
+    public static final int AUTOCLICK_DELAY_DEFAULT = 600;
+
     static final Object sInstanceSync = new Object();
 
     private static AccessibilityManager sInstance;
diff --git a/core/java/android/widget/RadialTimePickerView.java b/core/java/android/widget/RadialTimePickerView.java
index 9571109..7220256 100644
--- a/core/java/android/widget/RadialTimePickerView.java
+++ b/core/java/android/widget/RadialTimePickerView.java
@@ -16,12 +16,7 @@
 
 package android.widget;
 
-import android.animation.Animator;
-import android.animation.AnimatorSet;
-import android.animation.Keyframe;
 import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
-import android.animation.ValueAnimator;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
@@ -35,6 +30,7 @@
 import android.graphics.Typeface;
 import android.os.Bundle;
 import android.util.AttributeSet;
+import android.util.FloatProperty;
 import android.util.IntArray;
 import android.util.Log;
 import android.util.MathUtils;
@@ -50,7 +46,6 @@
 import com.android.internal.R;
 import com.android.internal.widget.ExploreByTouchHelper;
 
-import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Locale;
 
@@ -60,6 +55,7 @@
  * @hide
  */
 public class RadialTimePickerView extends View {
+
     private static final String TAG = "RadialTimePickerView";
 
     private static final int HOURS = 0;
@@ -73,12 +69,6 @@
     private static final int AM = 0;
     private static final int PM = 1;
 
-    // Opaque alpha level
-    private static final int ALPHA_OPAQUE = 255;
-
-    // Transparent alpha level
-    private static final int ALPHA_TRANSPARENT = 0;
-
     private static final int HOURS_IN_CIRCLE = 12;
     private static final int MINUTES_IN_CIRCLE = 60;
     private static final int DEGREES_FOR_ONE_HOUR = 360 / HOURS_IN_CIRCLE;
@@ -88,8 +78,8 @@
     private static final int[] HOURS_NUMBERS_24 = {0, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23};
     private static final int[] MINUTES_NUMBERS = {0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55};
 
-    private static final int FADE_OUT_DURATION = 500;
-    private static final int FADE_IN_DURATION = 500;
+    private static final int ANIM_DURATION_NORMAL = 500;
+    private static final int ANIM_DURATION_TOUCH = 60;
 
     private static final int[] SNAP_PREFER_30S_MAP = new int[361];
 
@@ -97,6 +87,9 @@
     private static final float[] COS_30 = new float[NUM_POSITIONS];
     private static final float[] SIN_30 = new float[NUM_POSITIONS];
 
+    /** "Something is wrong" color used when a color attribute is missing. */
+    private static final int MISSING_COLOR = Color.MAGENTA;
+
     static {
         // Prepare mapping to snap touchable degrees to selectable degrees.
         preparePrefer30sMap();
@@ -110,8 +103,19 @@
         }
     }
 
-    private final InvalidateUpdateListener mInvalidateUpdateListener =
-            new InvalidateUpdateListener();
+    private final FloatProperty<RadialTimePickerView> HOURS_TO_MINUTES =
+            new FloatProperty<RadialTimePickerView>("hoursToMinutes") {
+                @Override
+                public Float get(RadialTimePickerView radialTimePickerView) {
+                    return radialTimePickerView.mHoursToMinutes;
+                }
+
+                @Override
+                public void setValue(RadialTimePickerView object, float value) {
+                    object.mHoursToMinutes = value;
+                    object.invalidate();
+                }
+            };
 
     private final String[] mHours12Texts = new String[12];
     private final String[] mOuterHours24Texts = new String[12];
@@ -119,15 +123,8 @@
     private final String[] mMinutesTexts = new String[12];
 
     private final Paint[] mPaint = new Paint[2];
-    private final IntHolder[] mAlpha = new IntHolder[2];
-
     private final Paint mPaintCenter = new Paint();
-
-    private final Paint[][] mPaintSelector = new Paint[2][3];
-
-    private final int mSelectorColor;
-    private final int mSelectorDotColor;
-
+    private final Paint[] mPaintSelector = new Paint[3];
     private final Paint mPaintBackground = new Paint();
 
     private final Typeface mTypeface;
@@ -144,9 +141,6 @@
 
     private final int[] mSelectionDegrees = new int[2];
 
-    private final ArrayList<Animator> mHoursToMinutesAnims = new ArrayList<>();
-    private final ArrayList<Animator> mMinuteToHoursAnims = new ArrayList<>();
-
     private final RadialPickerTouchHelper mTouchHelper;
 
     private final Path mSelectorPath = new Path();
@@ -154,6 +148,9 @@
     private boolean mIs24HourMode;
     private boolean mShowHours;
 
+    private ObjectAnimator mHoursToMinutesAnimator;
+    private float mHoursToMinutes;
+
     /**
      * When in 24-hour mode, indicates that the current hour is between
      * 1 and 12 (inclusive).
@@ -165,6 +162,9 @@
     private int mSelectorDotRadius;
     private int mCenterDotRadius;
 
+    private int mSelectorColor;
+    private int mSelectorDotColor;
+
     private int mXCenter;
     private int mYCenter;
     private int mCircleRadius;
@@ -176,7 +176,6 @@
     private String[] mOuterTextHours;
     private String[] mInnerTextHours;
     private String[] mMinutesText;
-    private AnimatorSet mTransition;
 
     private int mAmOrPm;
 
@@ -304,27 +303,15 @@
             Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)  {
         super(context, attrs);
 
+        applyAttributes(attrs, defStyleAttr, defStyleRes);
+
         // Pull disabled alpha from theme.
         final TypedValue outValue = new TypedValue();
         context.getTheme().resolveAttribute(android.R.attr.disabledAlpha, outValue, true);
         mDisabledAlpha = outValue.getFloat();
 
-        // process style attributes
-        final Resources res = getResources();
-        final TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.TimePicker,
-                defStyleAttr, defStyleRes);
-
         mTypeface = Typeface.create("sans-serif", Typeface.NORMAL);
 
-        // Initialize all alpha values to opaque.
-        for (int i = 0; i < mAlpha.length; i++) {
-            mAlpha[i] = new IntHolder(ALPHA_OPAQUE);
-        }
-
-        mTextColor[HOURS] = a.getColorStateList(R.styleable.TimePicker_numbersTextColor);
-        mTextColor[HOURS_INNER] = a.getColorStateList(R.styleable.TimePicker_numbersInnerTextColor);
-        mTextColor[MINUTES] = mTextColor[HOURS];
-
         mPaint[HOURS] = new Paint();
         mPaint[HOURS].setAntiAlias(true);
         mPaint[HOURS].setTextAlign(Paint.Align.CENTER);
@@ -333,44 +320,21 @@
         mPaint[MINUTES].setAntiAlias(true);
         mPaint[MINUTES].setTextAlign(Paint.Align.CENTER);
 
-        final ColorStateList selectorColors = a.getColorStateList(
-                R.styleable.TimePicker_numbersSelectorColor);
-        final int selectorActivatedColor = selectorColors.getColorForState(
-                StateSet.get(StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_ACTIVATED), 0);
-
-        mPaintCenter.setColor(selectorActivatedColor);
         mPaintCenter.setAntiAlias(true);
 
-        final int[] activatedStateSet = StateSet.get(
-                StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_ACTIVATED);
+        mPaintSelector[SELECTOR_CIRCLE] = new Paint();
+        mPaintSelector[SELECTOR_CIRCLE].setAntiAlias(true);
 
-        mSelectorColor = selectorActivatedColor;
-        mSelectorDotColor = mTextColor[HOURS].getColorForState(activatedStateSet, 0);
+        mPaintSelector[SELECTOR_DOT] = new Paint();
+        mPaintSelector[SELECTOR_DOT].setAntiAlias(true);
 
-        mPaintSelector[HOURS][SELECTOR_CIRCLE] = new Paint();
-        mPaintSelector[HOURS][SELECTOR_CIRCLE].setAntiAlias(true);
+        mPaintSelector[SELECTOR_LINE] = new Paint();
+        mPaintSelector[SELECTOR_LINE].setAntiAlias(true);
+        mPaintSelector[SELECTOR_LINE].setStrokeWidth(2);
 
-        mPaintSelector[HOURS][SELECTOR_DOT] = new Paint();
-        mPaintSelector[HOURS][SELECTOR_DOT].setAntiAlias(true);
-
-        mPaintSelector[HOURS][SELECTOR_LINE] = new Paint();
-        mPaintSelector[HOURS][SELECTOR_LINE].setAntiAlias(true);
-        mPaintSelector[HOURS][SELECTOR_LINE].setStrokeWidth(2);
-
-        mPaintSelector[MINUTES][SELECTOR_CIRCLE] = new Paint();
-        mPaintSelector[MINUTES][SELECTOR_CIRCLE].setAntiAlias(true);
-
-        mPaintSelector[MINUTES][SELECTOR_DOT] = new Paint();
-        mPaintSelector[MINUTES][SELECTOR_DOT].setAntiAlias(true);
-
-        mPaintSelector[MINUTES][SELECTOR_LINE] = new Paint();
-        mPaintSelector[MINUTES][SELECTOR_LINE].setAntiAlias(true);
-        mPaintSelector[MINUTES][SELECTOR_LINE].setStrokeWidth(2);
-
-        mPaintBackground.setColor(a.getColor(R.styleable.TimePicker_numbersBackgroundColor,
-                context.getColor(R.color.timepicker_default_numbers_background_color_material)));
         mPaintBackground.setAntiAlias(true);
 
+        final Resources res = getResources();
         mSelectorRadius = res.getDimensionPixelSize(R.dimen.timepicker_selector_radius);
         mSelectorStroke = res.getDimensionPixelSize(R.dimen.timepicker_selector_stroke);
         mSelectorDotRadius = res.getDimensionPixelSize(R.dimen.timepicker_selector_dot_radius);
@@ -385,6 +349,7 @@
         mTextInset[HOURS_INNER] = res.getDimensionPixelSize(R.dimen.timepicker_text_inset_inner);
 
         mShowHours = true;
+        mHoursToMinutes = HOURS;
         mIs24HourMode = false;
         mAmOrPm = AM;
 
@@ -399,8 +364,6 @@
         initHoursAndMinutesText();
         initData();
 
-        a.recycle();
-
         // Initial values
         final Calendar calendar = Calendar.getInstance(Locale.getDefault());
         final int currentHour = calendar.get(Calendar.HOUR_OF_DAY);
@@ -412,6 +375,48 @@
         setHapticFeedbackEnabled(true);
     }
 
+    void applyAttributes(AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        final Context context = getContext();
+        final TypedArray a = getContext().obtainStyledAttributes(attrs,
+                R.styleable.TimePicker, defStyleAttr, defStyleRes);
+
+        final ColorStateList numbersTextColor = a.getColorStateList(
+                R.styleable.TimePicker_numbersTextColor);
+        final ColorStateList numbersInnerTextColor = a.getColorStateList(
+                R.styleable.TimePicker_numbersInnerTextColor);
+        mTextColor[HOURS] = numbersTextColor == null ?
+                ColorStateList.valueOf(MISSING_COLOR) : numbersTextColor;
+        mTextColor[HOURS_INNER] = numbersInnerTextColor == null ?
+                ColorStateList.valueOf(MISSING_COLOR) : numbersInnerTextColor;
+        mTextColor[MINUTES] = mTextColor[HOURS];
+
+        // Set up various colors derived from the selector "activated" state.
+        final ColorStateList selectorColors = a.getColorStateList(
+                R.styleable.TimePicker_numbersSelectorColor);
+        final int selectorActivatedColor;
+        if (selectorColors != null) {
+            final int[] stateSetEnabledActivated = StateSet.get(
+                    StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_ACTIVATED);
+            selectorActivatedColor = selectorColors.getColorForState(
+                    stateSetEnabledActivated, 0);
+        }  else {
+            selectorActivatedColor = MISSING_COLOR;
+        }
+
+        mPaintCenter.setColor(selectorActivatedColor);
+
+        final int[] stateSetActivated = StateSet.get(
+                StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_ACTIVATED);
+
+        mSelectorColor = selectorActivatedColor;
+        mSelectorDotColor = mTextColor[HOURS].getColorForState(stateSetActivated, 0);
+
+        mPaintBackground.setColor(a.getColor(R.styleable.TimePicker_numbersBackgroundColor,
+                context.getColor(R.color.timepicker_default_numbers_background_color_material)));
+
+        a.recycle();
+    }
+
     public void initialize(int hour, int minute, boolean is24HourMode) {
         if (mIs24HourMode != is24HourMode) {
             mIs24HourMode = is24HourMode;
@@ -569,35 +574,11 @@
     }
 
     public void showHours(boolean animate) {
-        if (mShowHours) {
-            return;
-        }
-
-        mShowHours = true;
-
-        if (animate) {
-            startMinutesToHoursAnimation();
-        }
-
-        initData();
-        invalidate();
-        mTouchHelper.invalidateRoot();
+        showPicker(true, animate);
     }
 
     public void showMinutes(boolean animate) {
-        if (!mShowHours) {
-            return;
-        }
-
-        mShowHours = false;
-
-        if (animate) {
-            startHoursToMinutesAnimation();
-        }
-
-        initData();
-        invalidate();
-        mTouchHelper.invalidateRoot();
+        showPicker(false, animate);
     }
 
     private void initHoursAndMinutesText() {
@@ -620,12 +601,6 @@
         }
 
         mMinutesText = mMinutesTexts;
-
-        final int hoursAlpha = mShowHours ? ALPHA_OPAQUE : ALPHA_TRANSPARENT;
-        mAlpha[HOURS].setValue(hoursAlpha);
-
-        final int minutesAlpha = mShowHours ? ALPHA_TRANSPARENT : ALPHA_OPAQUE;
-        mAlpha[MINUTES].setValue(minutesAlpha);
     }
 
     @Override
@@ -653,90 +628,144 @@
         final float alphaMod = mInputEnabled ? 1 : mDisabledAlpha;
 
         drawCircleBackground(canvas);
-        drawHours(canvas, alphaMod);
-        drawMinutes(canvas, alphaMod);
+
+        final Path selectorPath = mSelectorPath;
+        drawSelector(canvas, selectorPath);
+        drawHours(canvas, selectorPath, alphaMod);
+        drawMinutes(canvas, selectorPath, alphaMod);
         drawCenter(canvas, alphaMod);
     }
 
+    private void showPicker(boolean hours, boolean animate) {
+        if (mShowHours == hours) {
+            return;
+        }
+
+        mShowHours = hours;
+
+        if (animate) {
+            animatePicker(hours, ANIM_DURATION_NORMAL);
+        }
+
+        initData();
+        invalidate();
+        mTouchHelper.invalidateRoot();
+    }
+
+    private void animatePicker(boolean hoursToMinutes, long duration) {
+        final float target = hoursToMinutes ? HOURS : MINUTES;
+        if (mHoursToMinutes == target) {
+            // If we have a pending or running animator, cancel it.
+            if (mHoursToMinutesAnimator != null && mHoursToMinutesAnimator.isStarted()) {
+                mHoursToMinutesAnimator.cancel();
+                mHoursToMinutesAnimator = null;
+            }
+
+            // We're already showing the correct picker.
+            return;
+        }
+
+        mHoursToMinutesAnimator = ObjectAnimator.ofFloat(this, HOURS_TO_MINUTES, target);
+        mHoursToMinutesAnimator.setAutoCancel(true);
+        mHoursToMinutesAnimator.setDuration(duration);
+        mHoursToMinutesAnimator.start();
+    }
+
     private void drawCircleBackground(Canvas canvas) {
         canvas.drawCircle(mXCenter, mYCenter, mCircleRadius, mPaintBackground);
     }
 
-    private void drawHours(Canvas canvas, float alphaMod) {
-        final int hoursAlpha = (int) (mAlpha[HOURS].getValue() * alphaMod + 0.5f);
+    private void drawHours(Canvas canvas, Path selectorPath, float alphaMod) {
+        final int hoursAlpha = (int) (255f * (1f - mHoursToMinutes) * alphaMod + 0.5f);
         if (hoursAlpha > 0) {
-            // Draw the hour selector under the elements.
-            drawSelector(canvas, mIsOnInnerCircle ? HOURS_INNER : HOURS, null, alphaMod);
-
-            // Draw outer hours.
-            drawTextElements(canvas, mTextSize[HOURS], mTypeface, mTextColor[HOURS],
-                    mOuterTextHours, mOuterTextX[HOURS], mOuterTextY[HOURS], mPaint[HOURS],
-                    hoursAlpha, !mIsOnInnerCircle, mSelectionDegrees[HOURS], false);
-
-            // Draw inner hours (13-00) for 24-hour time.
-            if (mIs24HourMode && mInnerTextHours != null) {
-                drawTextElements(canvas, mTextSize[HOURS_INNER], mTypeface, mTextColor[HOURS_INNER],
-                        mInnerTextHours, mInnerTextX, mInnerTextY, mPaint[HOURS], hoursAlpha,
-                        mIsOnInnerCircle, mSelectionDegrees[HOURS], false);
-            }
-        }
-    }
-
-    private void drawMinutes(Canvas canvas, float alphaMod) {
-        final int minutesAlpha = (int) (mAlpha[MINUTES].getValue() * alphaMod + 0.5f);
-        if (minutesAlpha > 0) {
-            // Draw the minute selector under the elements.
-            drawSelector(canvas, MINUTES, mSelectorPath, alphaMod);
-
-            // Exclude the selector region, then draw minutes with no
+            // Exclude the selector region, then draw inner/outer hours with no
             // activated states.
             canvas.save(Canvas.CLIP_SAVE_FLAG);
-            canvas.clipPath(mSelectorPath, Region.Op.DIFFERENCE);
-            drawTextElements(canvas, mTextSize[MINUTES], mTypeface, mTextColor[MINUTES],
-                    mMinutesText, mOuterTextX[MINUTES], mOuterTextY[MINUTES], mPaint[MINUTES],
-                    minutesAlpha, false, 0, false);
+            canvas.clipPath(selectorPath, Region.Op.DIFFERENCE);
+            drawHoursClipped(canvas, hoursAlpha, false);
             canvas.restore();
 
             // Intersect the selector region, then draw minutes with only
             // activated states.
             canvas.save(Canvas.CLIP_SAVE_FLAG);
-            canvas.clipPath(mSelectorPath, Region.Op.INTERSECT);
-            drawTextElements(canvas, mTextSize[MINUTES], mTypeface, mTextColor[MINUTES],
-                    mMinutesText, mOuterTextX[MINUTES], mOuterTextY[MINUTES], mPaint[MINUTES],
-                    minutesAlpha, true, mSelectionDegrees[MINUTES], true);
+            canvas.clipPath(selectorPath, Region.Op.INTERSECT);
+            drawHoursClipped(canvas, hoursAlpha, true);
             canvas.restore();
         }
     }
 
+    private void drawHoursClipped(Canvas canvas, int hoursAlpha, boolean showActivated) {
+        // Draw outer hours.
+        drawTextElements(canvas, mTextSize[HOURS], mTypeface, mTextColor[HOURS], mOuterTextHours,
+                mOuterTextX[HOURS], mOuterTextY[HOURS], mPaint[HOURS], hoursAlpha,
+                showActivated && !mIsOnInnerCircle, mSelectionDegrees[HOURS], showActivated);
+
+        // Draw inner hours (13-00) for 24-hour time.
+        if (mIs24HourMode && mInnerTextHours != null) {
+            drawTextElements(canvas, mTextSize[HOURS_INNER], mTypeface, mTextColor[HOURS_INNER],
+                    mInnerTextHours, mInnerTextX, mInnerTextY, mPaint[HOURS], hoursAlpha,
+                    showActivated && mIsOnInnerCircle, mSelectionDegrees[HOURS], showActivated);
+        }
+    }
+
+    private void drawMinutes(Canvas canvas, Path selectorPath, float alphaMod) {
+        final int minutesAlpha = (int) (255f * mHoursToMinutes * alphaMod + 0.5f);
+        if (minutesAlpha > 0) {
+            // Exclude the selector region, then draw minutes with no
+            // activated states.
+            canvas.save(Canvas.CLIP_SAVE_FLAG);
+            canvas.clipPath(selectorPath, Region.Op.DIFFERENCE);
+            drawMinutesClipped(canvas, minutesAlpha, false);
+            canvas.restore();
+
+            // Intersect the selector region, then draw minutes with only
+            // activated states.
+            canvas.save(Canvas.CLIP_SAVE_FLAG);
+            canvas.clipPath(selectorPath, Region.Op.INTERSECT);
+            drawMinutesClipped(canvas, minutesAlpha, true);
+            canvas.restore();
+        }
+    }
+
+    private void drawMinutesClipped(Canvas canvas, int minutesAlpha, boolean showActivated) {
+        drawTextElements(canvas, mTextSize[MINUTES], mTypeface, mTextColor[MINUTES], mMinutesText,
+                mOuterTextX[MINUTES], mOuterTextY[MINUTES], mPaint[MINUTES], minutesAlpha,
+                showActivated, mSelectionDegrees[MINUTES], showActivated);
+    }
+
     private void drawCenter(Canvas canvas, float alphaMod) {
         mPaintCenter.setAlpha((int) (255 * alphaMod + 0.5f));
         canvas.drawCircle(mXCenter, mYCenter, mCenterDotRadius, mPaintCenter);
     }
 
-    private int applyAlpha(int argb, int alpha) {
-        final int srcAlpha = (argb >> 24) & 0xFF;
-        final int dstAlpha = (int) (srcAlpha * (alpha / 255.0) + 0.5f);
-        return (0xFFFFFF & argb) | (dstAlpha << 24);
-    }
-
     private int getMultipliedAlpha(int argb, int alpha) {
         return (int) (Color.alpha(argb) * (alpha / 255.0) + 0.5);
     }
 
-    private void drawSelector(Canvas canvas, int index, Path selectorPath, float alphaMod) {
-        final int alpha = (int) (mAlpha[index % 2].getValue() * alphaMod + 0.5f);
-        final int color = applyAlpha(mSelectorColor, alpha);
+    private void drawSelector(Canvas canvas, Path selectorPath) {
+        // Determine the current length, angle, and dot scaling factor.
+        final int hoursIndex = mIsOnInnerCircle ? HOURS_INNER : HOURS;
+        final int hoursInset = mTextInset[hoursIndex];
+        final int hoursAngleDeg = mSelectionDegrees[hoursIndex % 2];
+        final float hoursDotScale = mSelectionDegrees[hoursIndex % 2] % 30 != 0 ? 1 : 0;
+
+        final int minutesIndex = MINUTES;
+        final int minutesInset = mTextInset[minutesIndex];
+        final int minutesAngleDeg = mSelectionDegrees[minutesIndex];
+        final float minutesDotScale = mSelectionDegrees[minutesIndex] % 30 != 0 ? 1 : 0;
 
         // Calculate the current radius at which to place the selection circle.
         final int selRadius = mSelectorRadius;
-        final int selLength = mCircleRadius - mTextInset[index];
-        final double selAngleRad = Math.toRadians(mSelectionDegrees[index % 2]);
+        final float selLength =
+                mCircleRadius - MathUtils.lerp(hoursInset, minutesInset, mHoursToMinutes);
+        final double selAngleRad =
+                Math.toRadians(MathUtils.lerpDeg(hoursAngleDeg, minutesAngleDeg, mHoursToMinutes));
         final float selCenterX = mXCenter + selLength * (float) Math.sin(selAngleRad);
         final float selCenterY = mYCenter - selLength * (float) Math.cos(selAngleRad);
 
         // Draw the selection circle.
-        final Paint paint = mPaintSelector[index % 2][SELECTOR_CIRCLE];
-        paint.setColor(color);
+        final Paint paint = mPaintSelector[SELECTOR_CIRCLE];
+        paint.setColor(mSelectorColor);
         canvas.drawCircle(selCenterX, selCenterY, selRadius, paint);
 
         // If needed, set up the clip path for later.
@@ -746,26 +775,26 @@
         }
 
         // Draw the dot if we're between two items.
-        final boolean shouldDrawDot = mSelectionDegrees[index % 2] % 30 != 0;
-        if (shouldDrawDot) {
-            final Paint dotPaint = mPaintSelector[index % 2][SELECTOR_DOT];
+        final float dotScale = MathUtils.lerp(hoursDotScale, minutesDotScale, mHoursToMinutes);
+        if (dotScale > 0) {
+            final Paint dotPaint = mPaintSelector[SELECTOR_DOT];
             dotPaint.setColor(mSelectorDotColor);
-            canvas.drawCircle(selCenterX, selCenterY, mSelectorDotRadius, dotPaint);
+            canvas.drawCircle(selCenterX, selCenterY, mSelectorDotRadius * dotScale, dotPaint);
         }
 
         // Shorten the line to only go from the edge of the center dot to the
         // edge of the selection circle.
         final double sin = Math.sin(selAngleRad);
         final double cos = Math.cos(selAngleRad);
-        final int lineLength = selLength - selRadius;
+        final float lineLength = selLength - selRadius;
         final int centerX = mXCenter + (int) (mCenterDotRadius * sin);
         final int centerY = mYCenter - (int) (mCenterDotRadius * cos);
         final float linePointX = centerX + (int) (lineLength * sin);
         final float linePointY = centerY - (int) (lineLength * cos);
 
         // Draw the line.
-        final Paint linePaint = mPaintSelector[index % 2][SELECTOR_LINE];
-        linePaint.setColor(color);
+        final Paint linePaint = mPaintSelector[SELECTOR_LINE];
+        linePaint.setColor(mSelectorColor);
         linePaint.setStrokeWidth(mSelectorStroke);
         canvas.drawLine(mXCenter, mYCenter, linePointX, linePointY, linePaint);
     }
@@ -842,73 +871,6 @@
         }
     }
 
-    private static ObjectAnimator getFadeOutAnimator(IntHolder target, int startAlpha, int endAlpha,
-                InvalidateUpdateListener updateListener) {
-        final ObjectAnimator animator = ObjectAnimator.ofInt(target, "value", startAlpha, endAlpha);
-        animator.setDuration(FADE_OUT_DURATION);
-        animator.addUpdateListener(updateListener);
-        return animator;
-    }
-
-    private static ObjectAnimator getFadeInAnimator(IntHolder target, int startAlpha, int endAlpha,
-                InvalidateUpdateListener updateListener) {
-        final float delayMultiplier = 0.25f;
-        final float transitionDurationMultiplier = 1f;
-        final float totalDurationMultiplier = transitionDurationMultiplier + delayMultiplier;
-        final int totalDuration = (int) (FADE_IN_DURATION * totalDurationMultiplier);
-        final float delayPoint = (delayMultiplier * FADE_IN_DURATION) / totalDuration;
-
-        final Keyframe kf0, kf1, kf2;
-        kf0 = Keyframe.ofInt(0f, startAlpha);
-        kf1 = Keyframe.ofInt(delayPoint, startAlpha);
-        kf2 = Keyframe.ofInt(1f, endAlpha);
-        final PropertyValuesHolder fadeIn = PropertyValuesHolder.ofKeyframe("value", kf0, kf1, kf2);
-
-        final ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(target, fadeIn);
-        animator.setDuration(totalDuration);
-        animator.addUpdateListener(updateListener);
-        return animator;
-    }
-
-    private class InvalidateUpdateListener implements ValueAnimator.AnimatorUpdateListener {
-        @Override
-        public void onAnimationUpdate(ValueAnimator animation) {
-            RadialTimePickerView.this.invalidate();
-        }
-    }
-
-    private void startHoursToMinutesAnimation() {
-        if (mHoursToMinutesAnims.size() == 0) {
-            mHoursToMinutesAnims.add(getFadeOutAnimator(mAlpha[HOURS],
-                    ALPHA_OPAQUE, ALPHA_TRANSPARENT, mInvalidateUpdateListener));
-            mHoursToMinutesAnims.add(getFadeInAnimator(mAlpha[MINUTES],
-                    ALPHA_TRANSPARENT, ALPHA_OPAQUE, mInvalidateUpdateListener));
-        }
-
-        if (mTransition != null && mTransition.isRunning()) {
-            mTransition.end();
-        }
-        mTransition = new AnimatorSet();
-        mTransition.playTogether(mHoursToMinutesAnims);
-        mTransition.start();
-    }
-
-    private void startMinutesToHoursAnimation() {
-        if (mMinuteToHoursAnims.size() == 0) {
-            mMinuteToHoursAnims.add(getFadeOutAnimator(mAlpha[MINUTES],
-                    ALPHA_OPAQUE, ALPHA_TRANSPARENT, mInvalidateUpdateListener));
-            mMinuteToHoursAnims.add(getFadeInAnimator(mAlpha[HOURS],
-                    ALPHA_TRANSPARENT, ALPHA_OPAQUE, mInvalidateUpdateListener));
-        }
-
-        if (mTransition != null && mTransition.isRunning()) {
-            mTransition.end();
-        }
-        mTransition = new AnimatorSet();
-        mTransition.playTogether(mMinuteToHoursAnims);
-        mTransition.start();
-    }
-
     private int getDegreesFromXY(float x, float y, boolean constrainOutside) {
         // Ensure the point is inside the touchable area.
         final int innerBound;
@@ -992,6 +954,9 @@
             return false;
         }
 
+        // Ensure we're showing the correct picker.
+        animatePicker(mShowHours, ANIM_DURATION_TOUCH);
+
         final int type;
         final int newValue;
         final boolean valueChanged;
@@ -1356,20 +1321,4 @@
             return id >>> SHIFT_VALUE & MASK_VALUE;
         }
     }
-
-    private static class IntHolder {
-        private int mValue;
-
-        public IntHolder(int value) {
-            mValue = value;
-        }
-
-        public void setValue(int value) {
-            mValue = value;
-        }
-
-        public int getValue() {
-            return mValue;
-        }
-    }
 }
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index 61ef6dc..6d41c1d 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -200,8 +200,8 @@
 
         a.recycle();
 
-        mRadialTimePickerView = (RadialTimePickerView) mainView.findViewById(
-                R.id.radial_picker);
+        mRadialTimePickerView = (RadialTimePickerView) mainView.findViewById(R.id.radial_picker);
+        mRadialTimePickerView.applyAttributes(attrs, defStyleAttr, defStyleRes);
 
         setupListeners();
 
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index b6d7364..c9b8119 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -2615,7 +2615,7 @@
             if (action == MotionEvent.ACTION_DOWN) {
                 int y = (int)event.getY();
                 if (y >= (getHeight()-5) && !mWindow.hasChildren()) {
-                    Log.i(TAG, "Watchiing!");
+                    Log.i(TAG, "Watching!");
                     mWatchingForMenu = true;
                 }
                 return false;
diff --git a/core/java/com/android/internal/widget/NonClientDecorView.java b/core/java/com/android/internal/widget/NonClientDecorView.java
index 56cf921..7b80ac2 100644
--- a/core/java/com/android/internal/widget/NonClientDecorView.java
+++ b/core/java/com/android/internal/widget/NonClientDecorView.java
@@ -17,15 +17,23 @@
 package com.android.internal.widget;
 
 import android.content.Context;
+import android.graphics.Color;
 import android.graphics.Rect;
+import android.os.Looper;
 import android.os.RemoteException;
 import android.util.AttributeSet;
+import android.view.Choreographer;
+import android.view.DisplayListCanvas;
 import android.view.MotionEvent;
+import android.view.RenderNode;
+import android.view.ThreadedRenderer;
 import android.view.View;
+import android.view.ViewRootImpl;
 import android.widget.LinearLayout;
 import android.view.ViewGroup;
 import android.view.ViewOutlineProvider;
 import android.view.Window;
+import android.view.WindowCallbacks;
 import android.util.Log;
 import android.util.TypedValue;
 
@@ -58,7 +66,7 @@
  * This will be mitigated once b/22527834 will be addressed.
  */
 public class NonClientDecorView extends LinearLayout
-        implements View.OnClickListener, View.OnTouchListener {
+        implements View.OnClickListener, View.OnTouchListener, WindowCallbacks {
     private final static String TAG = "NonClientDecorView";
     // The height of a window which has focus in DIP.
     private final int DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP = 20;
@@ -67,6 +75,8 @@
     private PhoneWindow mOwner = null;
     private boolean mWindowHasShadow = false;
     private boolean mShowDecor = false;
+    // True when this object is listening for window size changes.
+    private boolean mAttachedCallbacksToRootViewImpl = false;
 
     // True if the window is being dragged.
     private boolean mDragging = false;
@@ -85,6 +95,9 @@
     // to max until the first layout command has been executed.
     private boolean mAllowUpdateElevation = false;
 
+    // The resize frame renderer.
+    private ResizeFrameThread mFrameRendererThread = null;
+
     public NonClientDecorView(Context context) {
         super(context);
     }
@@ -108,6 +121,18 @@
         // By changing the outline provider to BOUNDS, the window can remove its
         // background without removing the shadow.
         mOwner.getDecorView().setOutlineProvider(ViewOutlineProvider.BOUNDS);
+
+        if (!mAttachedCallbacksToRootViewImpl) {
+            // If there is no window callback installed there was no window set before. Set it now.
+            // Note that our ViewRootImpl object will not change.
+            getViewRootImpl().addWindowCallbacks(this);
+            mAttachedCallbacksToRootViewImpl = true;
+        } else if (mFrameRendererThread != null) {
+            // We are resizing and this call happened due to a configuration change. Tell the
+            // renderer about it.
+            mFrameRendererThread.onConfigurationChange();
+        }
+
         findViewById(R.id.maximize_window).setOnClickListener(this);
         findViewById(R.id.close_window).setOnClickListener(this);
     }
@@ -251,7 +276,9 @@
      **/
     private void updateElevation() {
         float elevation = 0;
-        if (mWindowHasShadow) {
+        // Do not use a shadow when we are in resizing mode (mRenderer not null) since the shadow
+        // is bound to the content size and not the target size.
+        if (mWindowHasShadow && mFrameRendererThread == null) {
             boolean fill = isFillingScreen();
             elevation = fill ? 0 :
                     (mWindowHasFocus ? DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP :
@@ -293,4 +320,274 @@
             }
         }
     }
+
+    @Override
+    public void onWindowDragResizeStart(Rect initialBounds) {
+        if (mOwner.isDestroyed()) {
+            // If the owner's window is gone, we should not be able to come here anymore.
+            releaseResources();
+            return;
+        }
+        if (mFrameRendererThread != null) {
+            return;
+        }
+        final ThreadedRenderer renderer =
+                (ThreadedRenderer) mOwner.getDecorView().getHardwareRenderer();
+        if (renderer != null) {
+            mFrameRendererThread = new ResizeFrameThread(renderer, initialBounds);
+            // Get rid of the shadow while we are resizing. Shadow drawing takes considerable time.
+            // If we want to get the shadow shown while resizing, we would need to elevate a new
+            // element which owns the caption and has the elevation.
+            updateElevation();
+        }
+    }
+
+    @Override
+    public void onWindowDragResizeEnd() {
+        releaseThreadedRenderer();
+    }
+
+    @Override
+    public void onWindowSizeIsChanging(Rect newBounds) {
+        if (mFrameRendererThread != null) {
+            mFrameRendererThread.setTargetRect(newBounds);
+        }
+    }
+
+    /**
+     * Release the renderer thread which is usually done when the user stops resizing.
+     */
+    private void releaseThreadedRenderer() {
+        if (mFrameRendererThread != null) {
+            mFrameRendererThread.releaseRenderer();
+            mFrameRendererThread = null;
+            // Bring the shadow back.
+            updateElevation();
+        }
+    }
+
+    /**
+     * Called when the parent window is destroyed to release all resources. Note that this will also
+     * destroy the renderer thread.
+     */
+    private void releaseResources() {
+        releaseThreadedRenderer();
+        if (mAttachedCallbacksToRootViewImpl) {
+            ViewRootImpl.removeWindowCallbacks(this);
+            mAttachedCallbacksToRootViewImpl = false;
+        }
+    }
+
+    /**
+     * The thread which draws the chrome while we are resizing.
+     * It starts with the creation and it ends once someone calls destroy().
+     * Any size changes can be passed by a call to setTargetRect will passed to the thread and
+     * executed via the Choreographer.
+     */
+    private class ResizeFrameThread extends Thread implements Choreographer.FrameCallback {
+        // This is containing the last requested size by a resize command. Note that this size might
+        // or might not have been applied to the output already.
+        private final Rect mTargetRect = new Rect();
+
+        // The render nodes for the multi threaded renderer.
+        private ThreadedRenderer mRenderer;
+        private RenderNode mFrameNode;
+        private RenderNode mBackdropNode;
+
+        private final Rect mOldTargetRect = new Rect();
+        private final Rect mNewTargetRect = new Rect();
+        private Choreographer mChoreographer;
+
+        // Cached size values from the last render for the case that the view hierarchy is gone
+        // during a configuration change.
+        private int mLastContentWidth;
+        private int mLastContentHeight;
+        private int mLastCaptionHeight;
+        private int mLastXOffset;
+        private int mLastYOffset;
+
+        ResizeFrameThread(ThreadedRenderer renderer, Rect initialBounds) {
+            mRenderer = renderer;
+
+            // Create the render nodes for our frame and backdrop which can be resized independently
+            // from the content.
+            mFrameNode = RenderNode.create("FrameNode", null);
+            mBackdropNode = RenderNode.create("BackdropNode", null);
+
+            mRenderer.addRenderNode(mFrameNode, false);
+            mRenderer.addRenderNode(mBackdropNode, true);
+
+            // Set the initial bounds and draw once so that we do not get a broken frame.
+            mTargetRect.set(initialBounds);
+            changeWindowSize(initialBounds);
+
+            // Kick off our draw thread.
+            start();
+        }
+
+        /**
+         * Call this function asynchronously when the window size has been changed. The change will
+         * be picked up once per frame and the frame will be re-rendered accordingly.
+         * @param newTargetBounds The new target bounds.
+         */
+        public void setTargetRect(Rect newTargetBounds) {
+            synchronized (this) {
+                mTargetRect.set(newTargetBounds);
+                // Notify of a bounds change.
+                pingRenderLocked();
+            }
+        }
+
+        /**
+         * The window got replaced due to a configuration change.
+         */
+        public void onConfigurationChange() {
+            if (mRenderer != null) {
+                // Enforce a window redraw.
+                mOldTargetRect.set(0, 0, 0, 0);
+                pingRenderLocked();
+            }
+        }
+
+        /**
+         * All resources of the renderer will be released. This function can be called from the
+         * the UI thread as well as the renderer thread.
+         */
+        public void releaseRenderer() {
+            synchronized (this) {
+                if (mRenderer != null) {
+                    // Invalidate the current content bounds.
+                    mRenderer.setContentDrawBounds(0, 0, 0, 0);
+
+                    // Remove the render nodes again (see comment above - better to do that only once).
+                    mRenderer.removeRenderNode(mFrameNode);
+                    mRenderer.removeRenderNode(mBackdropNode);
+
+                    mRenderer = null;
+
+                    // Exit the renderer loop.
+                    pingRenderLocked();
+                }
+            }
+        }
+
+        @Override
+        public void run() {
+            try {
+                Looper.prepare();
+                mChoreographer = Choreographer.getInstance();
+                Looper.loop();
+            } finally {
+                releaseRenderer();
+            }
+            synchronized (this) {
+                // Make sure no more messages are being sent.
+                mChoreographer = null;
+            }
+        }
+
+        /**
+         * The implementation of the FrameCallback.
+         * @param frameTimeNanos The time in nanoseconds when the frame started being rendered,
+         * in the {@link System#nanoTime()} timebase.  Divide this value by {@code 1000000}
+         */
+        @Override
+        public void doFrame(long frameTimeNanos) {
+            if (mRenderer == null) {
+                // Tell the looper to stop. We are done.
+                Looper.myLooper().quit();
+                return;
+            }
+            // Prevent someone from changing this while we are copying.
+            synchronized (this) {
+                mNewTargetRect.set(mTargetRect);
+            }
+            if (!mNewTargetRect.equals(mOldTargetRect)) {
+                mOldTargetRect.set(mNewTargetRect);
+                changeWindowSize(mNewTargetRect);
+            }
+        }
+
+        /**
+         * Resizing the frame to fit the new window size.
+         * @param newBounds The window bounds which needs to be drawn.
+         */
+        private void changeWindowSize(Rect newBounds) {
+            long startTime = System.currentTimeMillis();
+
+            // While a configuration change is taking place the view hierarchy might become
+            // inaccessible. For that case we remember the previous metrics to avoid flashes.
+            View caption = getChildAt(0);
+            View content = getChildAt(1);
+            if (caption != null && content != null) {
+                int captionHeight = caption.getHeight();
+                int contentWidth = content.getWidth();
+                int contentHeight = content.getHeight();
+                // Get the draw position within our surface (shadow offsets).
+                int[] surfaceOrigin = new int[2];
+                surfaceOrigin[0] = 0;
+                surfaceOrigin[1] = 0;
+                getLocationInSurface(surfaceOrigin);
+                // Only update if a layout has already be performed (which might not be after a
+                // relayout. Otherwise use the previous values for the content.
+                if (captionHeight != 0 && contentWidth != 0 && contentHeight != 0) {
+                    mLastCaptionHeight = captionHeight;
+                    mLastXOffset = surfaceOrigin[0];
+                    mLastYOffset = surfaceOrigin[1];
+                    mLastContentWidth = contentWidth;
+                    mLastContentHeight = contentHeight;
+                }
+            }
+
+            // Since the surface is spanning the entire screen, we have to add the start offset of
+            // the bounds to get to the surface location.
+            final int left = mLastXOffset + newBounds.left;
+            final int top = mLastYOffset + newBounds.top;
+            final int width = newBounds.width();
+            final int height = newBounds.height();
+
+            // Produce the draw calls.
+            // TODO(skuhne): Create a separate caption view which draws this. If the shadow should
+            // be resized while the window resizes, this hierarchy needs to have the elevation.
+            // That said - it is probably no good idea to draw the shadow every time since it costs
+            // a considerable time which we should rather spend for resizing the content and it does
+            // barely show while the entire screen is moving.
+            mFrameNode.setLeftTopRightBottom(left, top, left + width, top + mLastCaptionHeight);
+            DisplayListCanvas canvas = mFrameNode.start(width, height);
+            canvas.drawColor(Color.BLACK);
+            mFrameNode.end(canvas);
+
+            mBackdropNode.setLeftTopRightBottom(left, top + mLastCaptionHeight, left + width,
+                    top + height);
+
+            // The backdrop: clear everything with the background. Clipping is done elsewhere.
+            canvas = mBackdropNode.start(width, height - mLastCaptionHeight);
+            // TODO(skuhne): mOwner.getDecorView().mBackgroundFallback.draw(..) - or similar.
+            // Note: This might not work (calculator for example uses a transparent background).
+            canvas.drawColor(0xff808080);
+            mBackdropNode.end(canvas);
+
+            // The current content buffer is drawn here.
+            mRenderer.setContentDrawBounds(
+                    mLastXOffset,
+                    mLastYOffset + mLastCaptionHeight,
+                    mLastXOffset + mLastContentWidth,
+                    mLastYOffset + mLastCaptionHeight + mLastContentHeight);
+
+            // We need to render both rendered nodes explicitly.
+            mRenderer.drawRenderNode(mFrameNode);
+            mRenderer.drawRenderNode(mBackdropNode);
+        }
+
+        /**
+         * Sends a message to the renderer to wake up and perform the next action which can be
+         * either the next rendering or the self destruction if mRenderer is null.
+         * Note: This call must be synchronized.
+         */
+        private void pingRenderLocked() {
+            if (mChoreographer != null) {
+                mChoreographer.postFrameCallback(this);
+            }
+        }
+    }
 }
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 223dae0..314e4b6 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -66,10 +66,6 @@
 static jclass   gFontMetricsInt_class;
 static JMetricsID gFontMetricsInt_fieldID;
 
-static jclass   gPaint_class;
-static jfieldID gPaint_nativeInstanceID;
-static jfieldID gPaint_nativeTypefaceID;
-
 static void defaultSettingsForAndroid(Paint* paint) {
     // GlyphID encoding is required because we are using Harfbuzz shaping
     paint->setTextEncoding(Paint::kGlyphID_TextEncoding);
@@ -82,37 +78,17 @@
 
 static thread_local LocaleCacheEntry sSingleEntryLocaleCache;
 
-class PaintGlue {
-public:
+namespace PaintGlue {
     enum MoveOpt {
         AFTER, AT_OR_AFTER, BEFORE, AT_OR_BEFORE, AT
     };
 
-    static Paint* getNativePaint(JNIEnv* env, jobject paint) {
-        SkASSERT(env);
-        SkASSERT(paint);
-        SkASSERT(env->IsInstanceOf(paint, gPaint_class));
-        jlong paintHandle = env->GetLongField(paint, gPaint_nativeInstanceID);
-        android::Paint* p = reinterpret_cast<android::Paint*>(paintHandle);
-        SkASSERT(p);
-        return p;
-    }
-
-    static TypefaceImpl* getNativeTypeface(JNIEnv* env, jobject paint) {
-        SkASSERT(env);
-        SkASSERT(paint);
-        SkASSERT(env->IsInstanceOf(paint, gPaint_class));
-        jlong typefaceHandle = env->GetLongField(paint, gPaint_nativeTypefaceID);
-        android::TypefaceImpl* p = reinterpret_cast<android::TypefaceImpl*>(typefaceHandle);
-        return p;
-    }
-
     static void finalizer(JNIEnv* env, jobject clazz, jlong objHandle) {
         Paint* obj = reinterpret_cast<Paint*>(objHandle);
         delete obj;
     }
 
-    static jlong init(JNIEnv* env, jobject clazz) {
+    static jlong init(JNIEnv* env, jobject) {
         static_assert(1 <<  0 == SkPaint::kAntiAlias_Flag,          "paint_flags_mismatch");
         static_assert(1 <<  2 == SkPaint::kDither_Flag,             "paint_flags_mismatch");
         static_assert(1 <<  3 == SkPaint::kUnderlineText_Flag,      "paint_flags_mismatch");
@@ -149,9 +125,8 @@
     // Equivalent to the Java Paint's FILTER_BITMAP_FLAG.
     static const uint32_t sFilterBitmapFlag = 0x02;
 
-    static jint getFlags(JNIEnv* env, jobject paint) {
-        NPE_CHECK_RETURN_ZERO(env, paint);
-        Paint* nativePaint = getNativePaint(env, paint);
+    static jint getFlags(JNIEnv* env, jobject, jlong paintHandle) {
+        Paint* nativePaint = reinterpret_cast<Paint*>(paintHandle);
         uint32_t result = nativePaint->getFlags();
         result &= ~sFilterBitmapFlag; // Filtering no longer stored in this bit. Mask away.
         if (nativePaint->getFilterQuality() != kNone_SkFilterQuality) {
@@ -160,9 +135,8 @@
         return static_cast<jint>(result);
     }
 
-    static void setFlags(JNIEnv* env, jobject paint, jint flags) {
-        NPE_CHECK_RETURN_VOID(env, paint);
-        Paint* nativePaint = getNativePaint(env, paint);
+    static void setFlags(JNIEnv* env, jobject, jlong paintHandle, jint flags) {
+        Paint* nativePaint = reinterpret_cast<Paint*>(paintHandle);
         // Instead of modifying 0x02, change the filter level.
         nativePaint->setFilterQuality(flags & sFilterBitmapFlag
                 ? kLow_SkFilterQuality
@@ -175,57 +149,47 @@
         nativePaint->setFlags(flags);
     }
 
-    static jint getHinting(JNIEnv* env, jobject paint) {
-        NPE_CHECK_RETURN_ZERO(env, paint);
-        return getNativePaint(env, paint)->getHinting()
+    static jint getHinting(JNIEnv* env, jobject, jlong paintHandle) {
+        return reinterpret_cast<Paint*>(paintHandle)->getHinting()
                 == Paint::kNo_Hinting ? 0 : 1;
     }
 
-    static void setHinting(JNIEnv* env, jobject paint, jint mode) {
-        NPE_CHECK_RETURN_VOID(env, paint);
-        getNativePaint(env, paint)->setHinting(
+    static void setHinting(JNIEnv* env, jobject, jlong paintHandle, jint mode) {
+        reinterpret_cast<Paint*>(paintHandle)->setHinting(
                 mode == 0 ? Paint::kNo_Hinting : Paint::kNormal_Hinting);
     }
 
-    static void setAntiAlias(JNIEnv* env, jobject paint, jboolean aa) {
-        NPE_CHECK_RETURN_VOID(env, paint);
-        getNativePaint(env, paint)->setAntiAlias(aa);
+    static void setAntiAlias(JNIEnv* env, jobject, jlong paintHandle, jboolean aa) {
+        reinterpret_cast<Paint*>(paintHandle)->setAntiAlias(aa);
     }
 
-    static void setLinearText(JNIEnv* env, jobject paint, jboolean linearText) {
-        NPE_CHECK_RETURN_VOID(env, paint);
-        getNativePaint(env, paint)->setLinearText(linearText);
+    static void setLinearText(JNIEnv* env, jobject, jlong paintHandle, jboolean linearText) {
+        reinterpret_cast<Paint*>(paintHandle)->setLinearText(linearText);
     }
 
-    static void setSubpixelText(JNIEnv* env, jobject paint, jboolean subpixelText) {
-        NPE_CHECK_RETURN_VOID(env, paint);
-        getNativePaint(env, paint)->setSubpixelText(subpixelText);
+    static void setSubpixelText(JNIEnv* env, jobject, jlong paintHandle, jboolean subpixelText) {
+        reinterpret_cast<Paint*>(paintHandle)->setSubpixelText(subpixelText);
     }
 
-    static void setUnderlineText(JNIEnv* env, jobject paint, jboolean underlineText) {
-        NPE_CHECK_RETURN_VOID(env, paint);
-        getNativePaint(env, paint)->setUnderlineText(underlineText);
+    static void setUnderlineText(JNIEnv* env, jobject, jlong paintHandle, jboolean underlineText) {
+        reinterpret_cast<Paint*>(paintHandle)->setUnderlineText(underlineText);
     }
 
-    static void setStrikeThruText(JNIEnv* env, jobject paint, jboolean strikeThruText) {
-        NPE_CHECK_RETURN_VOID(env, paint);
-        getNativePaint(env, paint)->setStrikeThruText(strikeThruText);
+    static void setStrikeThruText(JNIEnv* env, jobject, jlong paintHandle, jboolean strikeThruText) {
+        reinterpret_cast<Paint*>(paintHandle)->setStrikeThruText(strikeThruText);
     }
 
-    static void setFakeBoldText(JNIEnv* env, jobject paint, jboolean fakeBoldText) {
-        NPE_CHECK_RETURN_VOID(env, paint);
-        getNativePaint(env, paint)->setFakeBoldText(fakeBoldText);
+    static void setFakeBoldText(JNIEnv* env, jobject, jlong paintHandle, jboolean fakeBoldText) {
+        reinterpret_cast<Paint*>(paintHandle)->setFakeBoldText(fakeBoldText);
     }
 
-    static void setFilterBitmap(JNIEnv* env, jobject paint, jboolean filterBitmap) {
-        NPE_CHECK_RETURN_VOID(env, paint);
-        getNativePaint(env, paint)->setFilterQuality(
+    static void setFilterBitmap(JNIEnv* env, jobject, jlong paintHandle, jboolean filterBitmap) {
+        reinterpret_cast<Paint*>(paintHandle)->setFilterQuality(
                 filterBitmap ? kLow_SkFilterQuality : kNone_SkFilterQuality);
     }
 
-    static void setDither(JNIEnv* env, jobject paint, jboolean dither) {
-        NPE_CHECK_RETURN_VOID(env, paint);
-        getNativePaint(env, paint)->setDither(dither);
+    static void setDither(JNIEnv* env, jobject, jlong paintHandle, jboolean dither) {
+        reinterpret_cast<Paint*>(paintHandle)->setDither(dither);
     }
 
     static jint getStyle(JNIEnv* env, jobject clazz,jlong objHandle) {
@@ -239,48 +203,40 @@
         obj->setStyle(style);
     }
 
-    static jint getColor(JNIEnv* env, jobject paint) {
-        NPE_CHECK_RETURN_ZERO(env, paint);
+    static jint getColor(JNIEnv* env, jobject, jlong paintHandle) {
         int color;
-        color = getNativePaint(env, paint)->getColor();
+        color = reinterpret_cast<Paint*>(paintHandle)->getColor();
         return static_cast<jint>(color);
     }
 
-    static jint getAlpha(JNIEnv* env, jobject paint) {
-        NPE_CHECK_RETURN_ZERO(env, paint);
+    static jint getAlpha(JNIEnv* env, jobject, jlong paintHandle) {
         int alpha;
-        alpha = getNativePaint(env, paint)->getAlpha();
+        alpha = reinterpret_cast<Paint*>(paintHandle)->getAlpha();
         return static_cast<jint>(alpha);
     }
 
-    static void setColor(JNIEnv* env, jobject paint, jint color) {
-        NPE_CHECK_RETURN_VOID(env, paint);
-        getNativePaint(env, paint)->setColor(color);
+    static void setColor(JNIEnv* env, jobject, jlong paintHandle, jint color) {
+        reinterpret_cast<Paint*>(paintHandle)->setColor(color);
     }
 
-    static void setAlpha(JNIEnv* env, jobject paint, jint a) {
-        NPE_CHECK_RETURN_VOID(env, paint);
-        getNativePaint(env, paint)->setAlpha(a);
+    static void setAlpha(JNIEnv* env, jobject, jlong paintHandle, jint a) {
+        reinterpret_cast<Paint*>(paintHandle)->setAlpha(a);
     }
 
-    static jfloat getStrokeWidth(JNIEnv* env, jobject paint) {
-        NPE_CHECK_RETURN_ZERO(env, paint);
-        return SkScalarToFloat(getNativePaint(env, paint)->getStrokeWidth());
+    static jfloat getStrokeWidth(JNIEnv* env, jobject, jlong paintHandle) {
+        return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getStrokeWidth());
     }
 
-    static void setStrokeWidth(JNIEnv* env, jobject paint, jfloat width) {
-        NPE_CHECK_RETURN_VOID(env, paint);
-        getNativePaint(env, paint)->setStrokeWidth(width);
+    static void setStrokeWidth(JNIEnv* env, jobject, jlong paintHandle, jfloat width) {
+        reinterpret_cast<Paint*>(paintHandle)->setStrokeWidth(width);
     }
 
-    static jfloat getStrokeMiter(JNIEnv* env, jobject paint) {
-        NPE_CHECK_RETURN_ZERO(env, paint);
-        return SkScalarToFloat(getNativePaint(env, paint)->getStrokeMiter());
+    static jfloat getStrokeMiter(JNIEnv* env, jobject, jlong paintHandle) {
+        return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getStrokeMiter());
     }
 
-    static void setStrokeMiter(JNIEnv* env, jobject paint, jfloat miter) {
-        NPE_CHECK_RETURN_VOID(env, paint);
-        getNativePaint(env, paint)->setStrokeMiter(miter);
+    static void setStrokeMiter(JNIEnv* env, jobject, jlong paintHandle, jfloat miter) {
+        reinterpret_cast<Paint*>(paintHandle)->setStrokeMiter(miter);
     }
 
     static jint getStrokeCap(JNIEnv* env, jobject clazz, jlong objHandle) {
@@ -417,46 +373,38 @@
         obj->setTextLocale(sSingleEntryLocaleCache.languageTag);
     }
 
-    static jboolean isElegantTextHeight(JNIEnv* env, jobject paint) {
-        NPE_CHECK_RETURN_ZERO(env, paint);
-        Paint* obj = getNativePaint(env, paint);
+    static jboolean isElegantTextHeight(JNIEnv* env, jobject, jlong paintHandle) {
+        Paint* obj = reinterpret_cast<Paint*>(paintHandle);
         return obj->getFontVariant() == VARIANT_ELEGANT;
     }
 
-    static void setElegantTextHeight(JNIEnv* env, jobject paint, jboolean aa) {
-        NPE_CHECK_RETURN_VOID(env, paint);
-        Paint* obj = getNativePaint(env, paint);
+    static void setElegantTextHeight(JNIEnv* env, jobject, jlong paintHandle, jboolean aa) {
+        Paint* obj = reinterpret_cast<Paint*>(paintHandle);
         obj->setFontVariant(aa ? VARIANT_ELEGANT : VARIANT_DEFAULT);
     }
 
-    static jfloat getTextSize(JNIEnv* env, jobject paint) {
-        NPE_CHECK_RETURN_ZERO(env, paint);
-        return SkScalarToFloat(getNativePaint(env, paint)->getTextSize());
+    static jfloat getTextSize(JNIEnv* env, jobject, jlong paintHandle) {
+        return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getTextSize());
     }
 
-    static void setTextSize(JNIEnv* env, jobject paint, jfloat textSize) {
-        NPE_CHECK_RETURN_VOID(env, paint);
-        getNativePaint(env, paint)->setTextSize(textSize);
+    static void setTextSize(JNIEnv* env, jobject, jlong paintHandle, jfloat textSize) {
+        reinterpret_cast<Paint*>(paintHandle)->setTextSize(textSize);
     }
 
-    static jfloat getTextScaleX(JNIEnv* env, jobject paint) {
-        NPE_CHECK_RETURN_ZERO(env, paint);
-        return SkScalarToFloat(getNativePaint(env, paint)->getTextScaleX());
+    static jfloat getTextScaleX(JNIEnv* env, jobject, jlong paintHandle) {
+        return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getTextScaleX());
     }
 
-    static void setTextScaleX(JNIEnv* env, jobject paint, jfloat scaleX) {
-        NPE_CHECK_RETURN_VOID(env, paint);
-        getNativePaint(env, paint)->setTextScaleX(scaleX);
+    static void setTextScaleX(JNIEnv* env, jobject, jlong paintHandle, jfloat scaleX) {
+        reinterpret_cast<Paint*>(paintHandle)->setTextScaleX(scaleX);
     }
 
-    static jfloat getTextSkewX(JNIEnv* env, jobject paint) {
-        NPE_CHECK_RETURN_ZERO(env, paint);
-        return SkScalarToFloat(getNativePaint(env, paint)->getTextSkewX());
+    static jfloat getTextSkewX(JNIEnv* env, jobject, jlong paintHandle) {
+        return SkScalarToFloat(reinterpret_cast<Paint*>(paintHandle)->getTextSkewX());
     }
 
-    static void setTextSkewX(JNIEnv* env, jobject paint, jfloat skewX) {
-        NPE_CHECK_RETURN_VOID(env, paint);
-        getNativePaint(env, paint)->setTextSkewX(skewX);
+    static void setTextSkewX(JNIEnv* env, jobject, jlong paintHandle, jfloat skewX) {
+        reinterpret_cast<Paint*>(paintHandle)->setTextSkewX(skewX);
     }
 
     static jfloat getLetterSpacing(JNIEnv* env, jobject clazz, jlong paintHandle) {
@@ -489,14 +437,15 @@
         paint->setHyphenEdit((uint32_t)hyphen);
     }
 
-    static SkScalar getMetricsInternal(JNIEnv* env, jobject jpaint, Paint::FontMetrics *metrics) {
+    static SkScalar getMetricsInternal(jlong paintHandle, jlong typefaceHandle,
+            Paint::FontMetrics *metrics) {
         const int kElegantTop = 2500;
         const int kElegantBottom = -1000;
         const int kElegantAscent = 1900;
         const int kElegantDescent = -500;
         const int kElegantLeading = 0;
-        Paint* paint = getNativePaint(env, jpaint);
-        TypefaceImpl* typeface = getNativeTypeface(env, jpaint);
+        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
+        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
         typeface = TypefaceImpl_resolveDefault(typeface);
         FakedFont baseFont = typeface->fFontCollection->baseFontFaked(typeface->fStyle);
         float saveSkewX = paint->getTextSkewX();
@@ -520,24 +469,22 @@
         return spacing;
     }
 
-    static jfloat ascent(JNIEnv* env, jobject paint) {
-        NPE_CHECK_RETURN_ZERO(env, paint);
+    static jfloat ascent(JNIEnv* env, jobject, jlong paintHandle, jlong typefaceHandle) {
         Paint::FontMetrics metrics;
-        getMetricsInternal(env, paint, &metrics);
+        getMetricsInternal(paintHandle, typefaceHandle, &metrics);
         return SkScalarToFloat(metrics.fAscent);
     }
 
-    static jfloat descent(JNIEnv* env, jobject paint) {
-        NPE_CHECK_RETURN_ZERO(env, paint);
+    static jfloat descent(JNIEnv* env, jobject, jlong paintHandle, jlong typefaceHandle) {
         Paint::FontMetrics metrics;
-        getMetricsInternal(env, paint, &metrics);
+        getMetricsInternal(paintHandle, typefaceHandle, &metrics);
         return SkScalarToFloat(metrics.fDescent);
     }
 
-    static jfloat getFontMetrics(JNIEnv* env, jobject paint, jobject metricsObj) {
-        NPE_CHECK_RETURN_ZERO(env, paint);
+    static jfloat getFontMetrics(JNIEnv* env, jobject, jlong paintHandle,
+            jlong typefaceHandle, jobject metricsObj) {
         Paint::FontMetrics metrics;
-        SkScalar spacing = getMetricsInternal(env, paint, &metrics);
+        SkScalar spacing = getMetricsInternal(paintHandle, typefaceHandle, &metrics);
 
         if (metricsObj) {
             SkASSERT(env->IsInstanceOf(metricsObj, gFontMetrics_class));
@@ -550,11 +497,11 @@
         return SkScalarToFloat(spacing);
     }
 
-    static jint getFontMetricsInt(JNIEnv* env, jobject paint, jobject metricsObj) {
-        NPE_CHECK_RETURN_ZERO(env, paint);
+    static jint getFontMetricsInt(JNIEnv* env, jobject, jlong paintHandle,
+            jlong typefaceHandle, jobject metricsObj) {
         Paint::FontMetrics metrics;
 
-        getMetricsInternal(env, paint, &metrics);
+        getMetricsInternal(paintHandle, typefaceHandle, &metrics);
         int ascent = SkScalarRoundToInt(metrics.fAscent);
         int descent = SkScalarRoundToInt(metrics.fDescent);
         int leading = SkScalarRoundToInt(metrics.fLeading);
@@ -573,7 +520,6 @@
     static jfloat doTextAdvances(JNIEnv *env, Paint *paint, TypefaceImpl* typeface,
             const jchar *text, jint start, jint count, jint contextCount, jint bidiFlags,
             jfloatArray advances, jint advancesIndex) {
-        NPE_CHECK_RETURN_ZERO(env, paint);
         NPE_CHECK_RETURN_ZERO(env, text);
 
         if ((start | count | contextCount | advancesIndex) < 0 || contextCount < count) {
@@ -841,7 +787,7 @@
 
     static void getStringBounds(JNIEnv* env, jobject, jlong paintHandle, jlong typefaceHandle,
                                 jstring text, jint start, jint end, jint bidiFlags, jobject bounds) {
-        const Paint* paint = reinterpret_cast<Paint*>(paintHandle);;
+        const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
         TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
         const jchar* textArray = env->GetStringChars(text, NULL);
         doTextBounds(env, textArray + start, end - start, bounds, *paint, typeface, bidiFlags);
@@ -961,97 +907,97 @@
         return result;
     }
 
-};
+}; // namespace PaintGlue
 
 static const JNINativeMethod methods[] = {
-    {"finalizer", "(J)V", (void*) PaintGlue::finalizer},
-    {"native_init","()J", (void*) PaintGlue::init},
-    {"native_initWithPaint","(J)J", (void*) PaintGlue::initWithPaint},
+    {"nFinalizer", "(J)V", (void*) PaintGlue::finalizer},
+    {"nInit","()J", (void*) PaintGlue::init},
+    {"nInitWithPaint","(J)J", (void*) PaintGlue::initWithPaint},
 
-    {"native_reset","!(J)V", (void*) PaintGlue::reset},
-    {"native_set","!(JJ)V", (void*) PaintGlue::assign},
-    {"getFlags","!()I", (void*) PaintGlue::getFlags},
-    {"setFlags","!(I)V", (void*) PaintGlue::setFlags},
-    {"getHinting","!()I", (void*) PaintGlue::getHinting},
-    {"setHinting","!(I)V", (void*) PaintGlue::setHinting},
-    {"setAntiAlias","!(Z)V", (void*) PaintGlue::setAntiAlias},
-    {"setSubpixelText","!(Z)V", (void*) PaintGlue::setSubpixelText},
-    {"setLinearText","!(Z)V", (void*) PaintGlue::setLinearText},
-    {"setUnderlineText","!(Z)V", (void*) PaintGlue::setUnderlineText},
-    {"setStrikeThruText","!(Z)V", (void*) PaintGlue::setStrikeThruText},
-    {"setFakeBoldText","!(Z)V", (void*) PaintGlue::setFakeBoldText},
-    {"setFilterBitmap","!(Z)V", (void*) PaintGlue::setFilterBitmap},
-    {"setDither","!(Z)V", (void*) PaintGlue::setDither},
-    {"native_getStyle","!(J)I", (void*) PaintGlue::getStyle},
-    {"native_setStyle","!(JI)V", (void*) PaintGlue::setStyle},
-    {"getColor","!()I", (void*) PaintGlue::getColor},
-    {"setColor","!(I)V", (void*) PaintGlue::setColor},
-    {"getAlpha","!()I", (void*) PaintGlue::getAlpha},
-    {"setAlpha","!(I)V", (void*) PaintGlue::setAlpha},
-    {"getStrokeWidth","!()F", (void*) PaintGlue::getStrokeWidth},
-    {"setStrokeWidth","!(F)V", (void*) PaintGlue::setStrokeWidth},
-    {"getStrokeMiter","!()F", (void*) PaintGlue::getStrokeMiter},
-    {"setStrokeMiter","!(F)V", (void*) PaintGlue::setStrokeMiter},
-    {"native_getStrokeCap","!(J)I", (void*) PaintGlue::getStrokeCap},
-    {"native_setStrokeCap","!(JI)V", (void*) PaintGlue::setStrokeCap},
-    {"native_getStrokeJoin","!(J)I", (void*) PaintGlue::getStrokeJoin},
-    {"native_setStrokeJoin","!(JI)V", (void*) PaintGlue::setStrokeJoin},
-    {"native_getFillPath","!(JJJ)Z", (void*) PaintGlue::getFillPath},
-    {"native_setShader","!(JJ)J", (void*) PaintGlue::setShader},
-    {"native_setColorFilter","!(JJ)J", (void*) PaintGlue::setColorFilter},
-    {"native_setXfermode","!(JJ)J", (void*) PaintGlue::setXfermode},
-    {"native_setPathEffect","!(JJ)J", (void*) PaintGlue::setPathEffect},
-    {"native_setMaskFilter","!(JJ)J", (void*) PaintGlue::setMaskFilter},
-    {"native_setTypeface","!(JJ)J", (void*) PaintGlue::setTypeface},
-    {"native_setRasterizer","!(JJ)J", (void*) PaintGlue::setRasterizer},
-    {"native_getTextAlign","!(J)I", (void*) PaintGlue::getTextAlign},
-    {"native_setTextAlign","!(JI)V", (void*) PaintGlue::setTextAlign},
-    {"native_setTextLocale","!(JLjava/lang/String;)V", (void*) PaintGlue::setTextLocale},
-    {"isElegantTextHeight","!()Z", (void*) PaintGlue::isElegantTextHeight},
-    {"setElegantTextHeight","!(Z)V", (void*) PaintGlue::setElegantTextHeight},
-    {"getTextSize","!()F", (void*) PaintGlue::getTextSize},
-    {"setTextSize","!(F)V", (void*) PaintGlue::setTextSize},
-    {"getTextScaleX","!()F", (void*) PaintGlue::getTextScaleX},
-    {"setTextScaleX","!(F)V", (void*) PaintGlue::setTextScaleX},
-    {"getTextSkewX","!()F", (void*) PaintGlue::getTextSkewX},
-    {"setTextSkewX","!(F)V", (void*) PaintGlue::setTextSkewX},
-    {"native_getLetterSpacing","!(J)F", (void*) PaintGlue::getLetterSpacing},
-    {"native_setLetterSpacing","!(JF)V", (void*) PaintGlue::setLetterSpacing},
-    {"native_setFontFeatureSettings","(JLjava/lang/String;)V",
+    {"nReset","!(J)V", (void*) PaintGlue::reset},
+    {"nSet","!(JJ)V", (void*) PaintGlue::assign},
+    {"nGetFlags","!(J)I", (void*) PaintGlue::getFlags},
+    {"nSetFlags","!(JI)V", (void*) PaintGlue::setFlags},
+    {"nGetHinting","!(J)I", (void*) PaintGlue::getHinting},
+    {"nSetHinting","!(JI)V", (void*) PaintGlue::setHinting},
+    {"nSetAntiAlias","!(JZ)V", (void*) PaintGlue::setAntiAlias},
+    {"nSetSubpixelText","!(JZ)V", (void*) PaintGlue::setSubpixelText},
+    {"nSetLinearText","!(JZ)V", (void*) PaintGlue::setLinearText},
+    {"nSetUnderlineText","!(JZ)V", (void*) PaintGlue::setUnderlineText},
+    {"nSetStrikeThruText","!(JZ)V", (void*) PaintGlue::setStrikeThruText},
+    {"nSetFakeBoldText","!(JZ)V", (void*) PaintGlue::setFakeBoldText},
+    {"nSetFilterBitmap","!(JZ)V", (void*) PaintGlue::setFilterBitmap},
+    {"nSetDither","!(JZ)V", (void*) PaintGlue::setDither},
+    {"nGetStyle","!(J)I", (void*) PaintGlue::getStyle},
+    {"nSetStyle","!(JI)V", (void*) PaintGlue::setStyle},
+    {"nGetColor","!(J)I", (void*) PaintGlue::getColor},
+    {"nSetColor","!(JI)V", (void*) PaintGlue::setColor},
+    {"nGetAlpha","!(J)I", (void*) PaintGlue::getAlpha},
+    {"nSetAlpha","!(JI)V", (void*) PaintGlue::setAlpha},
+    {"nGetStrokeWidth","!(J)F", (void*) PaintGlue::getStrokeWidth},
+    {"nSetStrokeWidth","!(JF)V", (void*) PaintGlue::setStrokeWidth},
+    {"nGetStrokeMiter","!(J)F", (void*) PaintGlue::getStrokeMiter},
+    {"nSetStrokeMiter","!(JF)V", (void*) PaintGlue::setStrokeMiter},
+    {"nGetStrokeCap","!(J)I", (void*) PaintGlue::getStrokeCap},
+    {"nSetStrokeCap","!(JI)V", (void*) PaintGlue::setStrokeCap},
+    {"nGetStrokeJoin","!(J)I", (void*) PaintGlue::getStrokeJoin},
+    {"nSetStrokeJoin","!(JI)V", (void*) PaintGlue::setStrokeJoin},
+    {"nGetFillPath","!(JJJ)Z", (void*) PaintGlue::getFillPath},
+    {"nSetShader","!(JJ)J", (void*) PaintGlue::setShader},
+    {"nSetColorFilter","!(JJ)J", (void*) PaintGlue::setColorFilter},
+    {"nSetXfermode","!(JJ)J", (void*) PaintGlue::setXfermode},
+    {"nSetPathEffect","!(JJ)J", (void*) PaintGlue::setPathEffect},
+    {"nSetMaskFilter","!(JJ)J", (void*) PaintGlue::setMaskFilter},
+    {"nSetTypeface","!(JJ)J", (void*) PaintGlue::setTypeface},
+    {"nSetRasterizer","!(JJ)J", (void*) PaintGlue::setRasterizer},
+    {"nGetTextAlign","!(J)I", (void*) PaintGlue::getTextAlign},
+    {"nSetTextAlign","!(JI)V", (void*) PaintGlue::setTextAlign},
+    {"nSetTextLocale","!(JLjava/lang/String;)V", (void*) PaintGlue::setTextLocale},
+    {"nIsElegantTextHeight","!(J)Z", (void*) PaintGlue::isElegantTextHeight},
+    {"nSetElegantTextHeight","!(JZ)V", (void*) PaintGlue::setElegantTextHeight},
+    {"nGetTextSize","!(J)F", (void*) PaintGlue::getTextSize},
+    {"nSetTextSize","!(JF)V", (void*) PaintGlue::setTextSize},
+    {"nGetTextScaleX","!(J)F", (void*) PaintGlue::getTextScaleX},
+    {"nSetTextScaleX","!(JF)V", (void*) PaintGlue::setTextScaleX},
+    {"nGetTextSkewX","!(J)F", (void*) PaintGlue::getTextSkewX},
+    {"nSetTextSkewX","!(JF)V", (void*) PaintGlue::setTextSkewX},
+    {"nGetLetterSpacing","!(J)F", (void*) PaintGlue::getLetterSpacing},
+    {"nSetLetterSpacing","!(JF)V", (void*) PaintGlue::setLetterSpacing},
+    {"nSetFontFeatureSettings","(JLjava/lang/String;)V",
             (void*) PaintGlue::setFontFeatureSettings},
-    {"native_getHyphenEdit", "!(J)I", (void*) PaintGlue::getHyphenEdit},
-    {"native_setHyphenEdit", "!(JI)V", (void*) PaintGlue::setHyphenEdit},
-    {"ascent","!()F", (void*) PaintGlue::ascent},
-    {"descent","!()F", (void*) PaintGlue::descent},
+    {"nGetHyphenEdit", "!(J)I", (void*) PaintGlue::getHyphenEdit},
+    {"nSetHyphenEdit", "!(JI)V", (void*) PaintGlue::setHyphenEdit},
+    {"nAscent","!(JJ)F", (void*) PaintGlue::ascent},
+    {"nDescent","!(JJ)F", (void*) PaintGlue::descent},
 
-    {"getFontMetrics", "!(Landroid/graphics/Paint$FontMetrics;)F",
+    {"nGetFontMetrics", "!(JJLandroid/graphics/Paint$FontMetrics;)F",
             (void*)PaintGlue::getFontMetrics},
-    {"getFontMetricsInt", "!(Landroid/graphics/Paint$FontMetricsInt;)I",
+    {"nGetFontMetricsInt", "!(JJLandroid/graphics/Paint$FontMetricsInt;)I",
             (void*)PaintGlue::getFontMetricsInt},
 
-    {"native_breakText","(JJ[CIIFI[F)I", (void*) PaintGlue::breakTextC},
-    {"native_breakText","(JJLjava/lang/String;ZFI[F)I", (void*) PaintGlue::breakTextS},
-    {"native_getTextAdvances","(JJ[CIIIII[FI)F",
+    {"nBreakText","(JJ[CIIFI[F)I", (void*) PaintGlue::breakTextC},
+    {"nBreakText","(JJLjava/lang/String;ZFI[F)I", (void*) PaintGlue::breakTextS},
+    {"nGetTextAdvances","(JJ[CIIIII[FI)F",
             (void*) PaintGlue::getTextAdvances___CIIIII_FI},
-    {"native_getTextAdvances","(JJLjava/lang/String;IIIII[FI)F",
+    {"nGetTextAdvances","(JJLjava/lang/String;IIIII[FI)F",
             (void*) PaintGlue::getTextAdvances__StringIIIII_FI},
 
-    {"native_getTextRunCursor", "(J[CIIIII)I", (void*) PaintGlue::getTextRunCursor___C},
-    {"native_getTextRunCursor", "(JLjava/lang/String;IIIII)I",
+    {"nGetTextRunCursor", "(J[CIIIII)I", (void*) PaintGlue::getTextRunCursor___C},
+    {"nGetTextRunCursor", "(JLjava/lang/String;IIIII)I",
             (void*) PaintGlue::getTextRunCursor__String},
-    {"native_getTextPath", "(JJI[CIIFFJ)V", (void*) PaintGlue::getTextPath___C},
-    {"native_getTextPath", "(JJILjava/lang/String;IIFFJ)V", (void*) PaintGlue::getTextPath__String},
-    {"nativeGetStringBounds", "(JJLjava/lang/String;IIILandroid/graphics/Rect;)V",
+    {"nGetTextPath", "(JJI[CIIFFJ)V", (void*) PaintGlue::getTextPath___C},
+    {"nGetTextPath", "(JJILjava/lang/String;IIFFJ)V", (void*) PaintGlue::getTextPath__String},
+    {"nGetStringBounds", "(JJLjava/lang/String;IIILandroid/graphics/Rect;)V",
             (void*) PaintGlue::getStringBounds },
-    {"nativeGetCharArrayBounds", "(JJ[CIIILandroid/graphics/Rect;)V",
+    {"nGetCharArrayBounds", "(JJ[CIIILandroid/graphics/Rect;)V",
             (void*) PaintGlue::getCharArrayBounds },
-    {"native_hasGlyph", "(JJILjava/lang/String;)Z", (void*) PaintGlue::hasGlyph },
-    {"native_getRunAdvance", "(JJ[CIIIIZI)F", (void*) PaintGlue::getRunAdvance___CIIIIZI_F},
-    {"native_getOffsetForAdvance", "(JJ[CIIIIZF)I",
+    {"nHasGlyph", "(JJILjava/lang/String;)Z", (void*) PaintGlue::hasGlyph },
+    {"nGetRunAdvance", "(JJ[CIIIIZI)F", (void*) PaintGlue::getRunAdvance___CIIIIZI_F},
+    {"nGetOffsetForAdvance", "(JJ[CIIIIZF)I",
             (void*) PaintGlue::getOffsetForAdvance___CIIIIZF_I},
 
-    {"native_setShadowLayer", "!(JFFFI)V", (void*)PaintGlue::setShadowLayer},
-    {"native_hasShadowLayer", "!(J)Z", (void*)PaintGlue::hasShadowLayer}
+    {"nSetShadowLayer", "!(JFFFI)V", (void*)PaintGlue::setShadowLayer},
+    {"nHasShadowLayer", "!(J)Z", (void*)PaintGlue::hasShadowLayer}
 };
 
 int register_android_graphics_Paint(JNIEnv* env) {
@@ -1073,10 +1019,6 @@
     gFontMetricsInt_fieldID.bottom = GetFieldIDOrDie(env, gFontMetricsInt_class, "bottom", "I");
     gFontMetricsInt_fieldID.leading = GetFieldIDOrDie(env, gFontMetricsInt_class, "leading", "I");
 
-    gPaint_class = MakeGlobalRefOrDie(env, FindClassOrDie(env, "android/graphics/Paint"));
-    gPaint_nativeInstanceID = GetFieldIDOrDie(env, gPaint_class, "mNativePaint", "J");
-    gPaint_nativeTypefaceID = GetFieldIDOrDie(env, gPaint_class, "mNativeTypeface", "J");
-
     return RegisterMethodsOrDie(env, "android/graphics/Paint", methods, NELEM(methods));
 }
 
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index c79f833..17eb876 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -461,10 +461,10 @@
     proxy->drawRenderNode(renderNode);
 }
 
-static void android_view_ThreadedRenderer_setContentOverdrawProtectionBounds(JNIEnv* env,
+static void android_view_ThreadedRenderer_setContentDrawBounds(JNIEnv* env,
         jobject clazz, jlong proxyPtr, jint left, jint top, jint right, jint bottom) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
-    proxy->setContentOverdrawProtectionBounds(left, top, right, bottom);
+    proxy->setContentDrawBounds(left, top, right, bottom);
 }
 
 // ----------------------------------------------------------------------------
@@ -522,8 +522,7 @@
     { "nAddRenderNode", "(JJZ)V", (void*) android_view_ThreadedRenderer_addRenderNode},
     { "nRemoveRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_removeRenderNode},
     { "nDrawRenderNode", "(JJ)V", (void*) android_view_ThreadedRendererd_drawRenderNode},
-    { "nSetContentOverdrawProtectionBounds", "(JIIII)V",
-                (void*)android_view_ThreadedRenderer_setContentOverdrawProtectionBounds},
+    { "nSetContentDrawBounds", "(JIIII)V", (void*)android_view_ThreadedRenderer_setContentDrawBounds},
 };
 
 int register_android_view_ThreadedRenderer(JNIEnv* env) {
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 38a1693..58640eb 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -307,9 +307,10 @@
     <style name="TextAppearance.Material.Widget.PopupMenu"/>
     <style name="TextAppearance.Material.Widget.PopupMenu.Large" parent="TextAppearance.Material.Menu" />
     <style name="TextAppearance.Material.Widget.PopupMenu.Small" parent="TextAppearance.Material.Menu" />
-    <style name="TextAppearance.Material.Widget.PopupMenu.Header" parent="TextAppearance.Material.Subhead">
+    <style name="TextAppearance.Material.Widget.PopupMenu.Header">
         <item name="fontFamily">@string/font_family_title_material</item>
         <item name="textSize">@dimen/text_size_menu_header_material</item>
+        <item name="textColor">?attr/textColorSecondary</item>
     </style>
 
     <style name="TextAppearance.Material.Widget.DropDownHint" parent="TextAppearance.Material.Menu" />
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 58de87a..11b4a9e 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -430,7 +430,7 @@
      * @param flags initial flag bits, as if they were passed via setFlags().
      */
     public Paint(int flags) {
-        mNativePaint = native_init();
+        mNativePaint = nInit();
         setFlags(flags | HIDDEN_DEFAULT_PAINT_FLAGS);
         // TODO: Turning off hinting has undesirable side effects, we need to
         //       revisit hinting once we add support for subpixel positioning
@@ -448,13 +448,14 @@
      *              new paint.
      */
     public Paint(Paint paint) {
-        mNativePaint = native_initWithPaint(paint.getNativeInstance());
+        mNativePaint = nInitWithPaint(paint.getNativeInstance());
         setClassVariablesFrom(paint);
     }
 
     /** Restores the paint to its default settings. */
     public void reset() {
-        native_reset(mNativePaint);
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        nReset(mNativePaint);
         setFlags(HIDDEN_DEFAULT_PAINT_FLAGS);
 
         // TODO: Turning off hinting has undesirable side effects, we need to
@@ -488,9 +489,11 @@
      * methods on this.
      */
     public void set(Paint src) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        if (src.mNativePaint == 0) throw new NullPointerException("Source is already finalized!");
         if (this != src) {
             // copy over the native settings
-            native_set(mNativePaint, src.mNativePaint);
+            nSet(mNativePaint, src.mNativePaint);
             setClassVariablesFrom(src);
         }
     }
@@ -538,10 +541,11 @@
      * @hide
      */
     public long getNativeInstance() {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         long newNativeShader = mShader == null ? 0 : mShader.getNativeInstance();
         if (newNativeShader != mNativeShader) {
             mNativeShader = newNativeShader;
-            native_setShader(mNativePaint, mNativeShader);
+            nSetShader(mNativePaint, mNativeShader);
         }
         return mNativePaint;
     }
@@ -574,26 +578,46 @@
      *
      * @return the paint's flags (see enums ending in _Flag for bit masks)
      */
-    public native int getFlags();
+    public int getFlags() {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        return nGetFlags(mNativePaint);
+    }
+
+    private native int nGetFlags(long paintPtr);
 
     /**
      * Set the paint's flags. Use the Flag enum to specific flag values.
      *
      * @param flags The new flag bits for the paint
      */
-    public native void setFlags(int flags);
+    public void setFlags(int flags) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        nSetFlags(mNativePaint, flags);
+    }
+
+    private native void nSetFlags(long paintPtr, int flags);
 
     /**
      * Return the paint's hinting mode.  Returns either
      * {@link #HINTING_OFF} or {@link #HINTING_ON}.
      */
-    public native int getHinting();
+    public int getHinting() {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        return nGetHinting(mNativePaint);
+    }
+
+    private native int nGetHinting(long paintPtr);
 
     /**
      * Set the paint's hinting mode.  May be either
      * {@link #HINTING_OFF} or {@link #HINTING_ON}.
      */
-    public native void setHinting(int mode);
+    public void setHinting(int mode) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        nSetHinting(mNativePaint, mode);
+    }
+
+    private native void nSetHinting(long paintPtr, int mode);
 
     /**
      * Helper for getFlags(), returning true if ANTI_ALIAS_FLAG bit is set
@@ -615,7 +639,12 @@
      *
      * @param aa true to set the antialias bit in the flags, false to clear it
      */
-    public native void setAntiAlias(boolean aa);
+    public void setAntiAlias(boolean aa) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        nSetAntiAlias(mNativePaint, aa);
+    }
+
+    private native void nSetAntiAlias(long paintPtr, boolean aa);
 
     /**
      * Helper for getFlags(), returning true if DITHER_FLAG bit is set
@@ -641,7 +670,12 @@
      *
      * @param dither true to set the dithering bit in flags, false to clear it
      */
-    public native void setDither(boolean dither);
+    public void setDither(boolean dither) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        nSetDither(mNativePaint, dither);
+    }
+
+    private native void nSetDither(long paintPtr, boolean dither);
 
     /**
      * Helper for getFlags(), returning true if LINEAR_TEXT_FLAG bit is set
@@ -658,7 +692,12 @@
      * @param linearText true to set the linearText bit in the paint's flags,
      *                   false to clear it.
      */
-    public native void setLinearText(boolean linearText);
+    public void setLinearText(boolean linearText) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        nSetLinearText(mNativePaint, linearText);
+    }
+
+    private native void nSetLinearText(long paintPtr, boolean linearText);
 
     /**
      * Helper for getFlags(), returning true if SUBPIXEL_TEXT_FLAG bit is set
@@ -675,7 +714,12 @@
      * @param subpixelText true to set the subpixelText bit in the paint's
      *                     flags, false to clear it.
      */
-    public native void setSubpixelText(boolean subpixelText);
+    public void setSubpixelText(boolean subpixelText) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        nSetSubpixelText(mNativePaint, subpixelText);
+    }
+
+    private native void nSetSubpixelText(long paintPtr, boolean subpixelText);
 
     /**
      * Helper for getFlags(), returning true if UNDERLINE_TEXT_FLAG bit is set
@@ -692,7 +736,12 @@
      * @param underlineText true to set the underlineText bit in the paint's
      *                      flags, false to clear it.
      */
-    public native void setUnderlineText(boolean underlineText);
+    public void setUnderlineText(boolean underlineText) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        nSetUnderlineText(mNativePaint, underlineText);
+    }
+
+    private native void nSetUnderlineText(long paintPtr, boolean underlineText);
 
     /**
      * Helper for getFlags(), returning true if STRIKE_THRU_TEXT_FLAG bit is set
@@ -709,7 +758,12 @@
      * @param strikeThruText true to set the strikeThruText bit in the paint's
      *                       flags, false to clear it.
      */
-    public native void setStrikeThruText(boolean strikeThruText);
+    public void setStrikeThruText(boolean strikeThruText) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        nSetStrikeThruText(mNativePaint, strikeThruText);
+    }
+
+    private native void nSetStrikeThruText(long paintPtr, boolean strikeThruText);
 
     /**
      * Helper for getFlags(), returning true if FAKE_BOLD_TEXT_FLAG bit is set
@@ -726,7 +780,12 @@
      * @param fakeBoldText true to set the fakeBoldText bit in the paint's
      *                     flags, false to clear it.
      */
-    public native void setFakeBoldText(boolean fakeBoldText);
+    public void setFakeBoldText(boolean fakeBoldText) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        nSetFakeBoldText(mNativePaint, fakeBoldText);
+    }
+
+    private native void nSetFakeBoldText(long paintPtr, boolean fakeBoldText);
 
     /**
      * Whether or not the bitmap filter is activated.
@@ -749,7 +808,12 @@
      * @param filter true to set the FILTER_BITMAP_FLAG bit in the paint's
      *               flags, false to clear it.
      */
-    public native void setFilterBitmap(boolean filter);
+    public void setFilterBitmap(boolean filter) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        nSetFilterBitmap(mNativePaint, filter);
+    }
+
+    private native void nSetFilterBitmap(long paintPtr, boolean filter);
 
     /**
      * Return the paint's style, used for controlling how primitives'
@@ -759,7 +823,8 @@
      * @return the paint's style setting (Fill, Stroke, StrokeAndFill)
      */
     public Style getStyle() {
-        return sStyleArray[native_getStyle(mNativePaint)];
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        return sStyleArray[nGetStyle(mNativePaint)];
     }
 
     /**
@@ -770,7 +835,8 @@
      * @param style The new style to set in the paint
      */
     public void setStyle(Style style) {
-        native_setStyle(mNativePaint, style.nativeInt);
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        nSetStyle(mNativePaint, style.nativeInt);
     }
 
     /**
@@ -782,7 +848,12 @@
      * @return the paint's color (and alpha).
      */
     @ColorInt
-    public native int getColor();
+    public int getColor() {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        return nGetColor(mNativePaint);
+    }
+
+    private native int nGetColor(long paintPtr);
 
     /**
      * Set the paint's color. Note that the color is an int containing alpha
@@ -792,7 +863,12 @@
      *
      * @param color The new color (including alpha) to set in the paint.
      */
-    public native void setColor(@ColorInt int color);
+    public void setColor(@ColorInt int color) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        nSetColor(mNativePaint, color);
+    }
+
+    private native void nSetColor(long paintPtr, @ColorInt int color);
 
     /**
      * Helper to getColor() that just returns the color's alpha value. This is
@@ -801,7 +877,12 @@
      *
      * @return the alpha component of the paint's color.
      */
-    public native int getAlpha();
+    public int getAlpha() {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        return nGetAlpha(mNativePaint);
+    }
+
+    private native int nGetAlpha(long paintPtr);
 
     /**
      * Helper to setColor(), that only assigns the color's alpha value,
@@ -810,7 +891,12 @@
      *
      * @param a set the alpha component [0..255] of the paint's color.
      */
-    public native void setAlpha(int a);
+    public void setAlpha(int a) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        nSetAlpha(mNativePaint, a);
+    }
+
+    private native void nSetAlpha(long paintPtr, int a);
 
     /**
      * Helper to setColor(), that takes a,r,g,b and constructs the color int
@@ -833,7 +919,12 @@
      * @return the paint's stroke width, used whenever the paint's style is
      *         Stroke or StrokeAndFill.
      */
-    public native float getStrokeWidth();
+    public float getStrokeWidth() {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        return nGetStrokeWidth(mNativePaint);
+    }
+
+    private native float nGetStrokeWidth(long paintPtr);
 
     /**
      * Set the width for stroking.
@@ -843,7 +934,12 @@
      * @param width set the paint's stroke width, used whenever the paint's
      *              style is Stroke or StrokeAndFill.
      */
-    public native void setStrokeWidth(float width);
+    public void setStrokeWidth(float width) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        nSetStrokeWidth(mNativePaint, width);
+    }
+
+    private native void nSetStrokeWidth(long paintPtr, float width);
 
     /**
      * Return the paint's stroke miter value. Used to control the behavior
@@ -852,7 +948,12 @@
      * @return the paint's miter limit, used whenever the paint's style is
      *         Stroke or StrokeAndFill.
      */
-    public native float getStrokeMiter();
+    public float getStrokeMiter() {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        return nGetStrokeMiter(mNativePaint);
+    }
+
+    private native float nGetStrokeMiter(long paintPtr);
 
     /**
      * Set the paint's stroke miter value. This is used to control the behavior
@@ -861,7 +962,12 @@
      * @param miter set the miter limit on the paint, used whenever the paint's
      *              style is Stroke or StrokeAndFill.
      */
-    public native void setStrokeMiter(float miter);
+    public void setStrokeMiter(float miter) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        nSetStrokeMiter(mNativePaint, miter);
+    }
+
+    private native void nSetStrokeMiter(long paintPtr, float miter);
 
     /**
      * Return the paint's Cap, controlling how the start and end of stroked
@@ -871,7 +977,8 @@
      *         style is Stroke or StrokeAndFill.
      */
     public Cap getStrokeCap() {
-        return sCapArray[native_getStrokeCap(mNativePaint)];
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        return sCapArray[nGetStrokeCap(mNativePaint)];
     }
 
     /**
@@ -881,7 +988,8 @@
      *            style is Stroke or StrokeAndFill.
      */
     public void setStrokeCap(Cap cap) {
-        native_setStrokeCap(mNativePaint, cap.nativeInt);
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        nSetStrokeCap(mNativePaint, cap.nativeInt);
     }
 
     /**
@@ -890,7 +998,8 @@
      * @return the paint's Join.
      */
     public Join getStrokeJoin() {
-        return sJoinArray[native_getStrokeJoin(mNativePaint)];
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        return sJoinArray[nGetStrokeJoin(mNativePaint)];
     }
 
     /**
@@ -900,7 +1009,8 @@
      *             Stroke or StrokeAndFill.
      */
     public void setStrokeJoin(Join join) {
-        native_setStrokeJoin(mNativePaint, join.nativeInt);
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        nSetStrokeJoin(mNativePaint, join.nativeInt);
     }
 
     /**
@@ -915,7 +1025,8 @@
      *                 drawn with a hairline (width == 0)
      */
     public boolean getFillPath(Path src, Path dst) {
-        return native_getFillPath(mNativePaint, src.ni(), dst.ni());
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        return nGetFillPath(mNativePaint, src.ni(), dst.ni());
     }
 
     /**
@@ -958,10 +1069,11 @@
      * @return       filter
      */
     public ColorFilter setColorFilter(ColorFilter filter) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         long filterNative = 0;
         if (filter != null)
             filterNative = filter.native_instance;
-        native_setColorFilter(mNativePaint, filterNative);
+        nSetColorFilter(mNativePaint, filterNative);
         mColorFilter = filter;
         return filter;
     }
@@ -985,10 +1097,11 @@
      * @return         xfermode
      */
     public Xfermode setXfermode(Xfermode xfermode) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         long xfermodeNative = 0;
         if (xfermode != null)
             xfermodeNative = xfermode.native_instance;
-        native_setXfermode(mNativePaint, xfermodeNative);
+        nSetXfermode(mNativePaint, xfermodeNative);
         mXfermode = xfermode;
         return xfermode;
     }
@@ -1012,11 +1125,12 @@
      * @return       effect
      */
     public PathEffect setPathEffect(PathEffect effect) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         long effectNative = 0;
         if (effect != null) {
             effectNative = effect.native_instance;
         }
-        native_setPathEffect(mNativePaint, effectNative);
+        nSetPathEffect(mNativePaint, effectNative);
         mPathEffect = effect;
         return effect;
     }
@@ -1041,11 +1155,12 @@
      * @return           maskfilter
      */
     public MaskFilter setMaskFilter(MaskFilter maskfilter) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         long maskfilterNative = 0;
         if (maskfilter != null) {
             maskfilterNative = maskfilter.native_instance;
         }
-        native_setMaskFilter(mNativePaint, maskfilterNative);
+        nSetMaskFilter(mNativePaint, maskfilterNative);
         mMaskFilter = maskfilter;
         return maskfilter;
     }
@@ -1072,11 +1187,12 @@
      * @return         typeface
      */
     public Typeface setTypeface(Typeface typeface) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         long typefaceNative = 0;
         if (typeface != null) {
             typefaceNative = typeface.native_instance;
         }
-        native_setTypeface(mNativePaint, typefaceNative);
+        nSetTypeface(mNativePaint, typefaceNative);
         mTypeface = typeface;
         mNativeTypeface = typefaceNative;
         return typeface;
@@ -1110,11 +1226,12 @@
      */
     @Deprecated
     public Rasterizer setRasterizer(Rasterizer rasterizer) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         long rasterizerNative = 0;
         if (rasterizer != null) {
             rasterizerNative = rasterizer.native_instance;
         }
-        native_setRasterizer(mNativePaint, rasterizerNative);
+        nSetRasterizer(mNativePaint, rasterizerNative);
         mRasterizer = rasterizer;
         return rasterizer;
     }
@@ -1132,7 +1249,8 @@
      * opaque, or the alpha from the shadow color if not.
      */
     public void setShadowLayer(float radius, float dx, float dy, int shadowColor) {
-      native_setShadowLayer(mNativePaint, radius, dx, dy, shadowColor);
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+      nSetShadowLayer(mNativePaint, radius, dx, dy, shadowColor);
     }
 
     /**
@@ -1149,7 +1267,8 @@
      * @hide
      */
     public boolean hasShadowLayer() {
-      return native_hasShadowLayer(mNativePaint);
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        return nHasShadowLayer(mNativePaint);
     }
 
     /**
@@ -1161,7 +1280,8 @@
      * @return the paint's Align value for drawing text.
      */
     public Align getTextAlign() {
-        return sAlignArray[native_getTextAlign(mNativePaint)];
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        return sAlignArray[nGetTextAlign(mNativePaint)];
     }
 
     /**
@@ -1173,7 +1293,8 @@
      * @param align set the paint's Align value for drawing text.
      */
     public void setTextAlign(Align align) {
-        native_setTextAlign(mNativePaint, align.nativeInt);
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        nSetTextAlign(mNativePaint, align.nativeInt);
     }
 
     /**
@@ -1206,6 +1327,7 @@
      * @param locale the paint's locale value for drawing text, must not be null.
      */
     public void setTextLocale(@NonNull Locale locale) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if (locale == null) {
             throw new IllegalArgumentException("locale cannot be null");
         }
@@ -1213,7 +1335,7 @@
             return;
         }
         mLocales = new LocaleList(locale);
-        native_setTextLocale(mNativePaint, locale.toString());
+        nSetTextLocale(mNativePaint, locale.toString());
     }
 
     /**
@@ -1244,13 +1366,14 @@
      * @param locales the paint's locale list for drawing text, must not be null or empty.
      */
     public void setTextLocales(@NonNull @Size(min=1) LocaleList locales) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if (locales == null || locales.isEmpty()) {
             throw new IllegalArgumentException("locales cannot be null or empty");
         }
         if (locales.equals(mLocales)) return;
         mLocales = locales;
         // TODO: Pass the whole LocaleList to native code
-        native_setTextLocale(mNativePaint, locales.getPrimary().toString());
+        nSetTextLocale(mNativePaint, locales.getPrimary().toString());
     }
 
     /**
@@ -1258,7 +1381,12 @@
      *
      * @return true if elegant metrics are enabled for text drawing.
      */
-    public native boolean isElegantTextHeight();
+    public boolean isElegantTextHeight() {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        return nIsElegantTextHeight(mNativePaint);
+    }
+
+    private native boolean nIsElegantTextHeight(long paintPtr);
 
     /**
      * Set the paint's elegant height metrics flag. This setting selects font
@@ -1267,21 +1395,36 @@
      *
      * @param elegant set the paint's elegant metrics flag for drawing text.
      */
-    public native void setElegantTextHeight(boolean elegant);
+    public void setElegantTextHeight(boolean elegant) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        nSetElegantTextHeight(mNativePaint, elegant);
+    }
+
+    private native void nSetElegantTextHeight(long paintPtr, boolean elegant);
 
     /**
      * Return the paint's text size.
      *
      * @return the paint's text size.
      */
-    public native float getTextSize();
+    public float getTextSize() {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        return nGetTextSize(mNativePaint);
+    }
+
+    private native float nGetTextSize(long paintPtr);
 
     /**
      * Set the paint's text size. This value must be > 0
      *
      * @param textSize set the paint's text size.
      */
-    public native void setTextSize(float textSize);
+    public void setTextSize(float textSize) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        nSetTextSize(mNativePaint, textSize);
+    }
+
+    private native void nSetTextSize(long paintPtr, float textSize);
 
     /**
      * Return the paint's horizontal scale factor for text. The default value
@@ -1289,7 +1432,12 @@
      *
      * @return the paint's scale factor in X for drawing/measuring text
      */
-    public native float getTextScaleX();
+    public float getTextScaleX() {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        return nGetTextScaleX(mNativePaint);
+    }
+
+    private native float nGetTextScaleX(long paintPtr);
 
     /**
      * Set the paint's horizontal scale factor for text. The default value
@@ -1298,7 +1446,12 @@
      *
      * @param scaleX set the paint's scale in X for drawing/measuring text.
      */
-    public native void setTextScaleX(float scaleX);
+    public void setTextScaleX(float scaleX) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        nSetTextScaleX(mNativePaint, scaleX);
+    }
+
+    private native void nSetTextScaleX(long paintPtr, float scaleX);
 
     /**
      * Return the paint's horizontal skew factor for text. The default value
@@ -1306,7 +1459,12 @@
      *
      * @return         the paint's skew factor in X for drawing text.
      */
-    public native float getTextSkewX();
+    public float getTextSkewX() {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        return nGetTextSkewX(mNativePaint);
+    }
+
+    private native float nGetTextSkewX(long paintPtr);
 
     /**
      * Set the paint's horizontal skew factor for text. The default value
@@ -1314,7 +1472,12 @@
      *
      * @param skewX set the paint's skew factor in X for drawing text.
      */
-    public native void setTextSkewX(float skewX);
+    public void setTextSkewX(float skewX) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        nSetTextSkewX(mNativePaint, skewX);
+    }
+
+    private native void nSetTextSkewX(long paintPtr, float skewX);
 
     /**
      * Return the paint's letter-spacing for text. The default value
@@ -1323,7 +1486,8 @@
      * @return         the paint's letter-spacing for drawing text.
      */
     public float getLetterSpacing() {
-        return native_getLetterSpacing(mNativePaint);
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        return nGetLetterSpacing(mNativePaint);
     }
 
     /**
@@ -1334,7 +1498,8 @@
      * @param letterSpacing set the paint's letter-spacing for drawing text.
      */
     public void setLetterSpacing(float letterSpacing) {
-        native_setLetterSpacing(mNativePaint, letterSpacing);
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        nSetLetterSpacing(mNativePaint, letterSpacing);
     }
 
     /**
@@ -1355,6 +1520,7 @@
      * @param settings the font feature settings string to use, may be null.
      */
     public void setFontFeatureSettings(String settings) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if (settings != null && settings.equals("")) {
             settings = null;
         }
@@ -1363,7 +1529,7 @@
             return;
         }
         mFontFeatureSettings = settings;
-        native_setFontFeatureSettings(mNativePaint, settings);
+        nSetFontFeatureSettings(mNativePaint, settings);
     }
 
     /**
@@ -1374,7 +1540,8 @@
      * @hide
      */
     public int getHyphenEdit() {
-        return native_getHyphenEdit(mNativePaint);
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        return nGetHyphenEdit(mNativePaint);
     }
 
     /**
@@ -1386,7 +1553,8 @@
      * @hide
      */
     public void setHyphenEdit(int hyphen) {
-        native_setHyphenEdit(mNativePaint, hyphen);
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        nSetHyphenEdit(mNativePaint, hyphen);
     }
 
     /**
@@ -1396,7 +1564,12 @@
      * @return the distance above (negative) the baseline (ascent) based on the
      *         current typeface and text size.
      */
-    public native float ascent();
+    public float ascent() {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        return nAscent(mNativePaint, mNativeTypeface);
+    }
+
+    private native float nAscent(long paintPtr, long typefacePtr);
 
     /**
      * Return the distance below (positive) the baseline (descent) based on the
@@ -1405,7 +1578,12 @@
      * @return the distance below (positive) the baseline (descent) based on
      *         the current typeface and text size.
      */
-    public native float descent();
+    public float descent() {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        return nDescent(mNativePaint, mNativeTypeface);
+    }
+
+    private native float nDescent(long paintPtr, long typefacePtr);
 
     /**
      * Class that describes the various metrics for a font at a given text size.
@@ -1447,7 +1625,13 @@
      *                the appropriate values given the paint's text attributes.
      * @return the font's recommended interline spacing.
      */
-    public native float getFontMetrics(FontMetrics metrics);
+    public float getFontMetrics(FontMetrics metrics) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        return nGetFontMetrics(mNativePaint, mNativeTypeface, metrics);
+    }
+
+    private native float nGetFontMetrics(long paintPtr,
+            long typefacePtr, FontMetrics metrics);
 
     /**
      * Allocates a new FontMetrics object, and then calls getFontMetrics(fm)
@@ -1487,7 +1671,13 @@
      *
      * @return the font's interline spacing.
      */
-    public native int getFontMetricsInt(FontMetricsInt fmi);
+    public int getFontMetricsInt(FontMetricsInt fmi) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        return nGetFontMetricsInt(mNativePaint, mNativeTypeface, fmi);
+    }
+
+    private native int nGetFontMetricsInt(long paintPtr,
+            long typefacePtr, FontMetricsInt fmi);
 
     public FontMetricsInt getFontMetricsInt() {
         FontMetricsInt fm = new FontMetricsInt();
@@ -1515,6 +1705,7 @@
      * @return      The width of the text
      */
     public float measureText(char[] text, int index, int count) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if (text == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
@@ -1526,13 +1717,13 @@
             return 0f;
         }
         if (!mHasCompatScaling) {
-            return (float) Math.ceil(native_getTextAdvances(mNativePaint, mNativeTypeface, text,
+            return (float) Math.ceil(nGetTextAdvances(mNativePaint, mNativeTypeface, text,
                     index, count, index, count, mBidiFlags, null, 0));
         }
 
         final float oldSize = getTextSize();
         setTextSize(oldSize * mCompatScaling);
-        float w = native_getTextAdvances(mNativePaint, mNativeTypeface, text, index, count, index,
+        float w = nGetTextAdvances(mNativePaint, mNativeTypeface, text, index, count, index,
                 count, mBidiFlags, null, 0);
         setTextSize(oldSize);
         return (float) Math.ceil(w*mInvCompatScaling);
@@ -1547,6 +1738,7 @@
      * @return      The width of the text
      */
     public float measureText(String text, int start, int end) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if (text == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
@@ -1558,12 +1750,12 @@
             return 0f;
         }
         if (!mHasCompatScaling) {
-            return (float) Math.ceil(native_getTextAdvances(mNativePaint, mNativeTypeface, text,
+            return (float) Math.ceil(nGetTextAdvances(mNativePaint, mNativeTypeface, text,
                     start, end, start, end, mBidiFlags, null, 0));
         }
         final float oldSize = getTextSize();
         setTextSize(oldSize * mCompatScaling);
-        float w = native_getTextAdvances(mNativePaint, mNativeTypeface, text, start, end, start,
+        float w = nGetTextAdvances(mNativePaint, mNativeTypeface, text, start, end, start,
                 end, mBidiFlags, null, 0);
         setTextSize(oldSize);
         return (float) Math.ceil(w * mInvCompatScaling);
@@ -1576,6 +1768,7 @@
      * @return      The width of the text
      */
     public float measureText(String text) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if (text == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
@@ -1636,6 +1829,7 @@
      */
     public int breakText(char[] text, int index, int count,
                                 float maxWidth, float[] measuredWidth) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if (text == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
@@ -1647,20 +1841,20 @@
             return 0;
         }
         if (!mHasCompatScaling) {
-            return native_breakText(mNativePaint, mNativeTypeface, text, index, count, maxWidth,
+            return nBreakText(mNativePaint, mNativeTypeface, text, index, count, maxWidth,
                     mBidiFlags, measuredWidth);
         }
 
         final float oldSize = getTextSize();
         setTextSize(oldSize * mCompatScaling);
-        int res = native_breakText(mNativePaint, mNativeTypeface, text, index, count,
+        int res = nBreakText(mNativePaint, mNativeTypeface, text, index, count,
                 maxWidth * mCompatScaling, mBidiFlags, measuredWidth);
         setTextSize(oldSize);
         if (measuredWidth != null) measuredWidth[0] *= mInvCompatScaling;
         return res;
     }
 
-    private static native int native_breakText(long native_object, long native_typeface,
+    private static native int nBreakText(long nObject, long nTypeface,
                                                char[] text, int index, int count,
                                                float maxWidth, int bidiFlags, float[] measuredWidth);
 
@@ -1683,6 +1877,7 @@
     public int breakText(CharSequence text, int start, int end,
                          boolean measureForwards,
                          float maxWidth, float[] measuredWidth) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if (text == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
@@ -1731,6 +1926,7 @@
      */
     public int breakText(String text, boolean measureForwards,
                                 float maxWidth, float[] measuredWidth) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if (text == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
@@ -1739,20 +1935,20 @@
             return 0;
         }
         if (!mHasCompatScaling) {
-            return native_breakText(mNativePaint, mNativeTypeface, text, measureForwards,
+            return nBreakText(mNativePaint, mNativeTypeface, text, measureForwards,
                     maxWidth, mBidiFlags, measuredWidth);
         }
 
         final float oldSize = getTextSize();
         setTextSize(oldSize*mCompatScaling);
-        int res = native_breakText(mNativePaint, mNativeTypeface, text, measureForwards,
+        int res = nBreakText(mNativePaint, mNativeTypeface, text, measureForwards,
                 maxWidth*mCompatScaling, mBidiFlags, measuredWidth);
         setTextSize(oldSize);
         if (measuredWidth != null) measuredWidth[0] *= mInvCompatScaling;
         return res;
     }
 
-    private static native int native_breakText(long native_object, long native_typeface,
+    private static native int nBreakText(long nObject, long nTypeface,
                                         String text, boolean measureForwards,
                                         float maxWidth, int bidiFlags, float[] measuredWidth);
 
@@ -1768,6 +1964,7 @@
      */
     public int getTextWidths(char[] text, int index, int count,
                              float[] widths) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if (text == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
@@ -1780,14 +1977,14 @@
             return 0;
         }
         if (!mHasCompatScaling) {
-            native_getTextAdvances(mNativePaint, mNativeTypeface, text, index, count, index, count,
+            nGetTextAdvances(mNativePaint, mNativeTypeface, text, index, count, index, count,
                     mBidiFlags, widths, 0);
             return count;
         }
 
         final float oldSize = getTextSize();
         setTextSize(oldSize * mCompatScaling);
-        native_getTextAdvances(mNativePaint, mNativeTypeface, text, index, count, index, count,
+        nGetTextAdvances(mNativePaint, mNativeTypeface, text, index, count, index, count,
                 mBidiFlags, widths, 0);
         setTextSize(oldSize);
         for (int i = 0; i < count; i++) {
@@ -1851,6 +2048,7 @@
      * @return       the number of code units in the specified text.
      */
     public int getTextWidths(String text, int start, int end, float[] widths) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if (text == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
@@ -1865,14 +2063,14 @@
             return 0;
         }
         if (!mHasCompatScaling) {
-            native_getTextAdvances(mNativePaint, mNativeTypeface, text, start, end, start, end,
+            nGetTextAdvances(mNativePaint, mNativeTypeface, text, start, end, start, end,
                     mBidiFlags, widths, 0);
             return end - start;
         }
 
         final float oldSize = getTextSize();
         setTextSize(oldSize * mCompatScaling);
-        native_getTextAdvances(mNativePaint, mNativeTypeface, text, start, end, start, end,
+        nGetTextAdvances(mNativePaint, mNativeTypeface, text, start, end, start, end,
                 mBidiFlags, widths, 0);
         setTextSize(oldSize);
         for (int i = 0; i < end - start; i++) {
@@ -1904,6 +2102,7 @@
             int contextIndex, int contextCount, boolean isRtl, float[] advances,
             int advancesIndex) {
 
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if (chars == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
@@ -1920,14 +2119,14 @@
             return 0f;
         }
         if (!mHasCompatScaling) {
-            return native_getTextAdvances(mNativePaint, mNativeTypeface, chars, index, count,
+            return nGetTextAdvances(mNativePaint, mNativeTypeface, chars, index, count,
                     contextIndex, contextCount, isRtl ? BIDI_FORCE_RTL : BIDI_FORCE_LTR, advances,
                     advancesIndex);
         }
 
         final float oldSize = getTextSize();
         setTextSize(oldSize * mCompatScaling);
-        float res = native_getTextAdvances(mNativePaint, mNativeTypeface, chars, index, count,
+        float res = nGetTextAdvances(mNativePaint, mNativeTypeface, chars, index, count,
                 contextIndex, contextCount, isRtl ? BIDI_FORCE_RTL : BIDI_FORCE_LTR, advances,
                 advancesIndex);
         setTextSize(oldSize);
@@ -1950,7 +2149,7 @@
     public float getTextRunAdvances(CharSequence text, int start, int end,
             int contextStart, int contextEnd, boolean isRtl, float[] advances,
             int advancesIndex) {
-
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if (text == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
@@ -2032,6 +2231,7 @@
      */
     public float getTextRunAdvances(String text, int start, int end, int contextStart,
             int contextEnd, boolean isRtl, float[] advances, int advancesIndex) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if (text == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
@@ -2048,14 +2248,14 @@
         }
 
         if (!mHasCompatScaling) {
-            return native_getTextAdvances(mNativePaint, mNativeTypeface, text, start, end,
+            return nGetTextAdvances(mNativePaint, mNativeTypeface, text, start, end,
                     contextStart, contextEnd, isRtl ? BIDI_FORCE_RTL : BIDI_FORCE_LTR, advances,
                     advancesIndex);
         }
 
         final float oldSize = getTextSize();
         setTextSize(oldSize * mCompatScaling);
-        float totalAdvance = native_getTextAdvances(mNativePaint, mNativeTypeface, text, start,
+        float totalAdvance = nGetTextAdvances(mNativePaint, mNativeTypeface, text, start,
                 end, contextStart, contextEnd, isRtl ? BIDI_FORCE_RTL : BIDI_FORCE_LTR, advances,
                 advancesIndex);
         setTextSize(oldSize);
@@ -2096,6 +2296,7 @@
      */
     public int getTextRunCursor(char[] text, int contextStart, int contextLength,
             int dir, int offset, int cursorOpt) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         int contextEnd = contextStart + contextLength;
         if (((contextStart | contextEnd | offset | (contextEnd - contextStart)
                 | (offset - contextStart) | (contextEnd - offset)
@@ -2104,7 +2305,7 @@
             throw new IndexOutOfBoundsException();
         }
 
-        return native_getTextRunCursor(mNativePaint, text,
+        return nGetTextRunCursor(mNativePaint, text,
                 contextStart, contextLength, dir, offset, cursorOpt);
     }
 
@@ -2183,6 +2384,7 @@
      */
     public int getTextRunCursor(String text, int contextStart, int contextEnd,
             int dir, int offset, int cursorOpt) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if (((contextStart | contextEnd | offset | (contextEnd - contextStart)
                 | (offset - contextStart) | (contextEnd - offset)
                 | (text.length() - contextEnd) | cursorOpt) < 0)
@@ -2190,7 +2392,7 @@
             throw new IndexOutOfBoundsException();
         }
 
-        return native_getTextRunCursor(mNativePaint, text,
+        return nGetTextRunCursor(mNativePaint, text,
                 contextStart, contextEnd, dir, offset, cursorOpt);
     }
 
@@ -2209,10 +2411,11 @@
      */
     public void getTextPath(char[] text, int index, int count,
                             float x, float y, Path path) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if ((index | count) < 0 || index + count > text.length) {
             throw new ArrayIndexOutOfBoundsException();
         }
-        native_getTextPath(mNativePaint, mNativeTypeface, mBidiFlags, text, index, count, x, y,
+        nGetTextPath(mNativePaint, mNativeTypeface, mBidiFlags, text, index, count, x, y,
                 path.ni());
     }
 
@@ -2231,10 +2434,11 @@
      */
     public void getTextPath(String text, int start, int end,
                             float x, float y, Path path) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if ((start | end | (end - start) | (text.length() - end)) < 0) {
             throw new IndexOutOfBoundsException();
         }
-        native_getTextPath(mNativePaint, mNativeTypeface, mBidiFlags, text, start, end, x, y,
+        nGetTextPath(mNativePaint, mNativeTypeface, mBidiFlags, text, start, end, x, y,
                 path.ni());
     }
 
@@ -2249,13 +2453,14 @@
      *               allocated by the caller.
      */
     public void getTextBounds(String text, int start, int end, Rect bounds) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if ((start | end | (end - start) | (text.length() - end)) < 0) {
             throw new IndexOutOfBoundsException();
         }
         if (bounds == null) {
             throw new NullPointerException("need bounds Rect");
         }
-        nativeGetStringBounds(mNativePaint, mNativeTypeface, text, start, end, mBidiFlags, bounds);
+        nGetStringBounds(mNativePaint, mNativeTypeface, text, start, end, mBidiFlags, bounds);
     }
 
     /**
@@ -2269,13 +2474,14 @@
      *               allocated by the caller.
      */
     public void getTextBounds(char[] text, int index, int count, Rect bounds) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if ((index | count) < 0 || index + count > text.length) {
             throw new ArrayIndexOutOfBoundsException();
         }
         if (bounds == null) {
             throw new NullPointerException("need bounds Rect");
         }
-        nativeGetCharArrayBounds(mNativePaint, mNativeTypeface, text, index, count, mBidiFlags,
+        nGetCharArrayBounds(mNativePaint, mNativeTypeface, text, index, count, mBidiFlags,
             bounds);
     }
 
@@ -2296,7 +2502,8 @@
      * @return true if the typeface has a glyph for the string
      */
     public boolean hasGlyph(String string) {
-        return native_hasGlyph(mNativePaint, mNativeTypeface, mBidiFlags, string);
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
+        return nHasGlyph(mNativePaint, mNativeTypeface, mBidiFlags, string);
     }
 
     /**
@@ -2337,6 +2544,7 @@
      */
     public float getRunAdvance(char[] text, int start, int end, int contextStart, int contextEnd,
             boolean isRtl, int offset) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if (text == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
@@ -2349,7 +2557,7 @@
             return 0.0f;
         }
         // TODO: take mCompatScaling into account (or eliminate compat scaling)?
-        return native_getRunAdvance(mNativePaint, mNativeTypeface, text, start, end,
+        return nGetRunAdvance(mNativePaint, mNativeTypeface, text, start, end,
                 contextStart, contextEnd, isRtl, offset);
     }
 
@@ -2367,6 +2575,7 @@
      */
     public float getRunAdvance(CharSequence text, int start, int end, int contextStart,
             int contextEnd, boolean isRtl, int offset) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if (text == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
@@ -2417,6 +2626,7 @@
      */
     public int getOffsetForAdvance(char[] text, int start, int end, int contextStart,
             int contextEnd, boolean isRtl, float advance) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if (text == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
@@ -2426,7 +2636,7 @@
             throw new IndexOutOfBoundsException();
         }
         // TODO: take mCompatScaling into account (or eliminate compat scaling)?
-        return native_getOffsetForAdvance(mNativePaint, mNativeTypeface, text, start, end,
+        return nGetOffsetForAdvance(mNativePaint, mNativeTypeface, text, start, end,
                 contextStart, contextEnd, isRtl, advance);
     }
 
@@ -2444,6 +2654,7 @@
      */
     public int getOffsetForAdvance(CharSequence text, int start, int end, int contextStart,
             int contextEnd, boolean isRtl, float advance) {
+        if (mNativePaint == 0) throw new NullPointerException("Already finalized!");
         if (text == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
@@ -2464,90 +2675,88 @@
     @Override
     protected void finalize() throws Throwable {
         try {
-            finalizer(mNativePaint);
-            mNativePaint = 0;
+            if (mNativePaint != 0) {
+                nFinalizer(mNativePaint);
+                mNativePaint = 0;
+            }
         } finally {
             super.finalize();
         }
     }
 
-    private static native long native_init();
-    private static native long native_initWithPaint(long paint);
-    private static native void native_reset(long native_object);
-    private static native void native_set(long native_dst, long native_src);
-    private static native int native_getStyle(long native_object);
-    private static native void native_setStyle(long native_object, int style);
-    private static native int native_getStrokeCap(long native_object);
-    private static native void native_setStrokeCap(long native_object, int cap);
-    private static native int native_getStrokeJoin(long native_object);
-    private static native void native_setStrokeJoin(long native_object,
+    private static native long nInit();
+    private static native long nInitWithPaint(long paint);
+    private static native void nReset(long paintPtr);
+    private static native void nSet(long paintPtrDest, long paintPtrSrc);
+    private static native int nGetStyle(long paintPtr);
+    private static native void nSetStyle(long paintPtr, int style);
+    private static native int nGetStrokeCap(long paintPtr);
+    private static native void nSetStrokeCap(long paintPtr, int cap);
+    private static native int nGetStrokeJoin(long paintPtr);
+    private static native void nSetStrokeJoin(long paintPtr,
                                                     int join);
-    private static native boolean native_getFillPath(long native_object,
+    private static native boolean nGetFillPath(long paintPtr,
                                                      long src, long dst);
-    private static native long native_setShader(long native_object, long shader);
-    private static native long native_setColorFilter(long native_object,
+    private static native long nSetShader(long paintPtr, long shader);
+    private static native long nSetColorFilter(long paintPtr,
                                                     long filter);
-    private static native long native_setXfermode(long native_object,
+    private static native long nSetXfermode(long paintPtr,
                                                   long xfermode);
-    private static native long native_setPathEffect(long native_object,
+    private static native long nSetPathEffect(long paintPtr,
                                                     long effect);
-    private static native long native_setMaskFilter(long native_object,
+    private static native long nSetMaskFilter(long paintPtr,
                                                     long maskfilter);
-    private static native long native_setTypeface(long native_object,
+    private static native long nSetTypeface(long paintPtr,
                                                   long typeface);
-    private static native long native_setRasterizer(long native_object,
+    private static native long nSetRasterizer(long paintPtr,
                                                    long rasterizer);
 
-    private static native int native_getTextAlign(long native_object);
-    private static native void native_setTextAlign(long native_object,
+    private static native int nGetTextAlign(long paintPtr);
+    private static native void nSetTextAlign(long paintPtr,
                                                    int align);
 
-    private static native void native_setTextLocale(long native_object,
+    private static native void nSetTextLocale(long paintPtr,
                                                     String locale);
 
-    private static native int native_getTextGlyphs(long native_object,
-            String text, int start, int end, int contextStart, int contextEnd,
-            int flags, char[] glyphs);
-
-    private static native float native_getTextAdvances(long native_object, long native_typeface,
+    private static native float nGetTextAdvances(long paintPtr, long typefacePtr,
             char[] text, int index, int count, int contextIndex, int contextCount,
             int bidiFlags, float[] advances, int advancesIndex);
-    private static native float native_getTextAdvances(long native_object, long native_typeface,
+    private static native float nGetTextAdvances(long paintPtr, long typefacePtr,
             String text, int start, int end, int contextStart, int contextEnd,
             int bidiFlags, float[] advances, int advancesIndex);
 
-    private native int native_getTextRunCursor(long native_object, char[] text,
+    private native int nGetTextRunCursor(long paintPtr, char[] text,
             int contextStart, int contextLength, int dir, int offset, int cursorOpt);
-    private native int native_getTextRunCursor(long native_object, String text,
+    private native int nGetTextRunCursor(long paintPtr, String text,
             int contextStart, int contextEnd, int dir, int offset, int cursorOpt);
 
-    private static native void native_getTextPath(long native_object, long native_typeface,
+    private static native void nGetTextPath(long paintPtr, long typefacePtr,
             int bidiFlags, char[] text, int index, int count, float x, float y, long path);
-    private static native void native_getTextPath(long native_object, long native_typeface,
+    private static native void nGetTextPath(long paintPtr, long typefacePtr,
             int bidiFlags, String text, int start, int end, float x, float y, long path);
-    private static native void nativeGetStringBounds(long nativePaint, long native_typeface,
+    private static native void nGetStringBounds(long nativePaint, long typefacePtr,
                                 String text, int start, int end, int bidiFlags, Rect bounds);
-    private static native void nativeGetCharArrayBounds(long nativePaint, long native_typeface,
+    private static native void nGetCharArrayBounds(long nativePaint, long typefacePtr,
                                 char[] text, int index, int count, int bidiFlags, Rect bounds);
-    private static native void finalizer(long nativePaint);
+    private static native void nFinalizer(long nativePaint);
 
-    private static native void native_setShadowLayer(long native_object,
+    private static native void nSetShadowLayer(long paintPtr,
             float radius, float dx, float dy, int color);
-    private static native boolean native_hasShadowLayer(long native_object);
+    private static native boolean nHasShadowLayer(long paintPtr);
 
-    private static native float native_getLetterSpacing(long native_object);
-    private static native void native_setLetterSpacing(long native_object,
+    private static native float nGetLetterSpacing(long paintPtr);
+    private static native void nSetLetterSpacing(long paintPtr,
                                                        float letterSpacing);
-    private static native void native_setFontFeatureSettings(long native_object,
+    private static native void nSetFontFeatureSettings(long paintPtr,
                                                              String settings);
-    private static native int native_getHyphenEdit(long native_object);
-    private static native void native_setHyphenEdit(long native_object, int hyphen);
-    private static native boolean native_hasGlyph(long native_object, long native_typeface,
+    private static native int nGetHyphenEdit(long paintPtr);
+    private static native void nSetHyphenEdit(long paintPtr, int hyphen);
+    private static native boolean nHasGlyph(long paintPtr, long typefacePtr,
             int bidiFlags, String string);
-    private static native float native_getRunAdvance(long native_object, long native_typeface,
+    private static native float nGetRunAdvance(long paintPtr, long typefacePtr,
             char[] text, int start, int end, int contextStart, int contextEnd, boolean isRtl,
             int offset);
-    private static native int native_getOffsetForAdvance(long native_object,
-            long native_typeface, char[] text, int start, int end, int contextStart, int contextEnd,
+    private static native int nGetOffsetForAdvance(long paintPtr,
+            long typefacePtr, char[] text, int start, int end, int contextStart, int contextEnd,
             boolean isRtl, float advance);
 }
diff --git a/graphics/tests/graphicstests/src/android/graphics/PaintTest.java b/graphics/tests/graphicstests/src/android/graphics/PaintTest.java
index b67aa7d..6763dd1 100644
--- a/graphics/tests/graphicstests/src/android/graphics/PaintTest.java
+++ b/graphics/tests/graphicstests/src/android/graphics/PaintTest.java
@@ -162,4 +162,60 @@
         } catch (IndexOutOfBoundsException e) {
         }
     }
+
+    public void testMeasureTextBidi() {
+        Paint p = new Paint();
+        {
+            String bidiText = "abc \u0644\u063A\u0629 def";
+            p.setBidiFlags(Paint.BIDI_LTR);
+            float width = p.measureText(bidiText, 0, 4);
+            p.setBidiFlags(Paint.BIDI_RTL);
+            width += p.measureText(bidiText, 4, 7);
+            p.setBidiFlags(Paint.BIDI_LTR);
+            width += p.measureText(bidiText, 7, bidiText.length());
+            assertEquals(width, p.measureText(bidiText), 1.0f);
+        }
+        {
+            String bidiText = "abc \u0644\u063A\u0629 def";
+            p.setBidiFlags(Paint.BIDI_DEFAULT_LTR);
+            float width = p.measureText(bidiText, 0, 4);
+            width += p.measureText(bidiText, 4, 7);
+            width += p.measureText(bidiText, 7, bidiText.length());
+            assertEquals(width, p.measureText(bidiText), 1.0f);
+        }
+        {
+            String bidiText = "abc \u0644\u063A\u0629 def";
+            p.setBidiFlags(Paint.BIDI_FORCE_LTR);
+            float width = p.measureText(bidiText, 0, 4);
+            width += p.measureText(bidiText, 4, 7);
+            width += p.measureText(bidiText, 7, bidiText.length());
+            assertEquals(width, p.measureText(bidiText), 1.0f);
+        }
+        {
+            String bidiText = "\u0644\u063A\u0629 abc \u0644\u063A\u0629";
+            p.setBidiFlags(Paint.BIDI_RTL);
+            float width = p.measureText(bidiText, 0, 4);
+            p.setBidiFlags(Paint.BIDI_LTR);
+            width += p.measureText(bidiText, 4, 7);
+            p.setBidiFlags(Paint.BIDI_RTL);
+            width += p.measureText(bidiText, 7, bidiText.length());
+            assertEquals(width, p.measureText(bidiText), 1.0f);
+        }
+        {
+            String bidiText = "\u0644\u063A\u0629 abc \u0644\u063A\u0629";
+            p.setBidiFlags(Paint.BIDI_DEFAULT_RTL);
+            float width = p.measureText(bidiText, 0, 4);
+            width += p.measureText(bidiText, 4, 7);
+            width += p.measureText(bidiText, 7, bidiText.length());
+            assertEquals(width, p.measureText(bidiText), 1.0f);
+        }
+        {
+            String bidiText = "\u0644\u063A\u0629 abc \u0644\u063A\u0629";
+            p.setBidiFlags(Paint.BIDI_FORCE_RTL);
+            float width = p.measureText(bidiText, 0, 4);
+            width += p.measureText(bidiText, 4, 7);
+            width += p.measureText(bidiText, 7, bidiText.length());
+            assertEquals(width, p.measureText(bidiText), 1.0f);
+        }
+    }
 }
diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp
index e0bf26d..0c29a9e 100644
--- a/libs/hwui/DeferredDisplayList.cpp
+++ b/libs/hwui/DeferredDisplayList.cpp
@@ -44,6 +44,12 @@
 #define DEBUG_COLOR_MERGEDBATCH      0x5f7f7fff
 #define DEBUG_COLOR_MERGEDBATCH_SOLO 0x5f7fff7f
 
+static bool avoidOverdraw() {
+    // Don't avoid overdraw when visualizing it, since that makes it harder to
+    // debug where it's coming from, and when the problem occurs.
+    return !Properties::debugOverdraw;
+};
+
 /////////////////////////////////////////////////////////////////////////////////
 // Operation Batches
 /////////////////////////////////////////////////////////////////////////////////
@@ -218,7 +224,10 @@
         // if paints are equal, then modifiers + paint attribs don't need to be compared
         if (op->mPaint == mOps[0].op->mPaint) return true;
 
-        if (op->getPaintAlpha() != mOps[0].op->getPaintAlpha()) return false;
+        if (PaintUtils::getAlphaDirect(op->mPaint)
+                != PaintUtils::getAlphaDirect(mOps[0].op->mPaint)) {
+            return false;
+        }
 
         if (op->mPaint && mOps[0].op->mPaint &&
             op->mPaint->getColorFilter() != mOps[0].op->mPaint->getColorFilter()) {
@@ -495,7 +504,7 @@
             && mSaveStack.empty()
             && !state->mRoundRectClipState;
 
-    if (CC_LIKELY(mAvoidOverdraw) && mBatches.size() &&
+    if (CC_LIKELY(avoidOverdraw()) && mBatches.size() &&
             state->mClipSideFlags != kClipSide_ConservativeFull &&
             deferInfo.opaqueOverBounds && state->mBounds.contains(mBounds)) {
         // avoid overdraw by resetting drawing state + discarding drawing ops
@@ -647,7 +656,7 @@
     // save and restore so that reordering doesn't affect final state
     renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
 
-    if (CC_LIKELY(mAvoidOverdraw)) {
+    if (CC_LIKELY(avoidOverdraw())) {
         for (unsigned int i = 1; i < mBatches.size(); i++) {
             if (mBatches[i] && mBatches[i]->coversBounds(mBounds)) {
                 discardDrawingBatches(i - 1);
diff --git a/libs/hwui/DeferredDisplayList.h b/libs/hwui/DeferredDisplayList.h
index 748bff6..7873fbd 100644
--- a/libs/hwui/DeferredDisplayList.h
+++ b/libs/hwui/DeferredDisplayList.h
@@ -83,8 +83,8 @@
 class DeferredDisplayList {
     friend struct DeferStateStruct; // used to give access to allocator
 public:
-    DeferredDisplayList(const Rect& bounds, bool avoidOverdraw = true) :
-            mBounds(bounds), mAvoidOverdraw(avoidOverdraw) {
+    DeferredDisplayList(const Rect& bounds)
+            : mBounds(bounds) {
         clear();
     }
     ~DeferredDisplayList() { clear(); }
@@ -152,7 +152,6 @@
 
     // layer space bounds of rendering
     Rect mBounds;
-    const bool mAvoidOverdraw;
 
     /**
      * At defer time, stores the *defer time* savecount of save/saveLayer ops that were deferred, so
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index 38f2363f..7038334 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -47,7 +47,8 @@
 }
 
 void DeferredLayerUpdater::setPaint(const SkPaint* paint) {
-    OpenGLRenderer::getAlphaAndModeDirect(paint, &mAlpha, &mMode);
+    mAlpha = PaintUtils::getAlphaDirect(paint);
+    mMode = PaintUtils::getXfermodeDirect(paint);
     SkColorFilter* colorFilter = (paint) ? paint->getColorFilter() : nullptr;
     SkRefCnt_SafeAssign(mColorFilter, colorFilter);
 }
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index dc5cb8b..ddfc533 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -172,10 +172,6 @@
     void setQuickRejected(bool quickRejected) { mQuickRejected = quickRejected; }
     bool getQuickRejected() { return mQuickRejected; }
 
-    inline int getPaintAlpha() const {
-        return OpenGLRenderer::getAlphaDirect(mPaint);
-    }
-
     virtual bool hasTextShadow() const {
         return false;
     }
@@ -213,7 +209,7 @@
 
         if (state.mAlpha != 1.0f) return false;
 
-        SkXfermode::Mode mode = OpenGLRenderer::getXfermodeDirect(mPaint);
+        SkXfermode::Mode mode = PaintUtils::getXfermodeDirect(mPaint);
         return (mode == SkXfermode::kSrcOver_Mode ||
                 mode == SkXfermode::kSrc_Mode);
 
@@ -249,8 +245,8 @@
 
     virtual bool getLocalBounds(Rect& localBounds) override {
         localBounds.set(mLocalBounds);
-        OpenGLRenderer::TextShadow textShadow;
-        if (OpenGLRenderer::getTextShadow(mPaint, &textShadow)) {
+        PaintUtils::TextShadow textShadow;
+        if (PaintUtils::getTextShadow(mPaint, &textShadow)) {
             Rect shadow(mLocalBounds);
             shadow.translate(textShadow.dx, textShadow.dx);
             shadow.outset(textShadow.radius);
@@ -372,8 +368,8 @@
 
 private:
     bool isSaveLayerAlpha() const {
-        SkXfermode::Mode mode = OpenGLRenderer::getXfermodeDirect(mPaint);
-        int alpha = OpenGLRenderer::getAlphaDirect(mPaint);
+        SkXfermode::Mode mode = PaintUtils::getXfermodeDirect(mPaint);
+        int alpha = PaintUtils::getAlphaDirect(mPaint);
         return alpha < 255 && mode == SkXfermode::kSrcOver_Mode;
     }
 
@@ -691,7 +687,7 @@
         // TODO: support clipped bitmaps by handling them in SET_TEXTURE
         deferInfo.mergeable = state.mMatrix.isSimple() && state.mMatrix.positiveScale() &&
                 !state.mClipSideFlags &&
-                OpenGLRenderer::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode &&
+                PaintUtils::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode &&
                 (mBitmap->colorType() != kAlpha_8_SkColorType);
     }
 
@@ -895,7 +891,7 @@
         deferInfo.batchId = DeferredDisplayList::kOpBatch_Patch;
         deferInfo.mergeId = getAtlasEntry(renderer) ? (mergeid_t) mEntry->getMergeId() : (mergeid_t) mBitmap;
         deferInfo.mergeable = state.mMatrix.isPureTranslate() &&
-                OpenGLRenderer::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode;
+                PaintUtils::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode;
         deferInfo.opaqueOverBounds = isOpaqueOverBounds(state) && mBitmap->isOpaque();
     }
 
@@ -1241,7 +1237,7 @@
     }
 
     virtual bool hasTextShadow() const override {
-        return OpenGLRenderer::hasTextShadow(mPaint);
+        return PaintUtils::hasTextShadow(mPaint);
     }
 
     virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
@@ -1330,7 +1326,7 @@
 
         deferInfo.mergeable = state.mMatrix.isPureTranslate()
                 && !hasDecorations
-                && OpenGLRenderer::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode;
+                && PaintUtils::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode;
     }
 
     virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 4b9d4f9..ccf0b48 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -667,14 +667,6 @@
     return mDrawn;
 }
 
-void FontRenderer::removeFont(const Font* font) {
-    mActiveFonts.remove(font->getDescription());
-
-    if (mCurrentFont == font) {
-        mCurrentFont = nullptr;
-    }
-}
-
 void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, float radius) {
     uint32_t intRadius = Blur::convertRadiusToInt(radius);
 #ifdef ANDROID_ENABLE_RENDERSCRIPT
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index 936c838..8172312 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -147,8 +147,6 @@
             float x3, float y3, float u3, float v3,
             float x4, float y4, float u4, float v4, CacheTexture* texture);
 
-    void removeFont(const Font* font);
-
     void checkTextureUpdate();
 
     void setTextureDirty() {
diff --git a/libs/hwui/Glop.h b/libs/hwui/Glop.h
index fa20b08..4785ea4 100644
--- a/libs/hwui/Glop.h
+++ b/libs/hwui/Glop.h
@@ -135,10 +135,6 @@
     } fill;
 
     struct Transform {
-        // Orthographic projection matrix for current FBO
-        // TODO: move out of Glop, since this is static per FBO
-        Matrix4 ortho;
-
         // modelView transform, accounting for delta between mesh transform and content of the mesh
         // often represents x/y offsets within command, or scaling for mesh unit size
         Matrix4 modelView;
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
index 69559a7..fa166ae 100644
--- a/libs/hwui/GlopBuilder.cpp
+++ b/libs/hwui/GlopBuilder.cpp
@@ -461,11 +461,10 @@
 // Transform
 ////////////////////////////////////////////////////////////////////////////////
 
-void GlopBuilder::setTransform(const Matrix4& ortho, const Matrix4& canvas,
+void GlopBuilder::setTransform(const Matrix4& canvas,
         const int transformFlags) {
     TRIGGER_STAGE(kTransformStage);
 
-    mOutGlop->transform.ortho = ortho;
     mOutGlop->transform.canvas = canvas;
     mOutGlop->transform.transformFlags = transformFlags;
 }
diff --git a/libs/hwui/GlopBuilder.h b/libs/hwui/GlopBuilder.h
index 549bb21..8d05570 100644
--- a/libs/hwui/GlopBuilder.h
+++ b/libs/hwui/GlopBuilder.h
@@ -71,7 +71,7 @@
     GlopBuilder& setFillTextureLayer(Layer& layer, float alpha);
 
     GlopBuilder& setTransform(const Snapshot& snapshot, const int transformFlags) {
-        setTransform(snapshot.getOrthoMatrix(), *snapshot.transform, transformFlags);
+        setTransform(*snapshot.transform, transformFlags);
         return *this;
     }
 
@@ -102,8 +102,7 @@
     void setFill(int color, float alphaScale,
             SkXfermode::Mode mode, Blend::ModeOrderSwap modeUsage,
             const SkShader* shader, const SkColorFilter* colorFilter);
-    void setTransform(const Matrix4& ortho, const Matrix4& canvas,
-            const int transformFlags);
+    void setTransform(const Matrix4& canvas, const int transformFlags);
 
     enum StageFlags {
         kInitialStage = 0,
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 8d85289..f99d92b 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -170,7 +170,8 @@
 }
 
 void Layer::setPaint(const SkPaint* paint) {
-    OpenGLRenderer::getAlphaAndModeDirect(paint, &alpha, &mode);
+    alpha = PaintUtils::getAlphaDirect(paint);
+    mode = PaintUtils::getXfermodeDirect(paint);
     setColorFilter((paint) ? paint->getColorFilter() : nullptr);
 }
 
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index a401ce1..9f24e37 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -540,7 +540,7 @@
         Rect bounds(left, top, right, bottom);
         Rect clip;
         calculateLayerBoundsAndClip(bounds, clip, true);
-        updateSnapshotIgnoreForLayer(bounds, clip, true, getAlphaDirect(paint));
+        updateSnapshotIgnoreForLayer(bounds, clip, true, PaintUtils::getAlphaDirect(paint));
 
         if (!mState.currentlyIgnored()) {
             writableSnapshot()->resetTransform(-bounds.left, -bounds.top, 0.0f);
@@ -615,7 +615,7 @@
     Rect clip;
     Rect bounds(left, top, right, bottom);
     calculateLayerBoundsAndClip(bounds, clip, fboLayer);
-    updateSnapshotIgnoreForLayer(bounds, clip, fboLayer, getAlphaDirect(paint));
+    updateSnapshotIgnoreForLayer(bounds, clip, fboLayer, PaintUtils::getAlphaDirect(paint));
 
     // Bail out if we won't draw in this snapshot
     if (mState.currentlyIgnored()) {
@@ -1405,7 +1405,7 @@
 
         setStencilFromClip();
     }
-    mRenderState.render(glop);
+    mRenderState.render(glop, currentSnapshot()->getOrthoMatrix());
     if (type == GlopRenderType::Standard && !mRenderState.stencil().isWriteEnabled()) {
         // TODO: specify more clearly when a draw should dirty the layer.
         // is writing to the stencil the only time we should ignore this?
@@ -1431,10 +1431,7 @@
             return;
         }
 
-        // Don't avoid overdraw when visualizing, since that makes it harder to
-        // debug where it's coming from, and when the problem occurs.
-        bool avoidOverdraw = !Properties::debugOverdraw;
-        DeferredDisplayList deferredList(mState.currentClipRect(), avoidOverdraw);
+        DeferredDisplayList deferredList(mState.currentClipRect());
         DeferStateStruct deferStruct(deferredList, *this, replayFlags);
         renderNode->defer(deferStruct, 0);
 
@@ -1958,8 +1955,8 @@
         FontRenderer& fontRenderer, int alpha, float x, float y) {
     mCaches.textureState().activateTexture(0);
 
-    TextShadow textShadow;
-    if (!getTextShadow(paint, &textShadow)) {
+    PaintUtils::TextShadow textShadow;
+    if (!PaintUtils::getTextShadow(paint, &textShadow)) {
         LOG_ALWAYS_FATAL("failed to query shadow attributes");
     }
 
@@ -1987,8 +1984,10 @@
     renderGlop(glop);
 }
 
+// TODO: remove this, once mState.currentlyIgnored captures snapshot alpha
 bool OpenGLRenderer::canSkipText(const SkPaint* paint) const {
-    float alpha = (hasTextShadow(paint) ? 1.0f : paint->getAlpha()) * currentSnapshot()->alpha;
+    float alpha = (PaintUtils::hasTextShadow(paint)
+            ? 1.0f : paint->getAlpha()) * currentSnapshot()->alpha;
     return MathUtils::isZero(alpha)
             && PaintUtils::getXfermode(paint->getXfermode()) == SkXfermode::kSrcOver_Mode;
 }
@@ -2017,11 +2016,10 @@
     FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer();
     fontRenderer.setFont(paint, SkMatrix::I());
 
-    int alpha;
-    SkXfermode::Mode mode;
-    getAlphaAndMode(paint, &alpha, &mode);
+    int alpha = PaintUtils::getAlphaDirect(paint) * currentSnapshot()->alpha;
+    SkXfermode::Mode mode = PaintUtils::getXfermodeDirect(paint);
 
-    if (CC_UNLIKELY(hasTextShadow(paint))) {
+    if (CC_UNLIKELY(PaintUtils::hasTextShadow(paint))) {
         drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer,
                 alpha, 0.0f, 0.0f);
     }
@@ -2162,13 +2160,12 @@
         y = floorf(y + transform.getTranslateY() + 0.5f);
     }
 
-    int alpha;
-    SkXfermode::Mode mode;
-    getAlphaAndMode(paint, &alpha, &mode);
+    int alpha = PaintUtils::getAlphaDirect(paint) * currentSnapshot()->alpha;
+    SkXfermode::Mode mode = PaintUtils::getXfermodeDirect(paint);
 
     FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer();
 
-    if (CC_UNLIKELY(hasTextShadow(paint))) {
+    if (CC_UNLIKELY(PaintUtils::hasTextShadow(paint))) {
         fontRenderer.setFont(paint, SkMatrix::I());
         drawTextShadow(paint, text, bytesCount, count, positions, fontRenderer,
                 alpha, oldX, oldY);
@@ -2238,9 +2235,8 @@
     fontRenderer.setFont(paint, SkMatrix::I());
     fontRenderer.setTextureFiltering(true);
 
-    int alpha;
-    SkXfermode::Mode mode;
-    getAlphaAndMode(paint, &alpha, &mode);
+    int alpha = PaintUtils::getAlphaDirect(paint) * currentSnapshot()->alpha;
+    SkXfermode::Mode mode = PaintUtils::getXfermodeDirect(paint);
     TextDrawFunctor functor(this, 0.0f, 0.0f, false, alpha, mode, paint);
 
     const Rect* clip = &writableSnapshot()->getLocalClip();
@@ -2530,12 +2526,6 @@
     renderGlop(glop);
 }
 
-void OpenGLRenderer::getAlphaAndMode(const SkPaint* paint, int* alpha,
-        SkXfermode::Mode* mode) const {
-    getAlphaAndModeDirect(paint, alpha,  mode);
-    *alpha *= currentSnapshot()->alpha;
-}
-
 float OpenGLRenderer::getLayerAlpha(const Layer* layer) const {
     return (layer->getAlpha() / 255.0f) * currentSnapshot()->alpha;
 }
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 910af57..400c225 100755
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -260,57 +260,6 @@
     void endMark() const;
 
     /**
-     * Gets the alpha and xfermode out of a paint object. If the paint is null
-     * alpha will be 255 and the xfermode will be SRC_OVER. This method does
-     * not multiply the paint's alpha by the current snapshot's alpha, and does
-     * not replace the alpha with the overrideLayerAlpha
-     *
-     * @param paint The paint to extract values from
-     * @param alpha Where to store the resulting alpha
-     * @param mode Where to store the resulting xfermode
-     */
-    static inline void getAlphaAndModeDirect(const SkPaint* paint, int* alpha,
-            SkXfermode::Mode* mode) {
-        *mode = getXfermodeDirect(paint);
-        *alpha = getAlphaDirect(paint);
-    }
-
-    static inline SkXfermode::Mode getXfermodeDirect(const SkPaint* paint) {
-        if (!paint) return SkXfermode::kSrcOver_Mode;
-        return PaintUtils::getXfermode(paint->getXfermode());
-    }
-
-    static inline int getAlphaDirect(const SkPaint* paint) {
-        if (!paint) return 255;
-        return paint->getAlpha();
-    }
-
-    struct TextShadow {
-        SkScalar radius;
-        float dx;
-        float dy;
-        SkColor color;
-    };
-
-    static inline bool getTextShadow(const SkPaint* paint, TextShadow* textShadow) {
-        SkDrawLooper::BlurShadowRec blur;
-        if (paint && paint->getLooper() && paint->getLooper()->asABlurShadow(&blur)) {
-            if (textShadow) {
-                textShadow->radius = Blur::convertSigmaToRadius(blur.fSigma);
-                textShadow->dx = blur.fOffset.fX;
-                textShadow->dy = blur.fOffset.fY;
-                textShadow->color = blur.fColor;
-            }
-            return true;
-        }
-        return false;
-    }
-
-    static inline bool hasTextShadow(const SkPaint* paint) {
-        return getTextShadow(paint, nullptr);
-    }
-
-    /**
      * Build the best transform to use to rasterize text given a full
      * transform matrix, and whether filteration is needed.
      *
@@ -493,16 +442,6 @@
     void drawTextureLayer(Layer* layer, const Rect& rect);
 
     /**
-     * Gets the alpha and xfermode out of a paint object. If the paint is null
-     * alpha will be 255 and the xfermode will be SRC_OVER. Accounts for snapshot alpha.
-     *
-     * @param paint The paint to extract values from
-     * @param alpha Where to store the resulting alpha
-     * @param mode Where to store the resulting xfermode
-     */
-    inline void getAlphaAndMode(const SkPaint* paint, int* alpha, SkXfermode::Mode* mode) const;
-
-    /**
      * Gets the alpha from a layer, accounting for snapshot alpha
      *
      * @param layer The layer from which the alpha is extracted
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index ddc7ecd..bf1b4d0 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -725,7 +725,9 @@
 void RenderNode::issueDrawShadowOperation(const Matrix4& transformFromParent, T& handler) {
     if (properties().getAlpha() <= 0.0f
             || properties().getOutline().getAlpha() <= 0.0f
-            || !properties().getOutline().getPath()) {
+            || !properties().getOutline().getPath()
+            || properties().getScaleX() == 0
+            || properties().getScaleY() == 0) {
         // no shadow to draw
         return;
     }
@@ -915,7 +917,10 @@
     const bool useViewProperties = (!mLayer || drawLayer);
     if (useViewProperties) {
         const Outline& outline = properties().getOutline();
-        if (properties().getAlpha() <= 0 || (outline.getShouldClip() && outline.isEmpty())) {
+        if (properties().getAlpha() <= 0
+                || (outline.getShouldClip() && outline.isEmpty())
+                || properties().getScaleX() == 0
+                || properties().getScaleY() == 0) {
             DISPLAY_LIST_LOGD("%*sRejected display list (%p, %s)", handler.level() * 2, "",
                     this, getName());
             return;
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index ad74bff..ce1bd6a 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -52,11 +52,8 @@
 
 bool LayerProperties::setFromPaint(const SkPaint* paint) {
     bool changed = false;
-    SkXfermode::Mode mode;
-    int alpha;
-    OpenGLRenderer::getAlphaAndModeDirect(paint, &alpha, &mode);
-    changed |= setAlpha(static_cast<uint8_t>(alpha));
-    changed |= setXferMode(mode);
+    changed |= setAlpha(static_cast<uint8_t>(PaintUtils::getAlphaDirect(paint)));
+    changed |= setXferMode(PaintUtils::getXfermodeDirect(paint));
     changed |= setColorFilter(paint ? paint->getColorFilter() : nullptr);
     return changed;
 }
diff --git a/libs/hwui/ShadowTessellator.cpp b/libs/hwui/ShadowTessellator.cpp
index 2209365..eb0fa74 100644
--- a/libs/hwui/ShadowTessellator.cpp
+++ b/libs/hwui/ShadowTessellator.cpp
@@ -73,8 +73,8 @@
     }
 
 #if DEBUG_SHADOW
-    ALOGD("light center %f %f %f",
-            adjustedLightCenter.x, adjustedLightCenter.y, adjustedLightCenter.z);
+    ALOGD("light center %f %f %f %d",
+            adjustedLightCenter.x, adjustedLightCenter.y, adjustedLightCenter.z, lightRadius);
 #endif
 
     // light position (because it's in local space) needs to compensate for receiver transform
diff --git a/libs/hwui/SpotShadow.cpp b/libs/hwui/SpotShadow.cpp
index 9b0a1aa..bdce73c 100644
--- a/libs/hwui/SpotShadow.cpp
+++ b/libs/hwui/SpotShadow.cpp
@@ -1051,7 +1051,7 @@
  */
 void SpotShadow::dumpPolygon(const Vector3* poly, int polyLength, const char* polyName) {
     for (int i = 0; i < polyLength; i++) {
-        ALOGD("polygon %s i %d x %f y %f", polyName, i, poly[i].x, poly[i].y);
+        ALOGD("polygon %s i %d x %f y %f z %f", polyName, i, poly[i].x, poly[i].y, poly[i].z);
     }
 }
 
diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp
index fb0753b..d680f99 100644
--- a/libs/hwui/font/Font.cpp
+++ b/libs/hwui/font/Font.cpp
@@ -61,8 +61,6 @@
 }
 
 Font::~Font() {
-    mState->removeFont(this);
-
     for (uint32_t i = 0; i < mCachedGlyphs.size(); i++) {
         delete mCachedGlyphs.valueAt(i);
     }
diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp
index c5126de..dfa70ac 100644
--- a/libs/hwui/renderstate/RenderState.cpp
+++ b/libs/hwui/renderstate/RenderState.cpp
@@ -208,7 +208,7 @@
 // Render
 ///////////////////////////////////////////////////////////////////////////////
 
-void RenderState::render(const Glop& glop) {
+void RenderState::render(const Glop& glop, const Matrix4& orthoMatrix) {
     const Glop::Mesh& mesh = glop.mesh;
     const Glop::Mesh::Vertices& vertices = mesh.vertices;
     const Glop::Mesh::Indices& indices = mesh.indices;
@@ -223,7 +223,7 @@
         fill.program->setColor(fill.color);
     }
 
-    fill.program->set(glop.transform.ortho,
+    fill.program->set(orthoMatrix,
             glop.transform.modelView,
             glop.transform.meshTransform(),
             glop.transform.transformFlags & TransformFlags::OffsetByFudgeFactor);
diff --git a/libs/hwui/renderstate/RenderState.h b/libs/hwui/renderstate/RenderState.h
index 4fd792c..9ae0845 100644
--- a/libs/hwui/renderstate/RenderState.h
+++ b/libs/hwui/renderstate/RenderState.h
@@ -84,7 +84,7 @@
     // more thinking...
     void postDecStrong(VirtualLightRefBase* object);
 
-    void render(const Glop& glop);
+    void render(const Glop& glop, const Matrix4& orthoMatrix);
 
     AssetAtlas& assetAtlas() { return mAssetAtlas; }
     Blend& blend() { return *mBlend; }
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 9dc5b45..ddfd621 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -62,7 +62,7 @@
         , mAnimationContext(contextFactory->createAnimationContext(mRenderThread.timeLord()))
         , mJankTracker(thread.timeLord().frameIntervalNanos())
         , mProfiler(mFrames)
-        , mContentOverdrawProtectionBounds(0, 0, 0, 0) {
+        , mContentDrawBounds(0, 0, 0, 0) {
     mRenderNodes.emplace_back(rootRenderNode);
     mRenderThread.renderState().registerCanvasContext(this);
     mProfiler.setDensity(mRenderThread.mainDisplayInfo().density);
@@ -309,7 +309,7 @@
     Rect outBounds;
     // It there are multiple render nodes, they are as follows:
     // #0 - backdrop
-    // #1 - content (with - and clipped to - bounds mContentOverdrawProtectionBounds)
+    // #1 - content (positioned at (0,0) and clipped to - its bounds mContentDrawBounds)
     // #2 - frame
     // Usually the backdrop cannot be seen since it will be entirely covered by the content. While
     // resizing however it might become partially visible. The following render loop will crop the
@@ -317,66 +317,72 @@
     // against the backdrop (since that indicates a shrinking of the window) and then the frame
     // around everything.
     // The bounds of the backdrop against which the content should be clipped.
-    Rect backdropBounds = mContentOverdrawProtectionBounds;
+    Rect backdropBounds = mContentDrawBounds;
+    // Usually the contents bounds should be mContentDrawBounds - however - we will
+    // move it towards the fixed edge to give it a more stable appearance (for the moment).
+    Rect contentBounds;
     // If there is no content bounds we ignore the layering as stated above and start with 2.
-    int layer = mContentOverdrawProtectionBounds.isEmpty() ? 2 : 0;
+    int layer = (mContentDrawBounds.isEmpty() || mRenderNodes.size() <= 2) ? 2 : 0;
     // Draw all render nodes. Note that
     for (const sp<RenderNode>& node : mRenderNodes) {
         if (layer == 0) { // Backdrop.
-            // Draw the backdrop clipped to the inverse content bounds.
+            // Draw the backdrop clipped to the inverse content bounds, but assume that the content
+            // was moved to the upper left corner.
             const RenderProperties& properties = node->properties();
             Rect targetBounds(properties.getLeft(), properties.getTop(),
                               properties.getRight(), properties.getBottom());
+            // Move the content bounds towards the fixed corner of the backdrop.
+            const int x = targetBounds.left;
+            const int y = targetBounds.top;
+            contentBounds.set(x, y, x + mContentDrawBounds.getWidth(),
+                                    y + mContentDrawBounds.getHeight());
             // Remember the intersection of the target bounds and the intersection bounds against
             // which we have to crop the content.
+            backdropBounds.set(x, y, x + backdropBounds.getWidth(), y + backdropBounds.getHeight());
             backdropBounds.intersect(targetBounds);
             // Check if we have to draw something on the left side ...
-            if (targetBounds.left < mContentOverdrawProtectionBounds.left) {
+            if (targetBounds.left < contentBounds.left) {
                 mCanvas->save(SkCanvas::kClip_SaveFlag);
                 if (mCanvas->clipRect(targetBounds.left, targetBounds.top,
-                                      mContentOverdrawProtectionBounds.left, targetBounds.bottom,
+                                      contentBounds.left, targetBounds.bottom,
                                       SkRegion::kIntersect_Op)) {
                     mCanvas->drawRenderNode(node.get(), outBounds);
                 }
                 // Reduce the target area by the area we have just painted.
-                targetBounds.left = std::min(mContentOverdrawProtectionBounds.left,
-                                             targetBounds.right);
+                targetBounds.left = std::min(contentBounds.left, targetBounds.right);
                 mCanvas->restore();
             }
             // ... or on the right side ...
-            if (targetBounds.right > mContentOverdrawProtectionBounds.right &&
+            if (targetBounds.right > contentBounds.right &&
                 !targetBounds.isEmpty()) {
                 mCanvas->save(SkCanvas::kClip_SaveFlag);
-                if (mCanvas->clipRect(mContentOverdrawProtectionBounds.right, targetBounds.top,
+                if (mCanvas->clipRect(contentBounds.right, targetBounds.top,
                                       targetBounds.right, targetBounds.bottom,
                                       SkRegion::kIntersect_Op)) {
                     mCanvas->drawRenderNode(node.get(), outBounds);
                 }
                 // Reduce the target area by the area we have just painted.
-                targetBounds.right = std::max(targetBounds.left,
-                                              mContentOverdrawProtectionBounds.right);
+                targetBounds.right = std::max(targetBounds.left, contentBounds.right);
                 mCanvas->restore();
             }
             // ... or at the top ...
-            if (targetBounds.top < mContentOverdrawProtectionBounds.top &&
+            if (targetBounds.top < contentBounds.top &&
                 !targetBounds.isEmpty()) {
                 mCanvas->save(SkCanvas::kClip_SaveFlag);
                 if (mCanvas->clipRect(targetBounds.left, targetBounds.top, targetBounds.right,
-                                      mContentOverdrawProtectionBounds.top,
+                                      contentBounds.top,
                                       SkRegion::kIntersect_Op)) {
                     mCanvas->drawRenderNode(node.get(), outBounds);
                 }
                 // Reduce the target area by the area we have just painted.
-                targetBounds.top = std::min(mContentOverdrawProtectionBounds.top,
-                                            targetBounds.bottom);
+                targetBounds.top = std::min(contentBounds.top, targetBounds.bottom);
                 mCanvas->restore();
             }
             // ... or at the bottom.
-            if (targetBounds.bottom > mContentOverdrawProtectionBounds.bottom &&
+            if (targetBounds.bottom > contentBounds.bottom &&
                 !targetBounds.isEmpty()) {
                 mCanvas->save(SkCanvas::kClip_SaveFlag);
-                if (mCanvas->clipRect(targetBounds.left,
-                                      mContentOverdrawProtectionBounds.bottom, targetBounds.right,
+                if (mCanvas->clipRect(targetBounds.left, contentBounds.bottom, targetBounds.right,
                                       targetBounds.bottom, SkRegion::kIntersect_Op)) {
                     mCanvas->drawRenderNode(node.get(), outBounds);
                 }
@@ -384,10 +390,17 @@
             }
         } else if (layer == 1) { // Content
             // It gets cropped against the bounds of the backdrop to stay inside.
-            mCanvas->save(SkCanvas::kClip_SaveFlag);
-            if (mCanvas->clipRect(backdropBounds.left, backdropBounds.top,
-                                  backdropBounds.right, backdropBounds.bottom,
-                                  SkRegion::kIntersect_Op)) {
+            mCanvas->save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
+
+            // We shift and clip the content to match its final location in the window.
+            const float left = mContentDrawBounds.left;
+            const float top = mContentDrawBounds.top;
+            const float dx = backdropBounds.left - left;
+            const float dy = backdropBounds.top - top;
+            const float width = backdropBounds.getWidth();
+            const float height = backdropBounds.getHeight();
+            mCanvas->translate(dx, dy);
+            if (mCanvas->clipRect(left, top, left + width, top + height, SkRegion::kIntersect_Op)) {
                 mCanvas->drawRenderNode(node.get(), outBounds);
             }
             mCanvas->restore();
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 1c3845c..e0cbabd 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -126,8 +126,8 @@
                 mRenderNodes.end());
     }
 
-    void setContentOverdrawProtectionBounds(int left, int top, int right, int bottom) {
-        mContentOverdrawProtectionBounds.set(left, top, right, bottom);
+    void setContentDrawBounds(int left, int top, int right, int bottom) {
+        mContentDrawBounds.set(left, top, right, bottom);
     }
 
 private:
@@ -167,7 +167,7 @@
     std::set<RenderNode*> mPrefetechedLayers;
 
     // Stores the bounds of the main content.
-    Rect mContentOverdrawProtectionBounds;
+    Rect mContentDrawBounds;
 };
 
 } /* namespace renderthread */
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index f43a769..26aae90 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -529,15 +529,14 @@
     staticPostAndWait(task);
 }
 
-CREATE_BRIDGE5(setContentOverdrawProtectionBounds, CanvasContext* context, int left, int top,
+CREATE_BRIDGE5(setContentDrawBounds, CanvasContext* context, int left, int top,
         int right, int bottom) {
-    args->context->setContentOverdrawProtectionBounds(args->left, args->top, args->right,
-                                                      args->bottom);
+    args->context->setContentDrawBounds(args->left, args->top, args->right, args->bottom);
     return nullptr;
 }
 
-void RenderProxy::setContentOverdrawProtectionBounds(int left, int top, int right, int bottom) {
-    SETUP_TASK(setContentOverdrawProtectionBounds);
+void RenderProxy::setContentDrawBounds(int left, int top, int right, int bottom) {
+    SETUP_TASK(setContentDrawBounds);
     args->context = mContext;
     args->left = left;
     args->top = top;
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 046f24a..d1b62f1 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -109,7 +109,7 @@
     ANDROID_API void addRenderNode(RenderNode* node, bool placeFront);
     ANDROID_API void removeRenderNode(RenderNode* node);
     ANDROID_API void drawRenderNode(RenderNode* node);
-    ANDROID_API void setContentOverdrawProtectionBounds(int left, int top, int right, int bottom);
+    ANDROID_API void setContentDrawBounds(int left, int top, int right, int bottom);
 
 private:
     RenderThread& mRenderThread;
diff --git a/libs/hwui/utils/PaintUtils.h b/libs/hwui/utils/PaintUtils.h
index ba02f5f..d00236e 100644
--- a/libs/hwui/utils/PaintUtils.h
+++ b/libs/hwui/utils/PaintUtils.h
@@ -16,12 +16,19 @@
 #ifndef PAINT_UTILS_H
 #define PAINT_UTILS_H
 
+#include <utils/Blur.h>
+
 #include <SkColorFilter.h>
+#include <SkDrawLooper.h>
 #include <SkXfermode.h>
 
 namespace android {
 namespace uirenderer {
 
+/**
+ * Utility methods for accessing data within SkPaint, and providing defaults
+ * with optional SkPaint pointers.
+ */
 class PaintUtils {
 public:
 
@@ -73,6 +80,39 @@
         return (filter->getFlags() & SkColorFilter::kAlphaUnchanged_Flag) == 0;
     }
 
+    struct TextShadow {
+        SkScalar radius;
+        float dx;
+        float dy;
+        SkColor color;
+    };
+
+    static inline bool getTextShadow(const SkPaint* paint, TextShadow* textShadow) {
+        SkDrawLooper::BlurShadowRec blur;
+        if (paint && paint->getLooper() && paint->getLooper()->asABlurShadow(&blur)) {
+            if (textShadow) {
+                textShadow->radius = Blur::convertSigmaToRadius(blur.fSigma);
+                textShadow->dx = blur.fOffset.fX;
+                textShadow->dy = blur.fOffset.fY;
+                textShadow->color = blur.fColor;
+            }
+            return true;
+        }
+        return false;
+    }
+
+    static inline bool hasTextShadow(const SkPaint* paint) {
+        return getTextShadow(paint, nullptr);
+    }
+
+    static inline SkXfermode::Mode getXfermodeDirect(const SkPaint* paint) {
+        return paint ? getXfermode(paint->getXfermode()) : SkXfermode::kSrcOver_Mode;
+    }
+
+    static inline int getAlphaDirect(const SkPaint* paint) {
+        return paint ? paint->getAlpha() : 255;
+    }
+
 }; // class PaintUtils
 
 } /* namespace uirenderer */
diff --git a/media/java/android/media/Metadata.java b/media/java/android/media/Metadata.java
index 54ad60e..4b8f81e 100644
--- a/media/java/android/media/Metadata.java
+++ b/media/java/android/media/Metadata.java
@@ -18,6 +18,7 @@
 
 import android.os.Parcel;
 import android.util.Log;
+import android.util.MathUtils;
 
 import java.util.Calendar;
 import java.util.Collections;
@@ -332,7 +333,14 @@
             }
 
             // Skip to the next one.
-            parcel.setDataPosition(start + size);
+            try {
+                parcel.setDataPosition(MathUtils.addOrThrow(start, size));
+            } catch (IllegalArgumentException e) {
+                Log.e(TAG, "Invalid size: " + e.getMessage());
+                error = true;
+                break;
+            }
+
             bytesLeft -= size;
             ++recCount;
         }
diff --git a/packages/DocumentsUI/res/menu/activity.xml b/packages/DocumentsUI/res/menu/activity.xml
index 673a254..7e0649b 100644
--- a/packages/DocumentsUI/res/menu/activity.xml
+++ b/packages/DocumentsUI/res/menu/activity.xml
@@ -23,13 +23,6 @@
         android:actionViewClass="android.widget.SearchView"
         android:imeOptions="actionSearch" />
     <item
-        android:id="@+id/menu_create_dir"
-        android:title="@string/menu_create_dir"
-        android:icon="@drawable/ic_menu_new_folder"
-        android:alphabeticShortcut="e"
-        android:showAsAction="always"
-        android:visible="false" />
-    <item
         android:id="@+id/menu_sort"
         android:title="@string/menu_sort"
         android:icon="@drawable/ic_menu_sortby"
@@ -63,6 +56,13 @@
         android:showAsAction="never"
         android:visible="false" />
     <item
+        android:id="@+id/menu_create_dir"
+        android:title="@string/menu_create_dir"
+        android:icon="@drawable/ic_menu_new_folder"
+        android:alphabeticShortcut="e"
+        android:showAsAction="always"
+        android:visible="false" />
+    <item
         android:id="@+id/menu_paste_from_clipboard"
         android:title="@string/menu_paste_from_clipboard"
         android:alphabeticShortcut="v"
@@ -70,11 +70,11 @@
         android:visible="false" />
     <!-- Copy action is defined in mode_directory.xml -->
     <item
-        android:id="@+id/menu_advanced"
+        android:id="@+id/menu_file_size"
         android:showAsAction="never"
         android:visible="false" />
     <item
-        android:id="@+id/menu_file_size"
+        android:id="@+id/menu_advanced"
         android:showAsAction="never"
         android:visible="false" />
     <item
diff --git a/packages/DocumentsUI/res/values-af/strings.xml b/packages/DocumentsUI/res/values-af/strings.xml
index c2b6dbc..ba92c00 100644
--- a/packages/DocumentsUI/res/values-af/strings.xml
+++ b/packages/DocumentsUI/res/values-af/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Lêers"</string>
     <string name="title_open" msgid="4353228937663917801">"Maak oop vanuit"</string>
     <string name="title_save" msgid="2433679664882857999">"Stoor na"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Skep vouer"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Roosteraansig"</string>
     <string name="menu_list" msgid="7279285939892417279">"Lysaansig"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Sorteer volgens"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Kies alles"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Kopieer na …"</string>
     <string name="menu_move" msgid="1828090633118079817">"Skuif na …"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Nuwe venster"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopieer"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Plak"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Wys interne berging"</string>
diff --git a/packages/DocumentsUI/res/values-am/strings.xml b/packages/DocumentsUI/res/values-am/strings.xml
index b82fa93..7fb3b74 100644
--- a/packages/DocumentsUI/res/values-am/strings.xml
+++ b/packages/DocumentsUI/res/values-am/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"ፋይሎች"</string>
     <string name="title_open" msgid="4353228937663917801">"ክፈት ከ"</string>
     <string name="title_save" msgid="2433679664882857999">"አስቀምጥ ወደ"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"አቃፊ ፍጠር"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"የፍርግርግ እይታ"</string>
     <string name="menu_list" msgid="7279285939892417279">"የዝርዝር እይታ"</string>
     <string name="menu_sort" msgid="7677740407158414452">"ደርድር በ"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"ሁሉንም ምረጥ"</string>
     <string name="menu_copy" msgid="3612326052677229148">"ቅዳ ወደ…"</string>
     <string name="menu_move" msgid="1828090633118079817">"ይውሰዱ ወደ..."</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"አዲሰ መስኮት"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"ቅዳ"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"ለጥፍ"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"ውስጣዊ ማከማቻ አሳይ"</string>
diff --git a/packages/DocumentsUI/res/values-ar/strings.xml b/packages/DocumentsUI/res/values-ar/strings.xml
index c7c9ef2..b61d190 100644
--- a/packages/DocumentsUI/res/values-ar/strings.xml
+++ b/packages/DocumentsUI/res/values-ar/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"الملفات"</string>
     <string name="title_open" msgid="4353228937663917801">"فتح من"</string>
     <string name="title_save" msgid="2433679664882857999">"حفظ في"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"إنشاء مجلد"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"عرض الشبكة"</string>
     <string name="menu_list" msgid="7279285939892417279">"عرض القائمة"</string>
     <string name="menu_sort" msgid="7677740407158414452">"ترتيب بحسب"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"تحديد الكل"</string>
     <string name="menu_copy" msgid="3612326052677229148">"نسخ إلى…"</string>
     <string name="menu_move" msgid="1828090633118079817">"نقل إلى..."</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"نافذة جديدة"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"نسخ"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"لصق"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"إظهار وحدة التخزين الداخلية"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"نسخ"</string>
     <string name="button_move" msgid="2202666023104202232">"نقل"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"إزالة"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"إعادة المحاولة"</string>
     <string name="sort_name" msgid="9183560467917256779">"بحسب الاسم"</string>
     <string name="sort_date" msgid="586080032956151448">"بحسب تاريخ التعديل"</string>
     <string name="sort_size" msgid="3350681319735474741">"بحسب الحجم"</string>
diff --git a/packages/DocumentsUI/res/values-az-rAZ/strings.xml b/packages/DocumentsUI/res/values-az-rAZ/strings.xml
index 8c79ceb..dc3827e 100644
--- a/packages/DocumentsUI/res/values-az-rAZ/strings.xml
+++ b/packages/DocumentsUI/res/values-az-rAZ/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Fayllar"</string>
     <string name="title_open" msgid="4353228937663917801">"Vasitəsilə açın"</string>
     <string name="title_save" msgid="2433679664882857999">"buraya saxlayın"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Qovluq yaradın"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Torlu görünüş"</string>
     <string name="menu_list" msgid="7279285939892417279">"Siyahı görünüşü"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Bunlardan biri üzrə sırala"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Hamısını seçin"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Buraya kopyalayın:"</string>
     <string name="menu_move" msgid="1828090633118079817">"Köçürün…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Yeni pəncərə"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopyalayın"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Yerləşdirin"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Daxili yaddaşı göstərin"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"Kopyala"</string>
     <string name="button_move" msgid="2202666023104202232">"Köçürün"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"Rədd edin"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"Yenidən cəhd edin"</string>
     <string name="sort_name" msgid="9183560467917256779">"Ad üzrə"</string>
     <string name="sort_date" msgid="586080032956151448">"Tarix üzrə dəyişmiş"</string>
     <string name="sort_size" msgid="3350681319735474741">"Ölçü üzrə"</string>
diff --git a/packages/DocumentsUI/res/values-bg/strings.xml b/packages/DocumentsUI/res/values-bg/strings.xml
index fdf57d0..e8c5822 100644
--- a/packages/DocumentsUI/res/values-bg/strings.xml
+++ b/packages/DocumentsUI/res/values-bg/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Файлове"</string>
     <string name="title_open" msgid="4353228937663917801">"Отваряне от"</string>
     <string name="title_save" msgid="2433679664882857999">"Запазване във:"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Създаване на папка"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Изглед в мрежа"</string>
     <string name="menu_list" msgid="7279285939892417279">"Списъчен изглед"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Сортиране по"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Избиране на всичко"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Копиране във…"</string>
     <string name="menu_move" msgid="1828090633118079817">"Преместване във…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Нов прозорец"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Копиране"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Поставяне"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Вътр. хранилище: Показв."</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"Копиране"</string>
     <string name="button_move" msgid="2202666023104202232">"Преместване"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"Отхвърляне"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"Нов опит"</string>
     <string name="sort_name" msgid="9183560467917256779">"По име"</string>
     <string name="sort_date" msgid="586080032956151448">"По дата на промяната"</string>
     <string name="sort_size" msgid="3350681319735474741">"По размер"</string>
diff --git a/packages/DocumentsUI/res/values-bn-rBD/strings.xml b/packages/DocumentsUI/res/values-bn-rBD/strings.xml
index 7caf57f..dc20b16 100644
--- a/packages/DocumentsUI/res/values-bn-rBD/strings.xml
+++ b/packages/DocumentsUI/res/values-bn-rBD/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"ফাইলগুলি"</string>
     <string name="title_open" msgid="4353228937663917801">"এখান থেকে খুলুন"</string>
     <string name="title_save" msgid="2433679664882857999">"এতে সংরক্ষণ করুন"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"ফোল্ডার তৈরি করুন"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"গ্রিড দৃশ্য"</string>
     <string name="menu_list" msgid="7279285939892417279">"তালিকা দৃশ্য"</string>
     <string name="menu_sort" msgid="7677740407158414452">"এই অনুসারে বাছুন"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"সবগুলি নির্বাচন করুন"</string>
     <string name="menu_copy" msgid="3612326052677229148">"এতে অনুলিপি করুন…"</string>
     <string name="menu_move" msgid="1828090633118079817">"এতে সরান..."</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"নতুন উইন্ডো"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"প্রতিলিপি করুন"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"আটকান"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"অভ্যন্তরীণ সঞ্চয়স্থান দেখান"</string>
diff --git a/packages/DocumentsUI/res/values-ca/strings.xml b/packages/DocumentsUI/res/values-ca/strings.xml
index ab365ce..ab90f1f 100644
--- a/packages/DocumentsUI/res/values-ca/strings.xml
+++ b/packages/DocumentsUI/res/values-ca/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Fitxers"</string>
     <string name="title_open" msgid="4353228937663917801">"Obre des de"</string>
     <string name="title_save" msgid="2433679664882857999">"Desa a"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Crea una carpeta"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Visualització de quadrícula"</string>
     <string name="menu_list" msgid="7279285939892417279">"Visualització de llista"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Ordena per"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Selecciona-ho tot"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Copia a…"</string>
     <string name="menu_move" msgid="1828090633118079817">"Mou a..."</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Finestra nova"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Copia"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Enganxa"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Mostra emmagatz. intern"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"Copia"</string>
     <string name="button_move" msgid="2202666023104202232">"Desplaça"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"Ignora"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"Torna-ho a provar"</string>
     <string name="sort_name" msgid="9183560467917256779">"Per nom"</string>
     <string name="sort_date" msgid="586080032956151448">"Per data de modificació"</string>
     <string name="sort_size" msgid="3350681319735474741">"Per mida"</string>
diff --git a/packages/DocumentsUI/res/values-cs/strings.xml b/packages/DocumentsUI/res/values-cs/strings.xml
index 62b313c..9b1b0c8 100644
--- a/packages/DocumentsUI/res/values-cs/strings.xml
+++ b/packages/DocumentsUI/res/values-cs/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Soubory"</string>
     <string name="title_open" msgid="4353228937663917801">"Otevřít"</string>
     <string name="title_save" msgid="2433679664882857999">"Uložit do"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Vytvořit složku"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Mřížkové zobrazení"</string>
     <string name="menu_list" msgid="7279285939892417279">"Zobrazení seznamu"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Řadit podle"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Vybrat vše"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Kopírovat do…"</string>
     <string name="menu_move" msgid="1828090633118079817">"Přesunout do…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Nové okno"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopírovat"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Vložit"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Zobrazit inter. úložiště"</string>
diff --git a/packages/DocumentsUI/res/values-da/strings.xml b/packages/DocumentsUI/res/values-da/strings.xml
index c3d7cdd..284d87e 100644
--- a/packages/DocumentsUI/res/values-da/strings.xml
+++ b/packages/DocumentsUI/res/values-da/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Filer"</string>
     <string name="title_open" msgid="4353228937663917801">"Åbn fra"</string>
     <string name="title_save" msgid="2433679664882857999">"Gem i"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Opret mappe"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Gittervisning"</string>
     <string name="menu_list" msgid="7279285939892417279">"Listevisning"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Sortér efter"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Markér alle"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Kopiér til…"</string>
     <string name="menu_move" msgid="1828090633118079817">"Flyt til…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Nyt vindue"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopiér"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Indsæt"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Vis intern lagerplads"</string>
diff --git a/packages/DocumentsUI/res/values-de/strings.xml b/packages/DocumentsUI/res/values-de/strings.xml
index f88b5c4..1fe53ff 100644
--- a/packages/DocumentsUI/res/values-de/strings.xml
+++ b/packages/DocumentsUI/res/values-de/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Dateien"</string>
     <string name="title_open" msgid="4353228937663917801">"Öffnen von"</string>
     <string name="title_save" msgid="2433679664882857999">"Speichern unter"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Ordner erstellen"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Rasteransicht"</string>
     <string name="menu_list" msgid="7279285939892417279">"Listenansicht"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Sortieren nach"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Alle auswählen"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Kopieren nach..."</string>
     <string name="menu_move" msgid="1828090633118079817">"Verschieben nach…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Neues Fenster"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopieren"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Einfügen"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Int. Speicher anzeigen"</string>
diff --git a/packages/DocumentsUI/res/values-el/strings.xml b/packages/DocumentsUI/res/values-el/strings.xml
index dcca46c..e9743ee 100644
--- a/packages/DocumentsUI/res/values-el/strings.xml
+++ b/packages/DocumentsUI/res/values-el/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Αρχεία"</string>
     <string name="title_open" msgid="4353228937663917801">"Άνοιγμα από"</string>
     <string name="title_save" msgid="2433679664882857999">"Αποθήκευση σε"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Δημιουργία φακέλου"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Προβολή πλέγματος"</string>
     <string name="menu_list" msgid="7279285939892417279">"Προβολή λίστας"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Ταξινόμηση κατά"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Επιλογή όλων"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Αντιγραφή σε…"</string>
     <string name="menu_move" msgid="1828090633118079817">"Μετακίνηση σε..."</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Νέο παράθυρο"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Αντιγραφή"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Επικόλληση"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Εμφ.εσωτ.χώρου αποθήκ."</string>
diff --git a/packages/DocumentsUI/res/values-en-rAU/strings.xml b/packages/DocumentsUI/res/values-en-rAU/strings.xml
index 26fd30f..03399e2 100644
--- a/packages/DocumentsUI/res/values-en-rAU/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rAU/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Files"</string>
     <string name="title_open" msgid="4353228937663917801">"Open from"</string>
     <string name="title_save" msgid="2433679664882857999">"Save to"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Create folder"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Grid view"</string>
     <string name="menu_list" msgid="7279285939892417279">"List view"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Sort by"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Select all"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Copy to…"</string>
     <string name="menu_move" msgid="1828090633118079817">"Move to…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"New window"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Copy"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Paste"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Show internal storage"</string>
diff --git a/packages/DocumentsUI/res/values-en-rGB/strings.xml b/packages/DocumentsUI/res/values-en-rGB/strings.xml
index 26fd30f..03399e2 100644
--- a/packages/DocumentsUI/res/values-en-rGB/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rGB/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Files"</string>
     <string name="title_open" msgid="4353228937663917801">"Open from"</string>
     <string name="title_save" msgid="2433679664882857999">"Save to"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Create folder"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Grid view"</string>
     <string name="menu_list" msgid="7279285939892417279">"List view"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Sort by"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Select all"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Copy to…"</string>
     <string name="menu_move" msgid="1828090633118079817">"Move to…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"New window"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Copy"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Paste"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Show internal storage"</string>
diff --git a/packages/DocumentsUI/res/values-en-rIN/strings.xml b/packages/DocumentsUI/res/values-en-rIN/strings.xml
index 26fd30f..03399e2 100644
--- a/packages/DocumentsUI/res/values-en-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rIN/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Files"</string>
     <string name="title_open" msgid="4353228937663917801">"Open from"</string>
     <string name="title_save" msgid="2433679664882857999">"Save to"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Create folder"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Grid view"</string>
     <string name="menu_list" msgid="7279285939892417279">"List view"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Sort by"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Select all"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Copy to…"</string>
     <string name="menu_move" msgid="1828090633118079817">"Move to…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"New window"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Copy"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Paste"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Show internal storage"</string>
diff --git a/packages/DocumentsUI/res/values-es-rUS/strings.xml b/packages/DocumentsUI/res/values-es-rUS/strings.xml
index 6e805b9..cc99d7f 100644
--- a/packages/DocumentsUI/res/values-es-rUS/strings.xml
+++ b/packages/DocumentsUI/res/values-es-rUS/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Archivos"</string>
     <string name="title_open" msgid="4353228937663917801">"Abrir desde"</string>
     <string name="title_save" msgid="2433679664882857999">"Guardar en"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Crear carpeta"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Vista de cuadrícula"</string>
     <string name="menu_list" msgid="7279285939892417279">"Vista de lista"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Ordenar por"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Seleccionar todo"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Copiar a…"</string>
     <string name="menu_move" msgid="1828090633118079817">"Mover a…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Ventana nueva"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Copiar"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Pegar"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Mostrar almacen. interno"</string>
diff --git a/packages/DocumentsUI/res/values-es/strings.xml b/packages/DocumentsUI/res/values-es/strings.xml
index 8fa1d2e..83403e0 100644
--- a/packages/DocumentsUI/res/values-es/strings.xml
+++ b/packages/DocumentsUI/res/values-es/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Archivos"</string>
     <string name="title_open" msgid="4353228937663917801">"Abrir desde"</string>
     <string name="title_save" msgid="2433679664882857999">"Guardar en"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Crear carpeta"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Vista de cuadrícula"</string>
     <string name="menu_list" msgid="7279285939892417279">"Vista de lista"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Ordenar por"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Seleccionar todo"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Copiar en…"</string>
     <string name="menu_move" msgid="1828090633118079817">"Mover a…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Nueva ventana"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Copiar"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Pegar"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Mostrar almac. interno"</string>
diff --git a/packages/DocumentsUI/res/values-et-rEE/strings.xml b/packages/DocumentsUI/res/values-et-rEE/strings.xml
index 7008885..b38fcd99 100644
--- a/packages/DocumentsUI/res/values-et-rEE/strings.xml
+++ b/packages/DocumentsUI/res/values-et-rEE/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Failid"</string>
     <string name="title_open" msgid="4353228937663917801">"Ava:"</string>
     <string name="title_save" msgid="2433679664882857999">"Salvesta:"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Loo kaust"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Ruudustikkuva"</string>
     <string name="menu_list" msgid="7279285939892417279">"Loendikuva"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Sortimisalus:"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Vali kõik"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Kopeeri asukohta ..."</string>
     <string name="menu_move" msgid="1828090633118079817">"Teisaldamine kohta ..."</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Uus aken"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopeeri"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Kleebi"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Kuva sis. salvestusruum"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"Kopeeri"</string>
     <string name="button_move" msgid="2202666023104202232">"Teisalda"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"Loobu"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"Proovi uuesti"</string>
     <string name="sort_name" msgid="9183560467917256779">"Nime järgi"</string>
     <string name="sort_date" msgid="586080032956151448">"Muutmiskuupäeva järgi"</string>
     <string name="sort_size" msgid="3350681319735474741">"Suuruse järgi"</string>
diff --git a/packages/DocumentsUI/res/values-eu-rES/strings.xml b/packages/DocumentsUI/res/values-eu-rES/strings.xml
index 17d7c66..9939b1d 100644
--- a/packages/DocumentsUI/res/values-eu-rES/strings.xml
+++ b/packages/DocumentsUI/res/values-eu-rES/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Fitxategiak"</string>
     <string name="title_open" msgid="4353228937663917801">"Ireki hemendik"</string>
     <string name="title_save" msgid="2433679664882857999">"Gorde hemen"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Sortu karpeta"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Sareta-ikuspegia"</string>
     <string name="menu_list" msgid="7279285939892417279">"Zerrenda-ikuspegia"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Ordenatzeko irizpidea"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Hautatu guztiak"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Kopiatu hemen…"</string>
     <string name="menu_move" msgid="1828090633118079817">"Eraman hona…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Leiho berria"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopiatu"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Itsatsi"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Erakutsi barneko memoria"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"Kopiatu"</string>
     <string name="button_move" msgid="2202666023104202232">"Mugitu"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"Baztertu"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"Saiatu berriro"</string>
     <string name="sort_name" msgid="9183560467917256779">"Izenaren arabera"</string>
     <string name="sort_date" msgid="586080032956151448">"Aldatze-dataren arabera"</string>
     <string name="sort_size" msgid="3350681319735474741">"Tamainaren arabera"</string>
diff --git a/packages/DocumentsUI/res/values-fa/strings.xml b/packages/DocumentsUI/res/values-fa/strings.xml
index c4f6d58..297e4a1 100644
--- a/packages/DocumentsUI/res/values-fa/strings.xml
+++ b/packages/DocumentsUI/res/values-fa/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"فایل‌ها"</string>
     <string name="title_open" msgid="4353228937663917801">"باز کردن از"</string>
     <string name="title_save" msgid="2433679664882857999">"ذخیره در"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"ایجاد پوشه"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"نمای جدولی"</string>
     <string name="menu_list" msgid="7279285939892417279">"نمای فهرستی"</string>
     <string name="menu_sort" msgid="7677740407158414452">"مرتب‌سازی براساس"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"انتخاب همه"</string>
     <string name="menu_copy" msgid="3612326052677229148">"کپی در..."</string>
     <string name="menu_move" msgid="1828090633118079817">"انتقال به…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"پنجره جدید"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"کپی"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"جای‌گذاری"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"نمایش فضای ذخیره‌سازی داخلی"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"کپی"</string>
     <string name="button_move" msgid="2202666023104202232">"انتقال"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"نپذیرفتن"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"دوباره امتحان کنید"</string>
     <string name="sort_name" msgid="9183560467917256779">"براساس نام"</string>
     <string name="sort_date" msgid="586080032956151448">"براساس تاریخ اصلاح"</string>
     <string name="sort_size" msgid="3350681319735474741">"براساس اندازه"</string>
diff --git a/packages/DocumentsUI/res/values-fi/strings.xml b/packages/DocumentsUI/res/values-fi/strings.xml
index 3e87300..a4c742a 100644
--- a/packages/DocumentsUI/res/values-fi/strings.xml
+++ b/packages/DocumentsUI/res/values-fi/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Tiedostot"</string>
     <string name="title_open" msgid="4353228937663917801">"Avaa sijainnista"</string>
     <string name="title_save" msgid="2433679664882857999">"Tallenna kohteeseen"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Luo kansio"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Ruudukkonäkymä"</string>
     <string name="menu_list" msgid="7279285939892417279">"Luettelonäkymä"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Lajitteluperuste"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Valitse kaikki"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Kopioi kohteeseen…"</string>
     <string name="menu_move" msgid="1828090633118079817">"Siirrä kohteeseen…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Uusi ikkuna"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopioi"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Liitä"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Näytä sis. tallennustila"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"Kopioi"</string>
     <string name="button_move" msgid="2202666023104202232">"Siirrä"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"Hylkää"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"Yritä uudelleen"</string>
     <string name="sort_name" msgid="9183560467917256779">"Nimen mukaan"</string>
     <string name="sort_date" msgid="586080032956151448">"Muokkauspäivän mukaan"</string>
     <string name="sort_size" msgid="3350681319735474741">"Koon mukaan"</string>
diff --git a/packages/DocumentsUI/res/values-fr-rCA/strings.xml b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
index 3e82f34..80cd0b2 100644
--- a/packages/DocumentsUI/res/values-fr-rCA/strings.xml
+++ b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Fichiers"</string>
     <string name="title_open" msgid="4353228937663917801">"Ouvrir à partir de"</string>
     <string name="title_save" msgid="2433679664882857999">"Enregistrer dans"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Créer un dossier"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Grille"</string>
     <string name="menu_list" msgid="7279285939892417279">"Liste"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Trier par"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Tout sélectionner"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Copier vers..."</string>
     <string name="menu_move" msgid="1828090633118079817">"Déplacer dans…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Nouvelle fenêtre"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Copier"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Coller"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Aff. mém. stock. interne"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"Copier"</string>
     <string name="button_move" msgid="2202666023104202232">"Déplacer"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"Faire disparaître"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"Réessayer"</string>
     <string name="sort_name" msgid="9183560467917256779">"Par nom"</string>
     <string name="sort_date" msgid="586080032956151448">"Par date de modification"</string>
     <string name="sort_size" msgid="3350681319735474741">"Par taille"</string>
diff --git a/packages/DocumentsUI/res/values-fr/strings.xml b/packages/DocumentsUI/res/values-fr/strings.xml
index 0512ab1..9616f63 100644
--- a/packages/DocumentsUI/res/values-fr/strings.xml
+++ b/packages/DocumentsUI/res/values-fr/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Fichiers"</string>
     <string name="title_open" msgid="4353228937663917801">"Ouvrir à partir de"</string>
     <string name="title_save" msgid="2433679664882857999">"Enregistrer sous"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Créer un dossier"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Grille"</string>
     <string name="menu_list" msgid="7279285939892417279">"Liste"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Trier par"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Tout sélectionner"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Copier vers…"</string>
     <string name="menu_move" msgid="1828090633118079817">"Placer dans…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Nouvelle fenêtre"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Copier"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Coller"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Aff. mém. stock. interne"</string>
diff --git a/packages/DocumentsUI/res/values-gl-rES/strings.xml b/packages/DocumentsUI/res/values-gl-rES/strings.xml
index a1cd614..aebf3a7 100644
--- a/packages/DocumentsUI/res/values-gl-rES/strings.xml
+++ b/packages/DocumentsUI/res/values-gl-rES/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Ficheiros"</string>
     <string name="title_open" msgid="4353228937663917801">"Abrir desde"</string>
     <string name="title_save" msgid="2433679664882857999">"Gardar en"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Crear cartafol"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Vista de grade"</string>
     <string name="menu_list" msgid="7279285939892417279">"Vista de lista"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Ordenar por"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Seleccionar todo"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Copiar en…"</string>
     <string name="menu_move" msgid="1828090633118079817">"Mover a…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Nova ventá"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Copiar"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Pegar"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Mostrar almacen. interno"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"Copiar"</string>
     <string name="button_move" msgid="2202666023104202232">"Mover"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"Ignorar"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"Tentar de novo"</string>
     <string name="sort_name" msgid="9183560467917256779">"Por nome"</string>
     <string name="sort_date" msgid="586080032956151448">"Por data de modificación"</string>
     <string name="sort_size" msgid="3350681319735474741">"Por tamaño"</string>
diff --git a/packages/DocumentsUI/res/values-gu-rIN/strings.xml b/packages/DocumentsUI/res/values-gu-rIN/strings.xml
index 059fb2c..9694afa 100644
--- a/packages/DocumentsUI/res/values-gu-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-gu-rIN/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"ફાઇલો"</string>
     <string name="title_open" msgid="4353228937663917801">"અહીંથી ખોલો"</string>
     <string name="title_save" msgid="2433679664882857999">"આમાં સાચવો"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"ફોલ્ડર બનાવો"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"ગ્રિડ દૃશ્ય"</string>
     <string name="menu_list" msgid="7279285939892417279">"સૂચિ દૃશ્ય"</string>
     <string name="menu_sort" msgid="7677740407158414452">"આ પ્રમાણે સૉર્ટ કરો"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"બધા પસંદ કરો"</string>
     <string name="menu_copy" msgid="3612326052677229148">"આના પર કૉપિ કરો…"</string>
     <string name="menu_move" msgid="1828090633118079817">"આમાં ખસેડો…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"નવી વિંડો"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"કૉપિ કરો"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"પેસ્ટ કરો"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"આંતરિક સ્ટોરેજ બતાવો"</string>
diff --git a/packages/DocumentsUI/res/values-hi/strings.xml b/packages/DocumentsUI/res/values-hi/strings.xml
index 8e33a00..3ee3d8b8 100644
--- a/packages/DocumentsUI/res/values-hi/strings.xml
+++ b/packages/DocumentsUI/res/values-hi/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"फ़ाइलें"</string>
     <string name="title_open" msgid="4353228937663917801">"यहां से खोलें"</string>
     <string name="title_save" msgid="2433679664882857999">"यहां सहेजें"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"फ़ोल्डर बनाएं"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"ग्रिड दृश्य"</string>
     <string name="menu_list" msgid="7279285939892417279">"सूची दृश्य"</string>
     <string name="menu_sort" msgid="7677740407158414452">"इससे क्रमित करें"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"सभी चुनें"</string>
     <string name="menu_copy" msgid="3612326052677229148">"इनकी कॉपी बनाएं..."</string>
     <string name="menu_move" msgid="1828090633118079817">"इसमें ले जाएं…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"नई विंडो"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"कॉपी करें"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"चिपकाएं"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"आंतरिक मेमोरी दिखाएं"</string>
diff --git a/packages/DocumentsUI/res/values-hr/strings.xml b/packages/DocumentsUI/res/values-hr/strings.xml
index 4774753..9d4393e 100644
--- a/packages/DocumentsUI/res/values-hr/strings.xml
+++ b/packages/DocumentsUI/res/values-hr/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Datoteke"</string>
     <string name="title_open" msgid="4353228937663917801">"Otvori iz"</string>
     <string name="title_save" msgid="2433679664882857999">"Spremi u"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Izradi mapu"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Prikaz rešetke"</string>
     <string name="menu_list" msgid="7279285939892417279">"Prikaz popisa"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Poredano po"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Odaberi sve"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Kopiraj u…"</string>
     <string name="menu_move" msgid="1828090633118079817">"Premjesti u…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Novi prozor"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopiraj"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Zalijepi"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Pokaži internu pohranu"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"Kopiraj"</string>
     <string name="button_move" msgid="2202666023104202232">"Premjesti"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"Odbaci"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"Pokušaj ponovo"</string>
     <string name="sort_name" msgid="9183560467917256779">"Po nazivu"</string>
     <string name="sort_date" msgid="586080032956151448">"Po datumu izmjene"</string>
     <string name="sort_size" msgid="3350681319735474741">"Po veličini"</string>
diff --git a/packages/DocumentsUI/res/values-hu/strings.xml b/packages/DocumentsUI/res/values-hu/strings.xml
index 7a521ec..18dcd70 100644
--- a/packages/DocumentsUI/res/values-hu/strings.xml
+++ b/packages/DocumentsUI/res/values-hu/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Fájlok"</string>
     <string name="title_open" msgid="4353228937663917801">"Megnyitás innen"</string>
     <string name="title_save" msgid="2433679664882857999">"Mentés ide"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Mappa létrehozása"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Rács"</string>
     <string name="menu_list" msgid="7279285939892417279">"Lista"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Rendezés"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Összes kijelölése"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Másolás ide…"</string>
     <string name="menu_move" msgid="1828090633118079817">"Áthelyezés…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Új ablak"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Másolás"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Beillesztés"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Belső tárhely"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"Másolás"</string>
     <string name="button_move" msgid="2202666023104202232">"Áthelyezés"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"Elvetés"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"Újrapróbálkozás"</string>
     <string name="sort_name" msgid="9183560467917256779">"Név szerint"</string>
     <string name="sort_date" msgid="586080032956151448">"Módosítás dátuma szerint"</string>
     <string name="sort_size" msgid="3350681319735474741">"Méret szerint"</string>
diff --git a/packages/DocumentsUI/res/values-hy-rAM/strings.xml b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
index 95d73f0..67d7f6a 100644
--- a/packages/DocumentsUI/res/values-hy-rAM/strings.xml
+++ b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Ֆայլեր"</string>
     <string name="title_open" msgid="4353228937663917801">"Բացել այստեղից"</string>
     <string name="title_save" msgid="2433679664882857999">"Պահել այստեղ"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Ստեղծել պանակ"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Ցանցի տեսքով"</string>
     <string name="menu_list" msgid="7279285939892417279">"Ցուցակի տեսք"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Դասավորել ըստ"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Ընտրել բոլորը"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Պատճենել…"</string>
     <string name="menu_move" msgid="1828090633118079817">"Տեղափոխում դեպի…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Նոր պատուհան"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Պատճենել"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Տեղադրել"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Ցույց տալ ներքին պահոցը"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"Պատճենել"</string>
     <string name="button_move" msgid="2202666023104202232">"Տեղափոխել"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"Փակել"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"Փորձել նորից"</string>
     <string name="sort_name" msgid="9183560467917256779">"Ըստ անվան"</string>
     <string name="sort_date" msgid="586080032956151448">"Ըստ փոփոխման ամսաթվի"</string>
     <string name="sort_size" msgid="3350681319735474741">"Ըստ չափի"</string>
diff --git a/packages/DocumentsUI/res/values-in/strings.xml b/packages/DocumentsUI/res/values-in/strings.xml
index 63d415c..a6f69bd 100644
--- a/packages/DocumentsUI/res/values-in/strings.xml
+++ b/packages/DocumentsUI/res/values-in/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"File"</string>
     <string name="title_open" msgid="4353228937663917801">"Buka dari"</string>
     <string name="title_save" msgid="2433679664882857999">"Simpan ke"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Buat folder"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Tampilan kisi"</string>
     <string name="menu_list" msgid="7279285939892417279">"Tampilan daftar"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Urutkan menurut"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Pilih semua"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Salin ke…"</string>
     <string name="menu_move" msgid="1828090633118079817">"Pindahkan ke..."</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Jendela baru"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Salin"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Tempel"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Tampilkan simpanan internal"</string>
diff --git a/packages/DocumentsUI/res/values-is-rIS/strings.xml b/packages/DocumentsUI/res/values-is-rIS/strings.xml
index 0c0e47f..89d2e03 100644
--- a/packages/DocumentsUI/res/values-is-rIS/strings.xml
+++ b/packages/DocumentsUI/res/values-is-rIS/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Skrár"</string>
     <string name="title_open" msgid="4353228937663917801">"Opna frá"</string>
     <string name="title_save" msgid="2433679664882857999">"Vista í"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Búa til möppu"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Töfluyfirlit"</string>
     <string name="menu_list" msgid="7279285939892417279">"Listayfirlit"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Raða eftir"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Velja allt"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Afrita í ..."</string>
     <string name="menu_move" msgid="1828090633118079817">"Færa í…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Nýr gluggi"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Afrita"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Líma"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Sýna innbyggða geymslu"</string>
diff --git a/packages/DocumentsUI/res/values-it/strings.xml b/packages/DocumentsUI/res/values-it/strings.xml
index de129a7..02a111e 100644
--- a/packages/DocumentsUI/res/values-it/strings.xml
+++ b/packages/DocumentsUI/res/values-it/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"File"</string>
     <string name="title_open" msgid="4353228937663917801">"Apri da"</string>
     <string name="title_save" msgid="2433679664882857999">"Salva in"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Crea cartella"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Visualizzazione griglia"</string>
     <string name="menu_list" msgid="7279285939892417279">"Visualizzazione elenco"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Ordina per"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Seleziona tutto"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Copia in…"</string>
     <string name="menu_move" msgid="1828090633118079817">"Sposta in..."</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Nuova finestra"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Copia"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Incolla"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Mostra memoria interna"</string>
diff --git a/packages/DocumentsUI/res/values-iw/strings.xml b/packages/DocumentsUI/res/values-iw/strings.xml
index dbe4630..3d3c489 100644
--- a/packages/DocumentsUI/res/values-iw/strings.xml
+++ b/packages/DocumentsUI/res/values-iw/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"קבצים"</string>
     <string name="title_open" msgid="4353228937663917801">"פתח מ-"</string>
     <string name="title_save" msgid="2433679664882857999">"שמור ב-"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"צור תיקיה"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"תצוגת רשת"</string>
     <string name="menu_list" msgid="7279285939892417279">"תצוגת רשימה"</string>
     <string name="menu_sort" msgid="7677740407158414452">"מיין לפי"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"בחר הכל"</string>
     <string name="menu_copy" msgid="3612326052677229148">"העתק אל…"</string>
     <string name="menu_move" msgid="1828090633118079817">"העברה אל…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"חלון חדש"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"העתק"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"הדבק"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"הצג אחסון פנימי"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"העתק"</string>
     <string name="button_move" msgid="2202666023104202232">"העבר"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"הסר"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"נסה שוב"</string>
     <string name="sort_name" msgid="9183560467917256779">"לפי שם"</string>
     <string name="sort_date" msgid="586080032956151448">"לפי תאריך שינוי"</string>
     <string name="sort_size" msgid="3350681319735474741">"לפי גודל"</string>
diff --git a/packages/DocumentsUI/res/values-ja/strings.xml b/packages/DocumentsUI/res/values-ja/strings.xml
index 45f0ea1..a58c0a5 100644
--- a/packages/DocumentsUI/res/values-ja/strings.xml
+++ b/packages/DocumentsUI/res/values-ja/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"ファイル"</string>
     <string name="title_open" msgid="4353228937663917801">"次から開く:"</string>
     <string name="title_save" msgid="2433679664882857999">"次に保存:"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"フォルダを作成"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"グリッド表示"</string>
     <string name="menu_list" msgid="7279285939892417279">"リスト表示"</string>
     <string name="menu_sort" msgid="7677740407158414452">"並べ替え"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"すべて選択"</string>
     <string name="menu_copy" msgid="3612326052677229148">"コピー…"</string>
     <string name="menu_move" msgid="1828090633118079817">"移動..."</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"新しいウィンドウ"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"コピー"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"貼り付け"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"内部ストレージを表示"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"コピー"</string>
     <string name="button_move" msgid="2202666023104202232">"移動"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"表示しない"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"再試行"</string>
     <string name="sort_name" msgid="9183560467917256779">"名前順"</string>
     <string name="sort_date" msgid="586080032956151448">"更新日順"</string>
     <string name="sort_size" msgid="3350681319735474741">"サイズ順"</string>
diff --git a/packages/DocumentsUI/res/values-ka-rGE/strings.xml b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
index 114e73c..cf4b5d6 100644
--- a/packages/DocumentsUI/res/values-ka-rGE/strings.xml
+++ b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"ფაილები"</string>
     <string name="title_open" msgid="4353228937663917801">"გახსნა აქედან:"</string>
     <string name="title_save" msgid="2433679664882857999">"შენახვა აქ:"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"საქაღალდის შექმნა"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"ბადის ხედი"</string>
     <string name="menu_list" msgid="7279285939892417279">"სიის ხედი"</string>
     <string name="menu_sort" msgid="7677740407158414452">"სორტირება:"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"ყველას არჩევა"</string>
     <string name="menu_copy" msgid="3612326052677229148">"კოპირება…"</string>
     <string name="menu_move" msgid="1828090633118079817">"გადაადგილება..."</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"ახალი ფანჯარა"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"კოპირება"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"ჩასმა"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"შიდა საცავის ჩვენება"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"კოპირება"</string>
     <string name="button_move" msgid="2202666023104202232">"გადაადგილება"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"დახურვა"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"ისევ ცდა"</string>
     <string name="sort_name" msgid="9183560467917256779">"სახელით"</string>
     <string name="sort_date" msgid="586080032956151448">"ცვლილების თარიღით"</string>
     <string name="sort_size" msgid="3350681319735474741">"ზომით"</string>
diff --git a/packages/DocumentsUI/res/values-kk-rKZ/strings.xml b/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
index af123c6..5ec16a9 100644
--- a/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
+++ b/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Файлдар"</string>
     <string name="title_open" msgid="4353228937663917801">"Мынадан ашу:"</string>
     <string name="title_save" msgid="2433679664882857999">"Сақталатын орны"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Қалта жасақтау"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Торлы көрініс"</string>
     <string name="menu_list" msgid="7279285939892417279">"Тізім көрінісі"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Белгіге қарай сұрыптау"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Барлығын таңдау"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Көшіру орны…"</string>
     <string name="menu_move" msgid="1828090633118079817">"Орнын ауыстыру…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Жаңа терезе"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Көшіру"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Қою"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Ішкі жадты көрсету"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"Көшіру"</string>
     <string name="button_move" msgid="2202666023104202232">"Жылжыту"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"Өшіру"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"Әрекетті қайталау"</string>
     <string name="sort_name" msgid="9183560467917256779">"Атауы бойынша"</string>
     <string name="sort_date" msgid="586080032956151448">"Өзгертілген мерзімі бойынша"</string>
     <string name="sort_size" msgid="3350681319735474741">"Өлшемі бойынша"</string>
diff --git a/packages/DocumentsUI/res/values-km-rKH/strings.xml b/packages/DocumentsUI/res/values-km-rKH/strings.xml
index 8f3feae..7377882 100644
--- a/packages/DocumentsUI/res/values-km-rKH/strings.xml
+++ b/packages/DocumentsUI/res/values-km-rKH/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"ឯកសារ"</string>
     <string name="title_open" msgid="4353228937663917801">"បើក​ពី"</string>
     <string name="title_save" msgid="2433679664882857999">"រក្សា​ទុក​ទៅ"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"បង្កើត​ថត"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"ទិដ្ឋភាព​ក្រឡា​"</string>
     <string name="menu_list" msgid="7279285939892417279">"ទិដ្ឋភាព​បញ្ជី"</string>
     <string name="menu_sort" msgid="7677740407158414452">"តម្រៀប​តាម"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"ជ្រើសរើសទាំងអស់"</string>
     <string name="menu_copy" msgid="3612326052677229148">"ថតចម្លងទៅ…"</string>
     <string name="menu_move" msgid="1828090633118079817">"ផ្លាស់ទីទៅ៖"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"បង្អួចថ្មី"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"ចម្លង"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"បិទភ្ជាប់"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"បង្ហាញឧបករណ៍ផ្ទុកខាងក្នុង"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"ចម្លង"</string>
     <string name="button_move" msgid="2202666023104202232">"ផ្លាស់ទី"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"បដិសេធ"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"ព្យាយាមម្ដងទៀត"</string>
     <string name="sort_name" msgid="9183560467917256779">"តាម​ឈ្មោះ"</string>
     <string name="sort_date" msgid="586080032956151448">"តាម​កាលបរិច្ឆេទ​បាន​កែប្រែ"</string>
     <string name="sort_size" msgid="3350681319735474741">"តាម​​ទំហំ"</string>
diff --git a/packages/DocumentsUI/res/values-kn-rIN/strings.xml b/packages/DocumentsUI/res/values-kn-rIN/strings.xml
index 826cf1e..a5cad7b 100644
--- a/packages/DocumentsUI/res/values-kn-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-kn-rIN/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"ಫೈಲ್‌ಗಳು"</string>
     <string name="title_open" msgid="4353228937663917801">"ಇದರ ಮೂಲಕ ತೆರೆಯಿರಿ"</string>
     <string name="title_save" msgid="2433679664882857999">"ಇವುಗಳಲ್ಲಿ ಉಳಿಸಿ"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"ಫೋಲ್ಡರ್ ರಚಿಸು"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"ಗ್ರಿಡ್ ವೀಕ್ಷಣೆ"</string>
     <string name="menu_list" msgid="7279285939892417279">"ಪಟ್ಟಿ ವೀಕ್ಷಣೆ"</string>
     <string name="menu_sort" msgid="7677740407158414452">"ಈ ಪ್ರಕಾರ ವಿಂಗಡಿಸು"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"ಎಲ್ಲವನ್ನೂ ಆಯ್ಕೆಮಾಡಿ"</string>
     <string name="menu_copy" msgid="3612326052677229148">"ಇದಕ್ಕೆ ನಕಲಿಸಿ…"</string>
     <string name="menu_move" msgid="1828090633118079817">"ಇದಕ್ಕೆ ಸರಿಸು…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"ಹೊಸ ವಿಂಡೋ"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"ನಕಲಿಸು"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"ಅಂಟಿಸು"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"ಆಂತರಿಕ ಸಂಗ್ರಹಣೆಯನ್ನು ತೋರಿಸು"</string>
diff --git a/packages/DocumentsUI/res/values-ko/strings.xml b/packages/DocumentsUI/res/values-ko/strings.xml
index 322b43b..1426bf8 100644
--- a/packages/DocumentsUI/res/values-ko/strings.xml
+++ b/packages/DocumentsUI/res/values-ko/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"파일"</string>
     <string name="title_open" msgid="4353228937663917801">"열기:"</string>
     <string name="title_save" msgid="2433679664882857999">"저장 위치:"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"폴더 만들기"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"바둑판식 보기"</string>
     <string name="menu_list" msgid="7279285939892417279">"목록 보기"</string>
     <string name="menu_sort" msgid="7677740407158414452">"정렬 기준"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"모두 선택"</string>
     <string name="menu_copy" msgid="3612326052677229148">"복사…"</string>
     <string name="menu_move" msgid="1828090633118079817">"이동…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"새 창"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"복사"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"붙여넣기"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"내부 저장소 표시"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"복사"</string>
     <string name="button_move" msgid="2202666023104202232">"이동"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"닫기"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"다시 시도"</string>
     <string name="sort_name" msgid="9183560467917256779">"이름순"</string>
     <string name="sort_date" msgid="586080032956151448">"수정된 날짜순"</string>
     <string name="sort_size" msgid="3350681319735474741">"크기순"</string>
diff --git a/packages/DocumentsUI/res/values-ky-rKG/strings.xml b/packages/DocumentsUI/res/values-ky-rKG/strings.xml
index c8aa69e..c1eadb7 100644
--- a/packages/DocumentsUI/res/values-ky-rKG/strings.xml
+++ b/packages/DocumentsUI/res/values-ky-rKG/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Файлдар"</string>
     <string name="title_open" msgid="4353228937663917801">"Кийинкиден ачуу:"</string>
     <string name="title_save" msgid="2433679664882857999">"Кийинкиге сактоо:"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Папка түзүү"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Тор көрүнүшү"</string>
     <string name="menu_list" msgid="7279285939892417279">"Тизмек көрүнүшү"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Ылгоо"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Бардыгын тандоо"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Төмөнкүгө көчүрүү…"</string>
     <string name="menu_move" msgid="1828090633118079817">"Төмөнкүгө жылдыруу..."</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Жаңы терезе"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Көчүрүү"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Чаптоо"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Ички сактагычты көрсөтүү"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"Көчүрүү"</string>
     <string name="button_move" msgid="2202666023104202232">"Жылдыруу"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"Этибарга албоо"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"Дагы аракет кылыңыз"</string>
     <string name="sort_name" msgid="9183560467917256779">"Аты боюнча"</string>
     <string name="sort_date" msgid="586080032956151448">"Өзгөртүлгөн күнү боюнча"</string>
     <string name="sort_size" msgid="3350681319735474741">"Өлчөмү боюнча"</string>
diff --git a/packages/DocumentsUI/res/values-lo-rLA/strings.xml b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
index dedfa05..5c0ffdb 100644
--- a/packages/DocumentsUI/res/values-lo-rLA/strings.xml
+++ b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"​ໄຟລ໌"</string>
     <string name="title_open" msgid="4353228937663917801">"ເປີດ​ຈາກ"</string>
     <string name="title_save" msgid="2433679664882857999">"ບັນທຶກໄປທີ່"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"ສ້າງໂຟນເດີ"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"ມຸມມອງແບບຊ່ອງ"</string>
     <string name="menu_list" msgid="7279285939892417279">"ມຸມມອງແບບລາຍຊື່"</string>
     <string name="menu_sort" msgid="7677740407158414452">"ຮຽງລຳດັບຕາມ"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"ເລືອກທັງຫມົດ"</string>
     <string name="menu_copy" msgid="3612326052677229148">"ອັດ​ສຳ​ເນົາ​ໃສ່…"</string>
     <string name="menu_move" msgid="1828090633118079817">"ຍ້າຍໄປໃສ່..."</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"ໜ້າຈໍໃໝ່"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"ສຳເນົາ"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"​ວາງໃສ່"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"ສະແດງ​ໂຕເກັບ​ຂໍ້ມູນພາຍໃນ"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"ສຳເນົາ"</string>
     <string name="button_move" msgid="2202666023104202232">"ຍ້າຍ"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"ປິດໄວ້"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"​ລອງ​ໃໝ່​ອີກ​"</string>
     <string name="sort_name" msgid="9183560467917256779">"ຕາມຊື່"</string>
     <string name="sort_date" msgid="586080032956151448">"ຕາມວັນທີທີ່ແກ້ໄຂ"</string>
     <string name="sort_size" msgid="3350681319735474741">"ຕາມຂະໜາດ"</string>
diff --git a/packages/DocumentsUI/res/values-lt/strings.xml b/packages/DocumentsUI/res/values-lt/strings.xml
index 0c8b443..49774e8c 100644
--- a/packages/DocumentsUI/res/values-lt/strings.xml
+++ b/packages/DocumentsUI/res/values-lt/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Failai"</string>
     <string name="title_open" msgid="4353228937663917801">"Atidaryti iš"</string>
     <string name="title_save" msgid="2433679664882857999">"Išsaugoti į"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Kurti aplanką"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Tinklelio rodinys"</string>
     <string name="menu_list" msgid="7279285939892417279">"Sąrašo rodinys"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Rūšiuoti pagal"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Pasirinkti viską"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Kopijuoti į..."</string>
     <string name="menu_move" msgid="1828090633118079817">"Perkelti į…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Naujas langas"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopijuoti"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Įklijuoti"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Rodyti vidinę atmintį"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"Kopijuoti"</string>
     <string name="button_move" msgid="2202666023104202232">"Perkelti"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"Atsisakyti"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"Bandyti dar kartą"</string>
     <string name="sort_name" msgid="9183560467917256779">"Pagal pavadinimą"</string>
     <string name="sort_date" msgid="586080032956151448">"Pagal keitimo datą"</string>
     <string name="sort_size" msgid="3350681319735474741">"Pagal dydį"</string>
diff --git a/packages/DocumentsUI/res/values-lv/strings.xml b/packages/DocumentsUI/res/values-lv/strings.xml
index 5c79554..9cb3425 100644
--- a/packages/DocumentsUI/res/values-lv/strings.xml
+++ b/packages/DocumentsUI/res/values-lv/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Faili"</string>
     <string name="title_open" msgid="4353228937663917801">"Atvēršana no:"</string>
     <string name="title_save" msgid="2433679664882857999">"Saglabāšana:"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Izveidot mapi"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Režģis"</string>
     <string name="menu_list" msgid="7279285939892417279">"Saraksts"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Kārtot pēc"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Atlasīt visus"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Kopēt…"</string>
     <string name="menu_move" msgid="1828090633118079817">"Pārvietot uz…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Jauns logs"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopēt"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Ielīmēt"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Rādīt iekšējo atmiņu"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"Kopēt"</string>
     <string name="button_move" msgid="2202666023104202232">"Pārvietot"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"Noraidīt"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"Mēģināt vēlreiz"</string>
     <string name="sort_name" msgid="9183560467917256779">"Pēc nosaukuma"</string>
     <string name="sort_date" msgid="586080032956151448">"Pēc pārveidošanas datuma"</string>
     <string name="sort_size" msgid="3350681319735474741">"Pēc lieluma"</string>
diff --git a/packages/DocumentsUI/res/values-mk-rMK/strings.xml b/packages/DocumentsUI/res/values-mk-rMK/strings.xml
index b2cb9f1..149d0d4 100644
--- a/packages/DocumentsUI/res/values-mk-rMK/strings.xml
+++ b/packages/DocumentsUI/res/values-mk-rMK/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Датотеки"</string>
     <string name="title_open" msgid="4353228937663917801">"Отвори од"</string>
     <string name="title_save" msgid="2433679664882857999">"Зачувај во"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Создади папка"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Приказ на мрежа"</string>
     <string name="menu_list" msgid="7279285939892417279">"Приказ на список"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Подреди по"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Избери ги сите"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Копирај во…"</string>
     <string name="menu_move" msgid="1828090633118079817">"Премести во..."</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Нов прозорец"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Копирај"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Залепи"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Прикажи внатрешна мемор."</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"Копирај"</string>
     <string name="button_move" msgid="2202666023104202232">"Премести"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"Отфрли"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"Обиди се пак"</string>
     <string name="sort_name" msgid="9183560467917256779">"По име"</string>
     <string name="sort_date" msgid="586080032956151448">"Изменети по датум"</string>
     <string name="sort_size" msgid="3350681319735474741">"По големина"</string>
diff --git a/packages/DocumentsUI/res/values-ml-rIN/strings.xml b/packages/DocumentsUI/res/values-ml-rIN/strings.xml
index 07efa66..c621359 100644
--- a/packages/DocumentsUI/res/values-ml-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-ml-rIN/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"ഫയലുകൾ"</string>
     <string name="title_open" msgid="4353228937663917801">"ഇതിൽ നിന്നും തുറക്കുക"</string>
     <string name="title_save" msgid="2433679664882857999">"ഇതില്‍‌ സംരക്ഷിക്കുക"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"ഫോൾഡർ സൃഷ്‌ടിക്കുക"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"ഗ്രിഡ് കാഴ്‌ച"</string>
     <string name="menu_list" msgid="7279285939892417279">"ലിസ്റ്റ് കാഴ്‌ച"</string>
     <string name="menu_sort" msgid="7677740407158414452">"ഇപ്രകാരം അടുക്കുക"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"എല്ലാം തിരഞ്ഞെടുക്കുക"</string>
     <string name="menu_copy" msgid="3612326052677229148">"ഇതിൽ പകർത്തുക…"</string>
     <string name="menu_move" msgid="1828090633118079817">"ഇതിലേക്ക് നീക്കുക..."</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"പുതിയ വിന്‍‍ഡോ"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"പകര്‍ത്തുക"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"ഒട്ടിക്കുക"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"ആന്തരിക സ്റ്റോറേജ്  കാണിക്കുക"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"പകര്‍ത്തുക"</string>
     <string name="button_move" msgid="2202666023104202232">"നീക്കുക"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"ഡിസ്മിസ് ചെയ്യുക"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"വീണ്ടും ശ്രമിക്കുക"</string>
     <string name="sort_name" msgid="9183560467917256779">"പേര് പ്രകാരം"</string>
     <string name="sort_date" msgid="586080032956151448">"പരിഷ്‌ക്കരിച്ച തീയതി പ്രകാരം"</string>
     <string name="sort_size" msgid="3350681319735474741">"വലുപ്പം പ്രകാരം"</string>
diff --git a/packages/DocumentsUI/res/values-mn-rMN/strings.xml b/packages/DocumentsUI/res/values-mn-rMN/strings.xml
index d45778c..fb7503e 100644
--- a/packages/DocumentsUI/res/values-mn-rMN/strings.xml
+++ b/packages/DocumentsUI/res/values-mn-rMN/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Файл"</string>
     <string name="title_open" msgid="4353228937663917801">"Нээх"</string>
     <string name="title_save" msgid="2433679664882857999">"Хадгалах"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Фолдер үүсгэх"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Эгнүүлж харах"</string>
     <string name="menu_list" msgid="7279285939892417279">"Жагсааж харах"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Эрэмбэлэх"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Бүгдийг сонгох"</string>
     <string name="menu_copy" msgid="3612326052677229148">"...руу хуулах"</string>
     <string name="menu_move" msgid="1828090633118079817">"Байршуулах газар"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Шинэ цонх"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Хуулах"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Буулгах"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Дотоод санг харуулах"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"Хуулах"</string>
     <string name="button_move" msgid="2202666023104202232">"Зөөх"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"Алгасах"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"Дахин оролдоно уу"</string>
     <string name="sort_name" msgid="9183560467917256779">"Нэрээр"</string>
     <string name="sort_date" msgid="586080032956151448">"Өөрчлөгдсөн огноогоор"</string>
     <string name="sort_size" msgid="3350681319735474741">"Хэмжээгээр"</string>
diff --git a/packages/DocumentsUI/res/values-mr-rIN/strings.xml b/packages/DocumentsUI/res/values-mr-rIN/strings.xml
index 8d70143..8d5885a 100644
--- a/packages/DocumentsUI/res/values-mr-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-mr-rIN/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"फायली"</string>
     <string name="title_open" msgid="4353228937663917801">"वरून उघडा"</string>
     <string name="title_save" msgid="2433679664882857999">"येथे जतन करा"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"फोल्डर तयार करा"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"ग्रिड दृश्य"</string>
     <string name="menu_list" msgid="7279285939892417279">"सूची"</string>
     <string name="menu_sort" msgid="7677740407158414452">"नुसार क्रमवारी लावा"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"सर्व निवडा"</string>
     <string name="menu_copy" msgid="3612326052677229148">"यावर कॉपी करा…"</string>
     <string name="menu_move" msgid="1828090633118079817">"यावर हलवा…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"नवीन विंडो"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"कॉपी करा"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"पेस्ट करा"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"अंतर्गत संचयन दर्शवा"</string>
diff --git a/packages/DocumentsUI/res/values-ms-rMY/strings.xml b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
index 2250109..6904e10 100644
--- a/packages/DocumentsUI/res/values-ms-rMY/strings.xml
+++ b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Fail"</string>
     <string name="title_open" msgid="4353228937663917801">"Buka dari"</string>
     <string name="title_save" msgid="2433679664882857999">"Simpan ke"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Buat folder"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Paparan grid"</string>
     <string name="menu_list" msgid="7279285939892417279">"Paparan senarai"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Isih mengikut"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Pilih semua"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Salin ke..."</string>
     <string name="menu_move" msgid="1828090633118079817">"Alihkan ke…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Tetingkap baharu"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Salin"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Tampal"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Papar storan dalaman"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"Salin"</string>
     <string name="button_move" msgid="2202666023104202232">"Alihkan"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"Tolak"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"Cuba Lagi"</string>
     <string name="sort_name" msgid="9183560467917256779">"Mengikut nama"</string>
     <string name="sort_date" msgid="586080032956151448">"Mengikut tarikh diubah"</string>
     <string name="sort_size" msgid="3350681319735474741">"Mengikut saiz"</string>
diff --git a/packages/DocumentsUI/res/values-my-rMM/strings.xml b/packages/DocumentsUI/res/values-my-rMM/strings.xml
index 480c27b..f3ed0f7 100644
--- a/packages/DocumentsUI/res/values-my-rMM/strings.xml
+++ b/packages/DocumentsUI/res/values-my-rMM/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"ဖိုင်များ"</string>
     <string name="title_open" msgid="4353228937663917801">"မှ ဖွင့်ပါ"</string>
     <string name="title_save" msgid="2433679664882857999">"သို့ သိမ်းပါ"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"အကန့် တည်ဆောက်ရန်"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"ဖယားကွက်မြင်ကွင်း"</string>
     <string name="menu_list" msgid="7279285939892417279">"အစဉ်လိုက်မြင်ကွင်း"</string>
     <string name="menu_sort" msgid="7677740407158414452">"အစဉ်အလိုက် စီခြင်း"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"အားလုံးကို ရွေးရန်"</string>
     <string name="menu_copy" msgid="3612326052677229148">"သို့ကူးယူရန်…"</string>
     <string name="menu_move" msgid="1828090633118079817">"...သို့ ရွှေ့ရန်"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"ဝင်းဒိုးသစ်"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"ကူးယူရန်"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"ကပ်ရန်"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"စက်ရှိစတိုရုံ ပြပါ"</string>
diff --git a/packages/DocumentsUI/res/values-nb/strings.xml b/packages/DocumentsUI/res/values-nb/strings.xml
index 48355aa..5f71805 100644
--- a/packages/DocumentsUI/res/values-nb/strings.xml
+++ b/packages/DocumentsUI/res/values-nb/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Filer"</string>
     <string name="title_open" msgid="4353228937663917801">"Åpne fra"</string>
     <string name="title_save" msgid="2433679664882857999">"Lagre i"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Opprett en mappe"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Rutenettvisning"</string>
     <string name="menu_list" msgid="7279285939892417279">"Listevisning"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Sortér etter"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Markér alt"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Kopiér til …"</string>
     <string name="menu_move" msgid="1828090633118079817">"Flytt til"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Nytt vindu"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopiér"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Lim inn"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Vis den interne lagringen"</string>
diff --git a/packages/DocumentsUI/res/values-ne-rNP/strings.xml b/packages/DocumentsUI/res/values-ne-rNP/strings.xml
index 53942c1..1bc6a29 100644
--- a/packages/DocumentsUI/res/values-ne-rNP/strings.xml
+++ b/packages/DocumentsUI/res/values-ne-rNP/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"फाइलहरू"</string>
     <string name="title_open" msgid="4353228937663917801">"यसबाट खोल्नुहोस्"</string>
     <string name="title_save" msgid="2433679664882857999">"यसमा सुरक्षित गर्नुहोस्"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"फोल्डर सिर्जना गर्नुहोस्"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"ग्रिड दृश्य"</string>
     <string name="menu_list" msgid="7279285939892417279">"सूची दृश्य"</string>
     <string name="menu_sort" msgid="7677740407158414452">"यसद्वारा क्रमवद्घ गर्नुहोस्"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"सबै चयन गर्नुहोस्"</string>
     <string name="menu_copy" msgid="3612326052677229148">"यसमा प्रतिलिपि गर्नुहोस् ..."</string>
     <string name="menu_move" msgid="1828090633118079817">"…मा सार्नुहोस्"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"नयाँ विन्डो"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"प्रतिलिपि बनाउनुहोस्"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"टाँस्नुहोस्"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"आन्तरिक भण्डारण देखाउनुहोस्"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"प्रतिलिपि बनाउनुहोस्"</string>
     <string name="button_move" msgid="2202666023104202232">"सार्नुहोस्"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"खारेज गर्नुहोस्"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"पुन: प्रयास गर्नुहोस्"</string>
     <string name="sort_name" msgid="9183560467917256779">"नाम अनुसार"</string>
     <string name="sort_date" msgid="586080032956151448">"परिमार्जित मिति अनुसार"</string>
     <string name="sort_size" msgid="3350681319735474741">"आकार अनुसार"</string>
diff --git a/packages/DocumentsUI/res/values-nl/strings.xml b/packages/DocumentsUI/res/values-nl/strings.xml
index d3e6bbe..79a6de9 100644
--- a/packages/DocumentsUI/res/values-nl/strings.xml
+++ b/packages/DocumentsUI/res/values-nl/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Bestanden"</string>
     <string name="title_open" msgid="4353228937663917801">"Openen vanuit"</string>
     <string name="title_save" msgid="2433679664882857999">"Opslaan in"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Map maken"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Rasterweergave"</string>
     <string name="menu_list" msgid="7279285939892417279">"Lijstweergave"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Sorteren op"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Alles selecteren"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Kopiëren naar…"</string>
     <string name="menu_move" msgid="1828090633118079817">"Verplaatsen naar…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Nieuw venster"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopiëren"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Plakken"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Interne opslag weergeven"</string>
diff --git a/packages/DocumentsUI/res/values-pa-rIN/strings.xml b/packages/DocumentsUI/res/values-pa-rIN/strings.xml
index 3b14396..c4fe4e4 100644
--- a/packages/DocumentsUI/res/values-pa-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-pa-rIN/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"ਫਾਈਲਾਂ"</string>
     <string name="title_open" msgid="4353228937663917801">"ਤੋਂ ਖੋਲ੍ਹੋ"</string>
     <string name="title_save" msgid="2433679664882857999">"ਇਸ ਵਿੱਚ ਸੁਰੱਖਿਅਤ ਕਰੋ"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"ਫੋਲਡਰ ਬਣਾਓ"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"ਗ੍ਰਿਡ ਵਿਊ"</string>
     <string name="menu_list" msgid="7279285939892417279">"ਸੂਚੀ ਦ੍ਰਿਸ਼"</string>
     <string name="menu_sort" msgid="7677740407158414452">"ਇਸ ਅਨੁਸਾਰ ਛਾਂਟੋ"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"ਸਾਰੇ ਚੁਣੋ"</string>
     <string name="menu_copy" msgid="3612326052677229148">"ਇਸ ਵਿੱਚ ਕਾਪੀ ਕਰੋ…"</string>
     <string name="menu_move" msgid="1828090633118079817">"ਇਸ ਵਿੱਚ ਮੂਵ ਕਰੋ..."</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"ਨਵੀਂ ਵਿੰਡੋ"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"ਕਾਪੀ ਕਰੋ"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"ਪੇਸਟ ਕਰੋ"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"ਅੰਦਰੂਨੀ ਸਟੋਰੇਜ ਦਿਖਾਓ"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"ਕਾਪੀ ਕਰੋ"</string>
     <string name="button_move" msgid="2202666023104202232">"ਮੂਵ ਕਰੋ"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"ਬਰਖਾਸਤ ਕਰੋ"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ"</string>
     <string name="sort_name" msgid="9183560467917256779">"ਨਾਮ ਮੁਤਾਬਕ"</string>
     <string name="sort_date" msgid="586080032956151448">"ਤਾਰੀਖ ਮੁਤਾਬਕ ਸੰਸ਼ੋਧਿਤ"</string>
     <string name="sort_size" msgid="3350681319735474741">"ਆਕਾਰ ਮੁਤਾਬਕ"</string>
diff --git a/packages/DocumentsUI/res/values-pl/strings.xml b/packages/DocumentsUI/res/values-pl/strings.xml
index 3e4ef68..30b0806 100644
--- a/packages/DocumentsUI/res/values-pl/strings.xml
+++ b/packages/DocumentsUI/res/values-pl/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Pliki"</string>
     <string name="title_open" msgid="4353228937663917801">"Otwórz z"</string>
     <string name="title_save" msgid="2433679664882857999">"Zapisz w"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Utwórz folder"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Widok siatki"</string>
     <string name="menu_list" msgid="7279285939892417279">"Widok listy"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Sortuj według"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Zaznacz wszystko"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Kopiuj do…"</string>
     <string name="menu_move" msgid="1828090633118079817">"Przenieś do…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Nowe okno"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopiuj"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Wklej"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Pokaż pamięć wewnętrzną"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"Kopiuj"</string>
     <string name="button_move" msgid="2202666023104202232">"Przenieś"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"Zamknij"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"Spróbuj ponownie"</string>
     <string name="sort_name" msgid="9183560467917256779">"Według nazwy"</string>
     <string name="sort_date" msgid="586080032956151448">"Według daty edycji"</string>
     <string name="sort_size" msgid="3350681319735474741">"Według rozmiaru"</string>
diff --git a/packages/DocumentsUI/res/values-pt-rBR/strings.xml b/packages/DocumentsUI/res/values-pt-rBR/strings.xml
index ca984cf..0233e3d 100644
--- a/packages/DocumentsUI/res/values-pt-rBR/strings.xml
+++ b/packages/DocumentsUI/res/values-pt-rBR/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Arquivos"</string>
     <string name="title_open" msgid="4353228937663917801">"Abrir de"</string>
     <string name="title_save" msgid="2433679664882857999">"Salvar em"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Criar pasta"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Visualização em grade"</string>
     <string name="menu_list" msgid="7279285939892417279">"Visualização em lista"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Classificar por"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Selecionar tudo"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Copiar para..."</string>
     <string name="menu_move" msgid="1828090633118079817">"Mover para..."</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Nova janela"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Copiar"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Colar"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Mostrar armaz. interno"</string>
diff --git a/packages/DocumentsUI/res/values-pt-rPT/strings.xml b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
index ab67358..0c41a91 100644
--- a/packages/DocumentsUI/res/values-pt-rPT/strings.xml
+++ b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Ficheiros"</string>
     <string name="title_open" msgid="4353228937663917801">"Abrir de"</string>
     <string name="title_save" msgid="2433679664882857999">"Guardar em"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Criar pasta"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Vista de grelha"</string>
     <string name="menu_list" msgid="7279285939892417279">"Vista de lista"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Ordenar por"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Selecionar tudo"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Copiar para…"</string>
     <string name="menu_move" msgid="1828090633118079817">"Mover para..."</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Nova janela"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Copiar"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Colar"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Mostrar mem. armaz. int."</string>
diff --git a/packages/DocumentsUI/res/values-pt/strings.xml b/packages/DocumentsUI/res/values-pt/strings.xml
index ca984cf..0233e3d 100644
--- a/packages/DocumentsUI/res/values-pt/strings.xml
+++ b/packages/DocumentsUI/res/values-pt/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Arquivos"</string>
     <string name="title_open" msgid="4353228937663917801">"Abrir de"</string>
     <string name="title_save" msgid="2433679664882857999">"Salvar em"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Criar pasta"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Visualização em grade"</string>
     <string name="menu_list" msgid="7279285939892417279">"Visualização em lista"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Classificar por"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Selecionar tudo"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Copiar para..."</string>
     <string name="menu_move" msgid="1828090633118079817">"Mover para..."</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Nova janela"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Copiar"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Colar"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Mostrar armaz. interno"</string>
diff --git a/packages/DocumentsUI/res/values-ro/strings.xml b/packages/DocumentsUI/res/values-ro/strings.xml
index e927b78..27734d5 100644
--- a/packages/DocumentsUI/res/values-ro/strings.xml
+++ b/packages/DocumentsUI/res/values-ro/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Fișiere"</string>
     <string name="title_open" msgid="4353228937663917801">"Deschideți din"</string>
     <string name="title_save" msgid="2433679664882857999">"Salvați în"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Creați un dosar"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Afișare tip grilă"</string>
     <string name="menu_list" msgid="7279285939892417279">"Afișare tip listă"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Sortați după"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Selectați tot"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Copiați în…"</string>
     <string name="menu_move" msgid="1828090633118079817">"Mutați în…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Fereastră nouă"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Copiați"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Inserați"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Afișați stocarea internă"</string>
diff --git a/packages/DocumentsUI/res/values-ru/strings.xml b/packages/DocumentsUI/res/values-ru/strings.xml
index cdf20ca..152992e 100644
--- a/packages/DocumentsUI/res/values-ru/strings.xml
+++ b/packages/DocumentsUI/res/values-ru/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Файлы"</string>
     <string name="title_open" msgid="4353228937663917801">"Открыть"</string>
     <string name="title_save" msgid="2433679664882857999">"Сохранить"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Новая папка"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Сетка"</string>
     <string name="menu_list" msgid="7279285939892417279">"Список"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Сортировать"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Выбрать все"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Копировать в…"</string>
     <string name="menu_move" msgid="1828090633118079817">"Переместить"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Новое окно"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Копировать"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Вставить"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Внутренняя память"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"Копировать"</string>
     <string name="button_move" msgid="2202666023104202232">"Переместить"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"Скрыть"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"Повторить"</string>
     <string name="sort_name" msgid="9183560467917256779">"По названию"</string>
     <string name="sort_date" msgid="586080032956151448">"По дате изменения"</string>
     <string name="sort_size" msgid="3350681319735474741">"По размеру"</string>
diff --git a/packages/DocumentsUI/res/values-si-rLK/strings.xml b/packages/DocumentsUI/res/values-si-rLK/strings.xml
index 138f8a6..a8165a1 100644
--- a/packages/DocumentsUI/res/values-si-rLK/strings.xml
+++ b/packages/DocumentsUI/res/values-si-rLK/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"ගොනු"</string>
     <string name="title_open" msgid="4353228937663917801">"විවෘත වන්නේ"</string>
     <string name="title_save" msgid="2433679664882857999">"සුරකින්නේ"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"ෆෝල්ඩරයක් සාදන්න"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"ජාල පෙනුම"</string>
     <string name="menu_list" msgid="7279285939892417279">"ලැයිස්තු පෙනුම"</string>
     <string name="menu_sort" msgid="7677740407158414452">"අනුපිළිවෙලට සකසා ඇත්තේ"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"සියල්ල තෝරන්න"</string>
     <string name="menu_copy" msgid="3612326052677229148">"වෙත පිටපත් කරන්න..."</string>
     <string name="menu_move" msgid="1828090633118079817">"වෙත ගෙනයන්න..."</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"නව කවුළුව"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"පිටපත් කරන්න"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"අලවන්න"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"අභ්‍යන්තර ආචයනය පෙන්වන්න"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"පිටපත් කිරීම"</string>
     <string name="button_move" msgid="2202666023104202232">"ගෙන යන්න"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"ඉවතලන්න"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"නැවත උත්සාහ කරන්න"</string>
     <string name="sort_name" msgid="9183560467917256779">"නමින්"</string>
     <string name="sort_date" msgid="586080032956151448">"වෙනස් කරන ලද දිනයෙන්"</string>
     <string name="sort_size" msgid="3350681319735474741">"ප්‍රමාණය මගින්"</string>
diff --git a/packages/DocumentsUI/res/values-sk/strings.xml b/packages/DocumentsUI/res/values-sk/strings.xml
index 4310819..3441f26 100644
--- a/packages/DocumentsUI/res/values-sk/strings.xml
+++ b/packages/DocumentsUI/res/values-sk/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Súbory"</string>
     <string name="title_open" msgid="4353228937663917801">"Otvoriť z"</string>
     <string name="title_save" msgid="2433679664882857999">"Uložiť do"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Vytvoriť priečinok"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Zobrazenie mriežky"</string>
     <string name="menu_list" msgid="7279285939892417279">"Zobrazenie zoznamu"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Zoradiť podľa"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Vybrať všetko"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Kopírovať do…"</string>
     <string name="menu_move" msgid="1828090633118079817">"Presunúť do…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Nové okno"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopírovať"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Prilepiť"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Zobraziť interné úložisko"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"Kopírovať"</string>
     <string name="button_move" msgid="2202666023104202232">"Presunúť"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"Odmietnuť"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"Skúsiť znova"</string>
     <string name="sort_name" msgid="9183560467917256779">"Podľa názvu"</string>
     <string name="sort_date" msgid="586080032956151448">"Podľa dátumu zmeny"</string>
     <string name="sort_size" msgid="3350681319735474741">"Podľa veľkosti"</string>
diff --git a/packages/DocumentsUI/res/values-sl/strings.xml b/packages/DocumentsUI/res/values-sl/strings.xml
index c9982a7..fe36664 100644
--- a/packages/DocumentsUI/res/values-sl/strings.xml
+++ b/packages/DocumentsUI/res/values-sl/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Datoteke"</string>
     <string name="title_open" msgid="4353228937663917801">"Odpri iz mape"</string>
     <string name="title_save" msgid="2433679664882857999">"Shrani v"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Ustvarjanje mape"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Mrežni pogled"</string>
     <string name="menu_list" msgid="7279285939892417279">"Pogled seznama"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Razvrsti glede na"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Izberi vse"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Kopiraj v …"</string>
     <string name="menu_move" msgid="1828090633118079817">"Premakni v ..."</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Novo okno"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopiraj"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Prilepi"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Pokaži notranjo shrambo"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"Kopiraj"</string>
     <string name="button_move" msgid="2202666023104202232">"Premik"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"Opusti"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"Poskusite znova"</string>
     <string name="sort_name" msgid="9183560467917256779">"Po imenu"</string>
     <string name="sort_date" msgid="586080032956151448">"Po datumu spremembe"</string>
     <string name="sort_size" msgid="3350681319735474741">"Po velikosti"</string>
diff --git a/packages/DocumentsUI/res/values-sq-rAL/strings.xml b/packages/DocumentsUI/res/values-sq-rAL/strings.xml
index f1ee1bc..18794f5 100644
--- a/packages/DocumentsUI/res/values-sq-rAL/strings.xml
+++ b/packages/DocumentsUI/res/values-sq-rAL/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Skedarët"</string>
     <string name="title_open" msgid="4353228937663917801">"Hap nga"</string>
     <string name="title_save" msgid="2433679664882857999">"Ruaje te"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Krijo dosje"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Pamje rrjete"</string>
     <string name="menu_list" msgid="7279285939892417279">"Pamje liste"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Rendit sipas"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Zgjidhi të gjitha"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Kopjo te..."</string>
     <string name="menu_move" msgid="1828090633118079817">"Zhvendos te..."</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Dritare e re"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopjo"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Ngjit"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Trego hapësirën e brendshme ruajtëse"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"Kopjo"</string>
     <string name="button_move" msgid="2202666023104202232">"Zhvendos"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"Largoje"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"Provo sërish"</string>
     <string name="sort_name" msgid="9183560467917256779">"Sipas emrit"</string>
     <string name="sort_date" msgid="586080032956151448">"Sipas datës së modifikimit"</string>
     <string name="sort_size" msgid="3350681319735474741">"Sipas madhësisë"</string>
diff --git a/packages/DocumentsUI/res/values-sr/strings.xml b/packages/DocumentsUI/res/values-sr/strings.xml
index c5116c2..fa047f2 100644
--- a/packages/DocumentsUI/res/values-sr/strings.xml
+++ b/packages/DocumentsUI/res/values-sr/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Датотеке"</string>
     <string name="title_open" msgid="4353228937663917801">"Отвори са"</string>
     <string name="title_save" msgid="2433679664882857999">"Сачувај у"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Направи директоријум"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Приказ мреже"</string>
     <string name="menu_list" msgid="7279285939892417279">"Приказ листе"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Сортирај према"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Изабери све"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Копирај на..."</string>
     <string name="menu_move" msgid="1828090633118079817">"Премести у..."</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Нови прозор"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Копирај"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Налепи"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Прикажи интерну меморију"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"Копирај"</string>
     <string name="button_move" msgid="2202666023104202232">"Премести"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"Одбаци"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"Покушај поново"</string>
     <string name="sort_name" msgid="9183560467917256779">"Према имену"</string>
     <string name="sort_date" msgid="586080032956151448">"Према датуму измене"</string>
     <string name="sort_size" msgid="3350681319735474741">"Према величини"</string>
diff --git a/packages/DocumentsUI/res/values-sv/strings.xml b/packages/DocumentsUI/res/values-sv/strings.xml
index 06e6514..5ac8691 100644
--- a/packages/DocumentsUI/res/values-sv/strings.xml
+++ b/packages/DocumentsUI/res/values-sv/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Filer"</string>
     <string name="title_open" msgid="4353228937663917801">"Öppna från"</string>
     <string name="title_save" msgid="2433679664882857999">"Spara till"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Skapa mapp"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Rutnätsvy"</string>
     <string name="menu_list" msgid="7279285939892417279">"Listvy"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Sortera efter"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Markera allt"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Kopiera till …"</string>
     <string name="menu_move" msgid="1828090633118079817">"Flytta till ..."</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Nytt fönster"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopiera"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Klistra in"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Visa internminne"</string>
diff --git a/packages/DocumentsUI/res/values-sw/strings.xml b/packages/DocumentsUI/res/values-sw/strings.xml
index 79bae1f..3daa18e 100644
--- a/packages/DocumentsUI/res/values-sw/strings.xml
+++ b/packages/DocumentsUI/res/values-sw/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Faili"</string>
     <string name="title_open" msgid="4353228937663917801">"Fungua kutoka"</string>
     <string name="title_save" msgid="2433679664882857999">"Hifadhi kwenye"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Unda folda"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Mwonekano gridi"</string>
     <string name="menu_list" msgid="7279285939892417279">"Mwonekano orodha"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Panga kwa"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Chagua zote"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Nakili kwenda..."</string>
     <string name="menu_move" msgid="1828090633118079817">"Hamisha hadi..."</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Dirisha jipya"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Nakili"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Bandika"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Onyesha hifadhi ya ndani"</string>
diff --git a/packages/DocumentsUI/res/values-ta-rIN/strings.xml b/packages/DocumentsUI/res/values-ta-rIN/strings.xml
index 117aabc..14fa702 100644
--- a/packages/DocumentsUI/res/values-ta-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-ta-rIN/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"கோப்புகள்"</string>
     <string name="title_open" msgid="4353228937663917801">"இதில் திற"</string>
     <string name="title_save" msgid="2433679664882857999">"இதில் சேமி"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"கோப்புறையை உருவாக்கு"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"கட்டக் காட்சி"</string>
     <string name="menu_list" msgid="7279285939892417279">"பட்டியல்"</string>
     <string name="menu_sort" msgid="7677740407158414452">"இதன்படி வரிசைப்படுத்து"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"எல்லாவற்றையும் தேர்ந்தெடு"</string>
     <string name="menu_copy" msgid="3612326052677229148">"இங்கு நகலெடு…"</string>
     <string name="menu_move" msgid="1828090633118079817">"இதற்கு நகர்த்து…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"புதிய சாளரம்"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"நகலெடு"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"ஒட்டு"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"அகச் சேமிப்பகத்தைக் காட்டு"</string>
diff --git a/packages/DocumentsUI/res/values-te-rIN/strings.xml b/packages/DocumentsUI/res/values-te-rIN/strings.xml
index 21b7f58..17c0066 100644
--- a/packages/DocumentsUI/res/values-te-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-te-rIN/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"ఫైల్‌లు"</string>
     <string name="title_open" msgid="4353228937663917801">"ఇక్కడి నుండి తెరువు"</string>
     <string name="title_save" msgid="2433679664882857999">"ఇందులో సేవ్ చేయి"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"ఫోల్డర్‌ను సృష్టించు"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"గ్రిడ్ వీక్షణ"</string>
     <string name="menu_list" msgid="7279285939892417279">"జాబితా వీక్షణ"</string>
     <string name="menu_sort" msgid="7677740407158414452">"ఇలా క్రమబద్ధీకరించు"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"అన్నీ ఎంచుకోండి"</string>
     <string name="menu_copy" msgid="3612326052677229148">"ఇక్కడికి కాపీ చేయి…"</string>
     <string name="menu_move" msgid="1828090633118079817">"దీనికి తరలించు..."</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"కొత్త విండో"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"కాపీ చేయి"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"అతికించు"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"అంతర్గత నిల్వను చూపు"</string>
diff --git a/packages/DocumentsUI/res/values-th/strings.xml b/packages/DocumentsUI/res/values-th/strings.xml
index 8a49708..47e12b6 100644
--- a/packages/DocumentsUI/res/values-th/strings.xml
+++ b/packages/DocumentsUI/res/values-th/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"ไฟล์"</string>
     <string name="title_open" msgid="4353228937663917801">"เปิดจาก"</string>
     <string name="title_save" msgid="2433679664882857999">"บันทึกไปยัง"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"สร้างโฟลเดอร์"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"มุมมองตาราง"</string>
     <string name="menu_list" msgid="7279285939892417279">"มุมมองรายการ"</string>
     <string name="menu_sort" msgid="7677740407158414452">"จัดเรียงตาม"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"เลือกทั้งหมด"</string>
     <string name="menu_copy" msgid="3612326052677229148">"คัดลอกไปยัง…"</string>
     <string name="menu_move" msgid="1828090633118079817">"ย้ายไปที่…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"หน้าต่างใหม่"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"คัดลอก"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"วาง"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"แสดงที่จัดเก็บภายใน"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"คัดลอก"</string>
     <string name="button_move" msgid="2202666023104202232">"ย้าย"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"ปิด"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"ลองอีกครั้ง"</string>
     <string name="sort_name" msgid="9183560467917256779">"ตามชื่อ"</string>
     <string name="sort_date" msgid="586080032956151448">"ตามวันที่ที่ปรับเปลี่ยน"</string>
     <string name="sort_size" msgid="3350681319735474741">"ตามขนาด"</string>
diff --git a/packages/DocumentsUI/res/values-tl/strings.xml b/packages/DocumentsUI/res/values-tl/strings.xml
index 5c0dc12..b09820c 100644
--- a/packages/DocumentsUI/res/values-tl/strings.xml
+++ b/packages/DocumentsUI/res/values-tl/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Mga File"</string>
     <string name="title_open" msgid="4353228937663917801">"Buksan mula sa"</string>
     <string name="title_save" msgid="2433679664882857999">"I-save sa"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Gumawa ng folder"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"View na grid"</string>
     <string name="menu_list" msgid="7279285939892417279">"View na listahan"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Uriin ayon sa"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Piliin lahat"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Kopyahin sa..."</string>
     <string name="menu_move" msgid="1828090633118079817">"Ilipat sa…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Bagong window"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopyahin"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"I-paste"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Ipakita internal storage"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"Kopyahin"</string>
     <string name="button_move" msgid="2202666023104202232">"Ilipat"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"I-dismiss"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"Subukang Muli"</string>
     <string name="sort_name" msgid="9183560467917256779">"Ayon sa pangalan"</string>
     <string name="sort_date" msgid="586080032956151448">"Ayon sa petsa ng pagbago"</string>
     <string name="sort_size" msgid="3350681319735474741">"Ayon sa laki"</string>
diff --git a/packages/DocumentsUI/res/values-tr/strings.xml b/packages/DocumentsUI/res/values-tr/strings.xml
index 092b38e..50fa357 100644
--- a/packages/DocumentsUI/res/values-tr/strings.xml
+++ b/packages/DocumentsUI/res/values-tr/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Dosyalar"</string>
     <string name="title_open" msgid="4353228937663917801">"Şuradan aç:"</string>
     <string name="title_save" msgid="2433679664882857999">"Şuraya kaydet:"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Klasör oluştur"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Tablo görünümü"</string>
     <string name="menu_list" msgid="7279285939892417279">"Liste görünümü"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Sıralama ölçütü"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Tümünü seç"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Kopyala…"</string>
     <string name="menu_move" msgid="1828090633118079817">"Taşı..."</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Yeni pencere"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopyala"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Yapıştır"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Dahili depolamayı göster"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"Kopyala"</string>
     <string name="button_move" msgid="2202666023104202232">"Taşı"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"Kapat"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"Tekrar Dene"</string>
     <string name="sort_name" msgid="9183560467917256779">"Ada göre"</string>
     <string name="sort_date" msgid="586080032956151448">"Değişiklik tarihine göre"</string>
     <string name="sort_size" msgid="3350681319735474741">"Boyuta göre"</string>
diff --git a/packages/DocumentsUI/res/values-uk/strings.xml b/packages/DocumentsUI/res/values-uk/strings.xml
index dff37c3..7382bf8 100644
--- a/packages/DocumentsUI/res/values-uk/strings.xml
+++ b/packages/DocumentsUI/res/values-uk/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Файли"</string>
     <string name="title_open" msgid="4353228937663917801">"Відкрити"</string>
     <string name="title_save" msgid="2433679664882857999">"Зберегти в"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Створити папку"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Режим таблиці"</string>
     <string name="menu_list" msgid="7279285939892417279">"Режим списку"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Параметри сортування"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Вибрати все"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Копіювати в…"</string>
     <string name="menu_move" msgid="1828090633118079817">"Перемістити в…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Нове вікно"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Копіювати"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Вставити"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Показати внутр. пам’ять"</string>
diff --git a/packages/DocumentsUI/res/values-ur-rPK/strings.xml b/packages/DocumentsUI/res/values-ur-rPK/strings.xml
index 82822ec..0e5544f 100644
--- a/packages/DocumentsUI/res/values-ur-rPK/strings.xml
+++ b/packages/DocumentsUI/res/values-ur-rPK/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"فائلیں"</string>
     <string name="title_open" msgid="4353228937663917801">"کھولیں از"</string>
     <string name="title_save" msgid="2433679664882857999">"اس میں محفوظ کریں"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"فولڈر بنائیں"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"گرڈ منظر"</string>
     <string name="menu_list" msgid="7279285939892417279">"فہرست منظر"</string>
     <string name="menu_sort" msgid="7677740407158414452">"ترتیب دیں بلحاظ"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"سبھی کو منتخب کریں"</string>
     <string name="menu_copy" msgid="3612326052677229148">"اس میں کاپی کریں…"</string>
     <string name="menu_move" msgid="1828090633118079817">"اس میں منتقل کریں…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"نئی ونڈو"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"کاپی کریں"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"پیسٹ کریں"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"داخلی اسٹوریج دکھائیں"</string>
diff --git a/packages/DocumentsUI/res/values-uz-rUZ/strings.xml b/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
index d0cfacc..9cc6bca 100644
--- a/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
+++ b/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Fayllar"</string>
     <string name="title_open" msgid="4353228937663917801">"Ochish"</string>
     <string name="title_save" msgid="2433679664882857999">"Saqlash"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Jild yaratish"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Katak ko‘rinishida"</string>
     <string name="menu_list" msgid="7279285939892417279">"Ro‘yxat ko‘rinishida"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Saralash"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Barchasini belgilash"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Nusxalash…"</string>
     <string name="menu_move" msgid="1828090633118079817">"Ko‘chirib o‘tkazish…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Yangi oyna"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Nusxalash"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Joylash"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Ichki xotirani ko‘rsatish"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"Nusxalash"</string>
     <string name="button_move" msgid="2202666023104202232">"Ko‘chirib o‘tkazish"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"O‘chirish"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"Qayta urinish"</string>
     <string name="sort_name" msgid="9183560467917256779">"Nomi bo‘yicha"</string>
     <string name="sort_date" msgid="586080032956151448">"Tahrir sanasi bo‘yicha"</string>
     <string name="sort_size" msgid="3350681319735474741">"Hajmi bo‘yicha"</string>
diff --git a/packages/DocumentsUI/res/values-vi/strings.xml b/packages/DocumentsUI/res/values-vi/strings.xml
index 4583362..1d55338 100644
--- a/packages/DocumentsUI/res/values-vi/strings.xml
+++ b/packages/DocumentsUI/res/values-vi/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Tệp"</string>
     <string name="title_open" msgid="4353228937663917801">"Mở từ"</string>
     <string name="title_save" msgid="2433679664882857999">"Lưu vào"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Tạo thư mục"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Chế độ xem lưới"</string>
     <string name="menu_list" msgid="7279285939892417279">"Chế độ xem danh sách"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Sắp xếp theo"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Chọn tất cả"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Sao chép vào…"</string>
     <string name="menu_move" msgid="1828090633118079817">"Chuyển tới..."</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Cửa sổ mới"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Sao chép"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Dán"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Hiển thị bộ nhớ trong"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"Sao chép"</string>
     <string name="button_move" msgid="2202666023104202232">"Di chuyển"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"Loại bỏ"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"Thử lại"</string>
     <string name="sort_name" msgid="9183560467917256779">"Theo tên"</string>
     <string name="sort_date" msgid="586080032956151448">"Theo ngày sửa đổi"</string>
     <string name="sort_size" msgid="3350681319735474741">"Theo kích thước"</string>
diff --git a/packages/DocumentsUI/res/values-zh-rCN/strings.xml b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
index d577e14..7e2e3d5 100644
--- a/packages/DocumentsUI/res/values-zh-rCN/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"文件"</string>
     <string name="title_open" msgid="4353228937663917801">"打开文件"</string>
     <string name="title_save" msgid="2433679664882857999">"保存文件"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"新建文件夹"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"网格视图"</string>
     <string name="menu_list" msgid="7279285939892417279">"列表视图"</string>
     <string name="menu_sort" msgid="7677740407158414452">"排序依据"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"全选"</string>
     <string name="menu_copy" msgid="3612326052677229148">"复制到…"</string>
     <string name="menu_move" msgid="1828090633118079817">"移动到…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"新建窗口"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"复制"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"粘贴"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"显示内部存储设备"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"复制"</string>
     <string name="button_move" msgid="2202666023104202232">"移动"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"关闭"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"重试"</string>
     <string name="sort_name" msgid="9183560467917256779">"按名称"</string>
     <string name="sort_date" msgid="586080032956151448">"按修改日期"</string>
     <string name="sort_size" msgid="3350681319735474741">"按大小"</string>
diff --git a/packages/DocumentsUI/res/values-zh-rHK/strings.xml b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
index 3d44047..6cbdf01 100644
--- a/packages/DocumentsUI/res/values-zh-rHK/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"檔案"</string>
     <string name="title_open" msgid="4353228937663917801">"開啟檔案"</string>
     <string name="title_save" msgid="2433679664882857999">"儲存至"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"建立資料夾"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"格狀檢視"</string>
     <string name="menu_list" msgid="7279285939892417279">"清單檢視"</string>
     <string name="menu_sort" msgid="7677740407158414452">"排序方式"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"全部選取"</string>
     <string name="menu_copy" msgid="3612326052677229148">"複製到…"</string>
     <string name="menu_move" msgid="1828090633118079817">"移至…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"新視窗"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"複製"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"貼上"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"顯示內部儲存空間"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"複製"</string>
     <string name="button_move" msgid="2202666023104202232">"移動"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"關閉"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"再試一次"</string>
     <string name="sort_name" msgid="9183560467917256779">"按名稱"</string>
     <string name="sort_date" msgid="586080032956151448">"按修改日期"</string>
     <string name="sort_size" msgid="3350681319735474741">"按大小"</string>
diff --git a/packages/DocumentsUI/res/values-zh-rTW/strings.xml b/packages/DocumentsUI/res/values-zh-rTW/strings.xml
index aaad98c..850f9b0 100644
--- a/packages/DocumentsUI/res/values-zh-rTW/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rTW/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"檔案"</string>
     <string name="title_open" msgid="4353228937663917801">"開啟檔案"</string>
     <string name="title_save" msgid="2433679664882857999">"儲存至"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"建立資料夾"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"格狀檢視"</string>
     <string name="menu_list" msgid="7279285939892417279">"清單檢視"</string>
     <string name="menu_sort" msgid="7677740407158414452">"排序依據"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"全選"</string>
     <string name="menu_copy" msgid="3612326052677229148">"複製到…"</string>
     <string name="menu_move" msgid="1828090633118079817">"移至…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"新視窗"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"複製"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"貼上"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"顯示內部儲存空間"</string>
@@ -45,8 +47,7 @@
     <string name="button_copy" msgid="8706475544635021302">"複製"</string>
     <string name="button_move" msgid="2202666023104202232">"移動"</string>
     <string name="button_dismiss" msgid="3714065566893946085">"關閉"</string>
-    <!-- no translation found for button_retry (4392027584153752797) -->
-    <skip />
+    <string name="button_retry" msgid="4392027584153752797">"再試一次"</string>
     <string name="sort_name" msgid="9183560467917256779">"依名稱"</string>
     <string name="sort_date" msgid="586080032956151448">"依修改日期"</string>
     <string name="sort_size" msgid="3350681319735474741">"依大小"</string>
diff --git a/packages/DocumentsUI/res/values-zu/strings.xml b/packages/DocumentsUI/res/values-zu/strings.xml
index 8f20cc4..fdf278d 100644
--- a/packages/DocumentsUI/res/values-zu/strings.xml
+++ b/packages/DocumentsUI/res/values-zu/strings.xml
@@ -20,7 +20,8 @@
     <string name="files_label" msgid="6051402950202690279">"Amafayela"</string>
     <string name="title_open" msgid="4353228937663917801">"Vula kusuka ku-"</string>
     <string name="title_save" msgid="2433679664882857999">"Londoloza ku-"</string>
-    <string name="menu_create_dir" msgid="5947289605844398389">"Dala ifolda"</string>
+    <!-- no translation found for menu_create_dir (2547620241173881754) -->
+    <skip />
     <string name="menu_grid" msgid="6878021334497835259">"Ukubuka kwegridi"</string>
     <string name="menu_list" msgid="7279285939892417279">"Ukubuka uhlu"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Hlunga nge-"</string>
@@ -33,6 +34,7 @@
     <string name="menu_select_all" msgid="8323579667348729928">"Khetha konke"</string>
     <string name="menu_copy" msgid="3612326052677229148">"Kopishela ku…"</string>
     <string name="menu_move" msgid="1828090633118079817">"Hambisa ku…"</string>
+    <string name="menu_new_window" msgid="1226032889278727538">"Iwindi elisha"</string>
     <string name="menu_copy_to_clipboard" msgid="489311381979634291">"Kopisha"</string>
     <string name="menu_paste_from_clipboard" msgid="2071583031180257091">"Namathisela"</string>
     <string name="menu_advanced_show" product="nosdcard" msgid="4693652895715631401">"Bonisa isitoreji sangaphakathi"</string>
diff --git a/packages/DocumentsUI/res/values/config.xml b/packages/DocumentsUI/res/values/config.xml
index ce5b174..ed7820b 100644
--- a/packages/DocumentsUI/res/values/config.xml
+++ b/packages/DocumentsUI/res/values/config.xml
@@ -15,5 +15,5 @@
 -->
 
 <resources>
-    <bool name="productivity_device">false</bool>
+    <bool name="productivity_device">true</bool>
 </resources>
diff --git a/packages/DocumentsUI/res/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml
index a4acb60..d21b5ee 100644
--- a/packages/DocumentsUI/res/values/strings.xml
+++ b/packages/DocumentsUI/res/values/strings.xml
@@ -27,7 +27,7 @@
     <string name="title_save">Save to</string>
 
     <!-- Menu item that creates a new directory/folder at the current location [CHAR LIMIT=24] -->
-    <string name="menu_create_dir">Create folder</string>
+    <string name="menu_create_dir">New folder</string>
     <!-- Menu item that switches view to show documents as a large-format grid of thumbnails [CHAR LIMIT=24] -->
     <string name="menu_grid">Grid view</string>
     <!-- Menu item that switches view to show documents as a list [CHAR LIMIT=24] -->
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index ab0f666..caaa2b9 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -128,10 +128,10 @@
 
     @Override
     public boolean onPrepareOptionsMenu(Menu menu) {
-        boolean shown = super.onPrepareOptionsMenu(menu);
+        super.onPrepareOptionsMenu(menu);
 
         final RootInfo root = getCurrentRoot();
-        final DocumentInfo cwd = getCurrentDirectory();
+        final boolean inRecents = getCurrentDirectory() == null;
 
         final MenuItem sort = menu.findItem(R.id.menu_sort);
         final MenuItem sortSize = menu.findItem(R.id.menu_sort_size);
@@ -141,24 +141,28 @@
         final MenuItem fileSize = menu.findItem(R.id.menu_file_size);
         final MenuItem settings = menu.findItem(R.id.menu_settings);
 
-        mSearchManager.update(root);
+        // I'm thinkin' this isn't necesary here. If it is...'cuz of a bug....
+        // then uncomment the linke and let's get a proper bug reference here.
+        // mSearchManager.update(root);
 
         // Search uses backend ranking; no sorting
-        sort.setVisible(cwd != null && !mSearchManager.isSearching());
+        sort.setVisible(!inRecents && !mSearchManager.isSearching());
+
+        // grid/list is effectively a toggle.
+        grid.setVisible(mState.derivedMode != State.MODE_GRID);
+        list.setVisible(mState.derivedMode != State.MODE_LIST);
+
+        sortSize.setVisible(mState.showSize); // Only sort by size when visible
+        fileSize.setVisible(!mState.forceSize);
+        advanced.setVisible(!mState.forceAdvanced);
+        settings.setVisible((root.flags & Root.FLAG_HAS_SETTINGS) != 0);
 
         advanced.setTitle(LocalPreferences.getDisplayAdvancedDevices(this)
                 ? R.string.menu_advanced_hide : R.string.menu_advanced_show);
         fileSize.setTitle(LocalPreferences.getDisplayFileSize(this)
                 ? R.string.menu_file_size_hide : R.string.menu_file_size_show);
 
-        sortSize.setVisible(mState.showSize); // Only sort by size when visible
-        fileSize.setVisible(!mState.showSize);
-        grid.setVisible(mState.derivedMode != State.MODE_GRID);
-        list.setVisible(mState.derivedMode != State.MODE_LIST);
-        advanced.setVisible(!mState.showAdvanced);
-        settings.setVisible((root.flags & Root.FLAG_HAS_SETTINGS) != 0);
-
-        return shown;
+        return true;
     }
 
     State buildDefaultState() {
@@ -277,6 +281,7 @@
         return cwd != null
                 && cwd.isCreateSupported()
                 && !mSearchManager.isSearching()
+                && !root.isRecents()
                 && !root.isDownloads();
     }
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
index 362052c..66f8acd 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
@@ -119,7 +119,7 @@
 
         int toastMessage = (mode == TRANSFER_MODE_COPY) ? R.plurals.copy_begin
                 : R.plurals.move_begin;
-        Shared.makeSnackbar(activity,
+        Snackbars.makeSnackbar(activity,
                 res.getQuantityString(toastMessage, srcDocs.size(), srcDocs.size()),
                 Snackbar.LENGTH_SHORT).show();
         activity.startService(copyIntent);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
index 9f44516..c6425a6 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
@@ -147,7 +147,7 @@
                 // Navigate into newly created child
                 mActivity.onDirectoryCreated(result);
             } else {
-                Shared.makeSnackbar(mActivity, R.string.create_error, Snackbar.LENGTH_SHORT).show();
+                Snackbars.makeSnackbar(mActivity, R.string.create_error, Snackbar.LENGTH_SHORT).show();
             }
 
             mActivity.setPending(false);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index b3ce103..0abbf4e 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -44,7 +44,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.Loader;
-import android.content.res.Resources;
 import android.database.Cursor;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
@@ -54,7 +53,6 @@
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.CancellationSignal;
-import android.os.Handler;
 import android.os.Looper;
 import android.os.OperationCanceledException;
 import android.os.Parcelable;
@@ -134,8 +132,6 @@
     private Model mModel;
     private Model.UpdateListener mModelUpdateListener = new ModelUpdateListener();
 
-    private final Handler mHandler = new Handler(Looper.getMainLooper());
-
     private View mEmptyView;
     private RecyclerView mRecView;
 
@@ -217,8 +213,6 @@
     @Override
     public View onCreateView(
             LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-        final Context context = inflater.getContext();
-        final Resources res = context.getResources();
         final View view = inflater.inflate(R.layout.fragment_directory, container, false);
 
         mMessageBar = MessageBar.create(getChildFragmentManager());
@@ -678,6 +672,7 @@
             checkNotNull(mMenu);
             // Delegate update logic to our owning action, since specialized logic is desired.
             mFragmentTuner.updateActionMenu(mMenu, mType, mNoDeleteCount == 0);
+            Menus.disableHiddenItems(mMenu);
         }
 
         @Override
@@ -799,13 +794,12 @@
 
     private void deleteDocuments(final Selection selected) {
         Context context = getActivity();
-        ContentResolver resolver = context.getContentResolver();
         String message = Shared.getQuantityString(context, R.plurals.deleting, selected.size());
 
         mModel.markForDeletion(selected);
 
         final Activity activity = getActivity();
-        Shared.makeSnackbar(activity, message, Snackbar.LENGTH_LONG)
+        Snackbars.makeSnackbar(activity, message, Snackbar.LENGTH_LONG)
                 .setAction(
                         R.string.undo,
                         new android.view.View.OnClickListener() {
@@ -823,7 +817,7 @@
                                             new Model.DeletionListener() {
                                                 @Override
                                                 public void onError() {
-                                                    Shared.makeSnackbar(
+                                                    Snackbars.makeSnackbar(
                                                             activity,
                                                             R.string.toast_failed_delete,
                                                             Snackbar.LENGTH_LONG)
@@ -1244,7 +1238,7 @@
 
     private void copyDocuments(final List<DocumentInfo> docs, final DocumentInfo destination) {
         if (!canCopy(docs, destination)) {
-            Shared.makeSnackbar(
+            Snackbars.makeSnackbar(
                     getActivity(),
                     R.string.clipboard_files_cannot_paste,
                     Snackbar.LENGTH_SHORT)
@@ -1298,7 +1292,7 @@
             void onDocumentsReady(List<DocumentInfo> docs) {
                 mClipper.clipDocuments(docs);
                 Activity activity = getActivity();
-                Shared.makeSnackbar(activity,
+                Snackbars.makeSnackbar(activity,
                         activity.getResources().getQuantityString(
                                 R.plurals.clipboard_files_clipped, docs.size(), docs.size()),
                                 Snackbar.LENGTH_SHORT).show();
@@ -1608,23 +1602,25 @@
 
         @Override
         public void updateActionMenu(Menu menu, int dirType, boolean canDelete) {
+            boolean copyEnabled = mManaging && dirType != TYPE_RECENT_OPEN;
+            // TODO: The selection needs to be deletable.
+            boolean moveEnabled =
+                    SystemProperties.getBoolean("debug.documentsui.enable_move", false);
+            menu.findItem(R.id.menu_copy_to_clipboard).setEnabled(copyEnabled);
 
             final MenuItem open = menu.findItem(R.id.menu_open);
             final MenuItem share = menu.findItem(R.id.menu_share);
             final MenuItem delete = menu.findItem(R.id.menu_delete);
             final MenuItem copyTo = menu.findItem(R.id.menu_copy_to);
             final MenuItem moveTo = menu.findItem(R.id.menu_move_to);
-            final MenuItem copyToClipboard = menu.findItem(R.id.menu_copy_to_clipboard);
 
             open.setVisible(!mManaging);
             share.setVisible(mManaging);
             delete.setVisible(mManaging && canDelete);
-            // Disable copying from the Recents view.
-            copyTo.setVisible(mManaging && dirType != TYPE_RECENT_OPEN);
-            moveTo.setVisible(SystemProperties.getBoolean("debug.documentsui.enable_move", false));
-
-            // Only shown in files mode.
-            copyToClipboard.setVisible(false);
+            copyTo.setVisible(copyEnabled);
+            copyTo.setEnabled(copyEnabled);
+            moveTo.setVisible(moveEnabled);
+            moveTo.setEnabled(moveEnabled);
         }
 
         @Override
@@ -1638,13 +1634,14 @@
         @Override
         public void updateActionMenu(Menu menu, int dirType, boolean canDelete) {
 
+            menu.findItem(R.id.menu_copy_to_clipboard).setEnabled(dirType != TYPE_RECENT_OPEN);
+
             menu.findItem(R.id.menu_share).setVisible(true);
             menu.findItem(R.id.menu_delete).setVisible(canDelete);
-            menu.findItem(R.id.menu_copy_to_clipboard).setVisible(true);
 
             menu.findItem(R.id.menu_open).setVisible(false);
-            menu.findItem(R.id.menu_copy_to).setVisible(false);
-            menu.findItem(R.id.menu_move_to).setVisible(false);
+            menu.findItem(R.id.menu_copy_to).setVisible(true);
+            menu.findItem(R.id.menu_move_to).setVisible(true);
         }
 
         @Override
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index ced03cc..6b428f5 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -89,8 +89,6 @@
             setTheme(R.style.DocumentsNonDialogTheme);
         }
 
-        final Context context = this;
-
         if (mShowAsDialog) {
             mDrawer = DrawerController.createDummy();
 
@@ -314,41 +312,35 @@
     public boolean onPrepareOptionsMenu(Menu menu) {
         super.onPrepareOptionsMenu(menu);
 
-        final RootInfo root = getCurrentRoot();
         final DocumentInfo cwd = getCurrentDirectory();
 
         final MenuItem createDir = menu.findItem(R.id.menu_create_dir);
         final MenuItem grid = menu.findItem(R.id.menu_grid);
         final MenuItem list = menu.findItem(R.id.menu_list);
-        final MenuItem advanced = menu.findItem(R.id.menu_advanced);
         final MenuItem fileSize = menu.findItem(R.id.menu_file_size);
         final MenuItem settings = menu.findItem(R.id.menu_settings);
 
-        boolean fileSizeVisible = mState.showSize && !mState.forceSize;
-        if (mState.action == ACTION_CREATE
+        boolean recents = cwd == null;
+        boolean picking = mState.action == ACTION_CREATE
                 || mState.action == ACTION_OPEN_TREE
-                || mState.action == ACTION_OPEN_COPY_DESTINATION) {
-            createDir.setVisible(cwd != null && cwd.isCreateSupported());
-            mSearchManager.showMenu(false);
+                || mState.action == ACTION_OPEN_COPY_DESTINATION;
 
-            // No display options in recent directories
-            if (cwd == null) {
-                grid.setVisible(false);
-                list.setVisible(false);
-                fileSizeVisible = false;
-            }
+        createDir.setVisible(picking && !recents && cwd.isCreateSupported());
+        mSearchManager.showMenu(!picking);
 
-            if (mState.action == ACTION_CREATE) {
-                final FragmentManager fm = getFragmentManager();
-                SaveFragment.get(fm).setSaveEnabled(cwd != null && cwd.isCreateSupported());
-            }
-        } else {
-            createDir.setVisible(false);
+        // No display options in recent directories
+        grid.setVisible(!(picking && recents));
+        list.setVisible(!(picking && recents));
+
+        fileSize.setVisible(fileSize.isVisible() && !picking);
+        settings.setVisible(false);
+
+        if (mState.action == ACTION_CREATE) {
+            final FragmentManager fm = getFragmentManager();
+            SaveFragment.get(fm).setSaveEnabled(cwd != null && cwd.isCreateSupported());
         }
 
-        advanced.setVisible(!mState.forceAdvanced);
-        fileSize.setVisible(fileSizeVisible);
-        settings.setVisible(false);
+        Menus.disableHiddenItems(menu);
 
         return true;
     }
@@ -611,7 +603,7 @@
             if (result != null) {
                 onTaskFinished(result);
             } else {
-                Shared.makeSnackbar(
+                Snackbars.makeSnackbar(
                     DocumentsActivity.this, R.string.save_error, Snackbar.LENGTH_SHORT).show();
             }
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
index f6a5131..70ddf59 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
@@ -225,30 +225,23 @@
 
     @Override
     public boolean onPrepareOptionsMenu(Menu menu) {
-        boolean shown = super.onPrepareOptionsMenu(menu);
-
-        menu.findItem(R.id.menu_file_size).setVisible(true);
-        menu.findItem(R.id.menu_advanced).setVisible(true);
+        super.onPrepareOptionsMenu(menu);
 
         final MenuItem createDir = menu.findItem(R.id.menu_create_dir);
         final MenuItem newWindow = menu.findItem(R.id.menu_new_window);
         final MenuItem pasteFromCb = menu.findItem(R.id.menu_paste_from_clipboard);
 
-        boolean canCreateDir = canCreateDirectory();
-
         createDir.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
-        createDir.setVisible(canCreateDir);
-        createDir.setEnabled(canCreateDir);
+        createDir.setVisible(true);
+        createDir.setEnabled(canCreateDirectory());
+
+        pasteFromCb.setEnabled(mClipper.hasItemsToPaste());
 
         newWindow.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
         newWindow.setVisible(mProductivityDevice);
-        newWindow.setEnabled(mProductivityDevice);
 
-        pasteFromCb.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
-        pasteFromCb.setVisible(true);
-        pasteFromCb.setEnabled(mClipper.hasItemsToPaste());
-
-        return shown;
+        Menus.disableHiddenItems(menu, pasteFromCb);
+        return true;
     }
 
     @Override
@@ -347,7 +340,7 @@
         try {
             startActivity(intent);
         } catch (ActivityNotFoundException ex2) {
-            Shared.makeSnackbar(this, R.string.toast_no_application, Snackbar.LENGTH_SHORT).show();
+            Snackbars.makeSnackbar(this, R.string.toast_no_application, Snackbar.LENGTH_SHORT).show();
         }
     }
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java b/packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java
index ed7333d..14a33f9 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java
@@ -140,6 +140,7 @@
     @Override
     public boolean onPrepareOptionsMenu(Menu menu) {
         super.onPrepareOptionsMenu(menu);
+        Menus.disableHiddenItems(menu);
         return true;
     }
 
@@ -184,7 +185,7 @@
                 try {
                     startActivity(view);
                 } catch (ActivityNotFoundException ex2) {
-                    Shared.makeSnackbar(this, R.string.toast_no_application, Snackbar.LENGTH_SHORT)
+                    Snackbars.makeSnackbar(this, R.string.toast_no_application, Snackbar.LENGTH_SHORT)
                             .show();
                 }
             }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Menus.java b/packages/DocumentsUI/src/com/android/documentsui/Menus.java
new file mode 100644
index 0000000..3f43a3d
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/Menus.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import android.view.Menu;
+import android.view.MenuItem;
+
+final class Menus {
+
+    private Menus() {}
+
+    /**
+     * Disables hidden menu items so that they are not invokable via command shortcuts
+     */
+    static void disableHiddenItems(Menu menu, MenuItem... exclusions) {
+        for (int i = 0; i < menu.size(); i++) {
+            MenuItem item = menu.getItem(i);
+            if (item.isVisible()) {
+              continue;
+            }
+            if (contains(exclusions, item)) {
+                continue;
+            }
+            item.setEnabled(false);
+        }
+    }
+
+    private static boolean contains(MenuItem[] exclusions, MenuItem item) {
+        for (int x = 0; x < exclusions.length; x++) {
+            if (exclusions[x] == item) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Shared.java b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
index e06d6a5..a4d6dc5 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Shared.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
@@ -16,12 +16,7 @@
 
 package com.android.documentsui;
 
-import static com.android.internal.util.Preconditions.checkNotNull;
-
-import android.app.Activity;
 import android.content.Context;
-import android.support.design.widget.Snackbar;
-import android.view.View;
 
 /** @hide */
 public final class Shared {
@@ -35,14 +30,4 @@
     public static final String getQuantityString(Context context, int resourceId, int quantity) {
         return context.getResources().getQuantityString(resourceId, quantity, quantity);
     }
-
-    public static final Snackbar makeSnackbar(Activity activity, int messageId, int duration) {
-        return makeSnackbar(activity, activity.getResources().getText(messageId), duration);
-    }
-
-    public static final Snackbar makeSnackbar(Activity activity, CharSequence message, int duration)
-    {
-        final View view = checkNotNull(activity.findViewById(R.id.coordinator_layout));
-        return Snackbar.make(view, message, duration);
-    }
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Snackbars.java b/packages/DocumentsUI/src/com/android/documentsui/Snackbars.java
new file mode 100644
index 0000000..f48b298
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/Snackbars.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.app.Activity;
+import android.support.design.widget.Snackbar;
+import android.view.View;
+
+final class Snackbars {
+    private Snackbars() {}
+
+    public static final Snackbar makeSnackbar(Activity activity, int messageId, int duration) {
+        return Snackbars.makeSnackbar(activity, activity.getResources().getText(messageId), duration);
+    }
+
+    public static final Snackbar makeSnackbar(Activity activity, CharSequence message, int duration)
+    {
+        final View view = checkNotNull(activity.findViewById(R.id.coordinator_layout));
+        return Snackbar.make(view, message, duration);
+    }
+}
diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags
index 47e24e8..368f9f7 100644
--- a/packages/SystemUI/proguard.flags
+++ b/packages/SystemUI/proguard.flags
@@ -13,3 +13,11 @@
 -keep class com.android.systemui.statusbar.phone.PhoneStatusBar
 -keep class com.android.systemui.statusbar.tv.TvStatusBar
 -keep class com.android.systemui.recents.*
+
+-keepclassmembers class ** {
+    public void onBusEvent(**);
+    public void onInterprocessBusEvent(**);
+}
+-keepclassmembers class ** extends **.EventBus$InterprocessEvent {
+	public <init>(android.os.Bundle);
+}
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index f8fc232..b69fc0f 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -325,8 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Միայն\nկարևորները"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Միայն\nզարթուցիչ"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Լիցքավորում (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> մինչև լրիվ լիցքավորումը)"</string>
-    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Արագ լիցքավորում (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>՝ մինչև լցվելը)"</string>
-    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Դանդաղ լիցքավորում (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>՝ մինչև լցվելը)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Արագ լիցքավորում (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>՝ մինչև ավարտ)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Դանդաղ լիցքավորում (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>՝ մինչև ավարտ)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Անջատել օգտվողին"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Փոխել օգտվողին. ներկայիս օգտվողն է՝ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Ընթացիկ օգտվողը՝ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index d91335c..7323126 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -393,7 +393,7 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Utöka"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Komprimera"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Skärmen har fästs"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Detta visar skärmen tills du lossar den. Tryck länge på bakåtknappen och Översikt samtidigt om du vill lossa skärmen."</string>
+    <string name="screen_pinning_description" msgid="1346522416878235405">"Med den här funktionen är skärmen synlig tills du lossar den. Tryck länge på Tillbaka och Översikt samtidigt om du vill lossa skärmen."</string>
     <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Detta visar skärmen tills du lossar den. Tryck länge på Översikt om du vill lossa skärmen."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"OK"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nej tack"</string>
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 23cc8f0..a78351a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -74,6 +74,8 @@
 public class Recents extends SystemUI
         implements ActivityOptions.OnAnimationStartedListener, RecentsComponent {
 
+    public final static int EVENT_BUS_PRIORITY = 1;
+
     final public static String EXTRA_TRIGGERED_FROM_ALT_TAB = "triggeredFromAltTab";
     final public static String EXTRA_TRIGGERED_FROM_HOME_KEY = "triggeredFromHomeKey";
     final public static String EXTRA_RECENTS_VISIBILITY = "recentsVisibility";
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 9ce6b2c..5c61c5ca6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -19,23 +19,32 @@
 import android.app.Activity;
 import android.app.ActivityOptions;
 import android.app.SearchManager;
+import android.app.TaskStackBuilder;
 import android.appwidget.AppWidgetManager;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.net.Uri;
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.provider.Settings;
 import android.view.KeyEvent;
 import android.view.View;
 import android.view.ViewStub;
 import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.R;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.AppWidgetProviderChangedEvent;
+import com.android.systemui.recents.events.ui.DismissTaskEvent;
+import com.android.systemui.recents.events.ui.ResizeTaskEvent;
+import com.android.systemui.recents.events.ui.ShowApplicationInfoEvent;
 import com.android.systemui.recents.misc.Console;
 import com.android.systemui.recents.misc.ReferenceCountedTrigger;
 import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.recents.model.RecentsPackageMonitor;
 import com.android.systemui.recents.model.RecentsTaskLoadPlan;
 import com.android.systemui.recents.model.RecentsTaskLoader;
 import com.android.systemui.recents.model.Task;
@@ -44,16 +53,17 @@
 import com.android.systemui.recents.views.SystemBarScrimViews;
 import com.android.systemui.recents.views.ViewAnimation;
 
-import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 
 /**
  * The main Recents activity that is started from AlternateRecentsComponent.
  */
-public class RecentsActivity extends Activity implements RecentsView.RecentsViewCallbacks,
-        RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks {
+public class RecentsActivity extends Activity implements RecentsView.RecentsViewCallbacks {
+
+    public final static int EVENT_BUS_PRIORITY = Recents.EVENT_BUS_PRIORITY + 1;
 
     RecentsConfiguration mConfig;
+    RecentsPackageMonitor mPackageMonitor;
     long mLastTabKeyEventTime;
 
     // Top level views
@@ -318,12 +328,17 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+
+        // Register this activity with the event bus
+        EventBus.getDefault().register(this, EVENT_BUS_PRIORITY);
+
         // For the non-primary user, ensure that the SystemServicesProxy and configuration is
         // initialized
         RecentsTaskLoader.initialize(this);
         SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
         mConfig = RecentsConfiguration.initialize(this, ssp);
         mConfig.update(this, ssp, ssp.getWindowRect());
+        mPackageMonitor = new RecentsPackageMonitor();
 
         // Initialize the widget host (the host id is static and does not change)
         mAppWidgetHost = new RecentsAppWidgetHost(this, Constants.Values.App.AppWidgetHostId);
@@ -371,7 +386,7 @@
         registerReceiver(mServiceBroadcastReceiver, filter);
 
         // Register any broadcast receivers for the task loader
-        loader.registerReceivers(this, mRecentsView);
+        mPackageMonitor.register(this);
 
         // Update the recent tasks
         updateRecentsTasks();
@@ -415,7 +430,7 @@
         unregisterReceiver(mServiceBroadcastReceiver);
 
         // Unregister any broadcast receivers for the task loader
-        loader.unregisterReceivers();
+        mPackageMonitor.unregister();
 
         // Workaround for b/22542869, if the RecentsActivity is started again, but without going
         // through SystemUI, we need to reset the config launch flags to ensure that we do not
@@ -437,6 +452,7 @@
 
         // Stop listening for widget package changes if there was one bound
         mAppWidgetHost.stopListening();
+        EventBus.getDefault().unregister(this);
     }
 
     public void onEnterAnimationTriggered() {
@@ -446,16 +462,12 @@
         mRecentsView.startEnterRecentsAnimation(ctx);
 
         if (mSearchWidgetInfo != null) {
-            final WeakReference<RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks> cbRef =
-                    new WeakReference<RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks>(
-                            RecentsActivity.this);
             ctx.postAnimationTrigger.addLastDecrementRunnable(new Runnable() {
                 @Override
                 public void run() {
                     // Start listening for widget package changes if there is one bound
-                    RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks cb = cbRef.get();
-                    if (cb != null) {
-                        mAppWidgetHost.startListening(cb);
+                    if (mAppWidgetHost != null) {
+                        mAppWidgetHost.startListening();
                     }
                 }
             });
@@ -530,11 +542,6 @@
         return mResizeTaskDebugDialog;
     }
 
-    @Override
-    public void onTaskResize(Task t) {
-        getResizeTaskDebugDialog().showResizeTaskDialog(t, mRecentsView);
-    }
-
     /**** RecentsView.RecentsViewCallbacks Implementation ****/
 
     @Override
@@ -572,10 +579,40 @@
         mAfterPauseRunnable = r;
     }
 
-    /**** RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks Implementation ****/
+    /**** EventBus events ****/
 
-    @Override
-    public void refreshSearchWidgetView() {
+    public final void onBusEvent(AppWidgetProviderChangedEvent event) {
+        refreshSearchWidgetView();
+    }
+
+    public final void onBusEvent(ShowApplicationInfoEvent event) {
+        // Create a new task stack with the application info details activity
+        Intent baseIntent = event.task.key.baseIntent;
+        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
+                Uri.fromParts("package", baseIntent.getComponent().getPackageName(), null));
+        intent.setComponent(intent.resolveActivity(getPackageManager()));
+        TaskStackBuilder.create(this)
+                .addNextIntentWithParentStack(intent).startActivities(null,
+                new UserHandle(event.task.key.userId));
+
+        // Keep track of app-info invocations
+        MetricsLogger.count(this, "overview_app_info", 1);
+    }
+
+    public final void onBusEvent(DismissTaskEvent event) {
+        // Remove any stored data from the loader
+        RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
+        loader.deleteTaskData(event.task, false);
+
+        // Remove the task from activity manager
+        loader.getSystemServicesProxy().removeTask(event.task.key.id);
+    }
+
+    public final void onBusEvent(ResizeTaskEvent event) {
+        getResizeTaskDebugDialog().showResizeTaskDialog(event.task, mRecentsView);
+    }
+
+    private void refreshSearchWidgetView() {
         if (mSearchWidgetInfo != null) {
             SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
             int searchWidgetId = ssp.getSearchAppWidgetId(this);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java
index 0102332..fc96c11 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java
@@ -20,24 +20,19 @@
 import android.appwidget.AppWidgetHostView;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.Context;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.AppWidgetProviderChangedEvent;
 
 /** Our special app widget host for the Search widget */
 public class RecentsAppWidgetHost extends AppWidgetHost {
 
-    /* Callbacks to notify when an app package changes */
-    interface RecentsAppWidgetHostCallbacks {
-        void refreshSearchWidgetView();
-    }
-
-    RecentsAppWidgetHostCallbacks mCb;
     boolean mIsListening;
 
     public RecentsAppWidgetHost(Context context, int hostId) {
         super(context, hostId);
     }
 
-    public void startListening(RecentsAppWidgetHostCallbacks cb) {
-        mCb = cb;
+    public void startListening() {
         if (!mIsListening) {
             mIsListening = true;
             super.startListening();
@@ -47,11 +42,9 @@
     @Override
     public void stopListening() {
         if (mIsListening) {
+            mIsListening = false;
             super.stopListening();
         }
-        // Ensure that we release any references to the callbacks
-        mCb = null;
-        mIsListening = false;
     }
 
     @Override
@@ -66,8 +59,8 @@
     @Override
     protected void onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidgetInfo) {
         super.onProviderChanged(appWidgetId, appWidgetInfo);
-        if (mIsListening && mCb != null) {
-            mCb.refreshSearchWidgetView();
+        if (mIsListening) {
+            EventBus.getDefault().send(new AppWidgetProviderChangedEvent());
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java b/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java
new file mode 100644
index 0000000..ef543d0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java
@@ -0,0 +1,844 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents.events;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.MutableBoolean;
+
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * Represents a subscriber, which implements various event bus handler methods.
+ */
+class Subscriber {
+    private WeakReference<Object> mSubscriber;
+
+    long registrationTime;
+
+    Subscriber(Object subscriber, long registrationTime) {
+        mSubscriber = new WeakReference<>(subscriber);
+        this.registrationTime = registrationTime;
+    }
+
+    public String toString(int priority) {
+        Object sub = mSubscriber.get();
+        String id = Integer.toHexString(System.identityHashCode(sub));
+        return sub.getClass().getSimpleName() + " [0x" + id + ", P" + priority + "]";
+    }
+
+    public Object getReference() {
+        return mSubscriber.get();
+    }
+}
+
+/**
+ * Represents an event handler with a priority.
+ */
+class EventHandler {
+    int priority;
+    Subscriber subscriber;
+    EventHandlerMethod method;
+
+    EventHandler(Subscriber subscriber, EventHandlerMethod method, int priority) {
+        this.subscriber = subscriber;
+        this.method = method;
+        this.priority = priority;
+    }
+
+    @Override
+    public String toString() {
+        return subscriber.toString(priority) + " " + method.toString();
+    }
+}
+
+/**
+ * Represents the low level method handling a particular event.
+ */
+class EventHandlerMethod {
+    private Method mMethod;
+    Class<? extends EventBus.Event> eventType;
+
+    EventHandlerMethod(Method method, Class<? extends EventBus.Event> eventType) {
+        mMethod = method;
+        mMethod.setAccessible(true);
+        this.eventType = eventType;
+    }
+
+    public void invoke(Object target, EventBus.Event event)
+            throws InvocationTargetException, IllegalAccessException {
+        mMethod.invoke(target, event);
+    }
+
+    @Override
+    public String toString() {
+        return mMethod.getName() + "(" + eventType.getSimpleName() + ")";
+    }
+}
+
+/**
+ * A simple in-process event bus.  It is simple because we can make assumptions about the state of
+ * SystemUI and Recent's lifecycle.
+ *
+ * <p>
+ * Currently, there is a single EventBus that handles {@link EventBus.Event}s for each subscriber
+ * on the main application thread.  Publishers can send() events to synchronously call subscribers
+ * of that event, or post() events to be processed in the next run of the {@link Looper}.  In
+ * addition, the EventBus supports sending and handling {@link EventBus.InterprocessEvent}s
+ * (within the same package) implemented using standard {@link BroadcastReceiver} mechanism.
+ * Interprocess events must be posted using postInterprocess() to ensure that it is dispatched
+ * correctly across processes.
+ *
+ * <p>
+ * Subscribers must be registered with a particular EventBus before they will receive events, and
+ * handler methods must match a specific signature.
+ *
+ * <p>
+ * Event method signature:<ul>
+ * <li>Methods must be public final
+ * <li>Methods must return void
+ * <li>Methods must be called "onBusEvent"
+ * <li>Methods must take one parameter, of class type deriving from {@link EventBus.Event}
+ * </ul>
+ *
+ * <p>
+ * Interprocess-Event method signature:<ul>
+ * <li>Methods must be public final
+ * <li>Methods must return void
+ * <li>Methods must be called "onInterprocessBusEvent"
+ * <li>Methods must take one parameter, of class type deriving from {@link EventBus.InterprocessEvent}
+ * </ul>
+ * </p>
+ *
+ * </p>
+ * Each subscriber can be registered with a given priority (default 1), and events will be dispatch
+ * in decreasing order of priority.  For subscribers with the same priority, events will be
+ * dispatched by latest registration time to earliest.
+ *
+ * <p>
+ * Interprocess events must extend {@link EventBus.InterprocessEvent}, have a constructor which
+ * takes a {@link Bundle} and implement toBundle().  This allows us to serialize events to be sent
+ * across processes.
+ *
+ * <p>
+ * Caveats:<ul>
+ * <li>The EventBus keeps a {@link WeakReference} to the publisher to prevent memory leaks, so
+ * there must be another strong reference to the publisher for it to not get garbage-collected and
+ * continue receiving events.
+ * <li>Because the event handlers are called back using reflection, the EventBus is not intended
+ * for use in tight, performance criticial loops.  For most user input/system callback events, this
+ * is generally of low enough frequency to use the EventBus.
+ * <li>Because the event handlers are called back using reflection, there will often be no
+ * references to them from actual code.  The proguard configuration will be need to be updated to
+ * keep these extra methods:
+ *
+ * -keepclassmembers class ** {
+ * public void onBusEvent(**);
+ * public void onInterprocessBusEvent(**);
+ * }
+ * -keepclassmembers class ** extends **.EventBus$InterprocessEvent {
+ * public <init>(android.os.Bundle);
+ * }
+ *
+ * <li>Subscriber registration can be expensive depending on the subscriber's {@link Class}.  This
+ * is only done once per class type, but if possible, it is best to pre-register an instance of
+ * that class beforehand or when idle.
+ * <li>Each event should be sent once.  Events may hold internal information about the current
+ * dispatch, or may be queued to be dispatched on another thread (if posted from a non-main thread),
+ * so it may be unsafe to edit, change, or re-send the event again.
+ * <li>Events should follow a pattern of public-final POD (plain old data) objects, where they are
+ * initialized by the constructor and read by each subscriber of that event.  Subscribers should
+ * never alter events as they are processed, and this enforces that pattern.
+ * </ul>
+ *
+ * <p>
+ * Future optimizations:
+ * <li>throw exception/log when a subscriber loses the reference
+ * <li>trace cost per registration & invocation
+ * <li>trace cross-process invocation
+ * <li>register(subscriber, Class&lt;?&gt;...) -- pass in exact class types you want registered
+ * <li>setSubscriberEventHandlerPriority(subscriber, Class<Event>, priority)
+ * <li>allow subscribers to implement interface, ie. EventBus.Subscriber, which lets then test a
+ * message before invocation (ie. check if task id == this task id)
+ * <li>add postOnce() which automatically debounces
+ * <li>add postDelayed() which delays / postDelayedOnce() which delays and bounces
+ * <li>consolidate register() and registerInterprocess()
+ * <li>sendForResult&lt;ReturnType&gt;(Event) to send and get a result, but who will send the
+ * result?
+ * </p>
+ */
+public class EventBus extends BroadcastReceiver {
+
+    public static final String TAG = "EventBus";
+
+    /**
+     * An event super class that allows us to track internal event state across subscriber
+     * invocations.
+     *
+     * Events should not be edited by subscribers.
+     */
+    public static class Event {
+        // Indicates that this event's dispatch should be traced and logged to logcat
+        boolean trace;
+        // Indicates that this event must be posted on the EventBus's looper thread before invocation
+        boolean requiresPost;
+        // Not currently exposed, allows a subscriber to cancel further dispatch of this event
+        boolean cancelled;
+
+        // Only accessible from derived events
+        protected Event() {}
+    }
+
+    /**
+     * An inter-process event super class that allows us to track user state across subscriber
+     * invocations.
+     */
+    public static class InterprocessEvent extends Event {
+        private static final String EXTRA_USER = "_user";
+
+        // The user which this event originated from
+        public final int user;
+
+        // Only accessible from derived events
+        protected InterprocessEvent(int user) {
+            this.user = user;
+        }
+
+        /**
+         * Called from the event bus
+         */
+        protected InterprocessEvent(Bundle b) {
+            user = b.getInt(EXTRA_USER);
+        }
+
+        protected Bundle toBundle() {
+            Bundle b = new Bundle();
+            b.putInt(EXTRA_USER, user);
+            return b;
+        }
+    }
+
+    /**
+     * Proguard must also know, and keep, all methods matching this signature.
+     *
+     * -keepclassmembers class ** {
+     *     public void onBusEvent(**);
+     *     public void onInterprocessBusEvent(**);
+     * }
+     */
+    private static final String METHOD_PREFIX = "onBusEvent";
+    private static final String INTERPROCESS_METHOD_PREFIX = "onInterprocessBusEvent";
+
+    // Ensures that interprocess events can only be sent from a process holding this permission. */
+    private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
+
+    // Used for passing event data across process boundaries
+    private static final String EXTRA_INTERPROCESS_EVENT_BUNDLE = "interprocess_event_bundle";
+
+    // The default priority of all subscribers
+    private static final int DEFAULT_SUBSCRIBER_PRIORITY = 1;
+
+    // Used for debugging everything
+    private static final boolean DEBUG_TRACE_ALL = false;
+
+    // Orders the handlers by priority and registration time
+    private static final Comparator<EventHandler> EVENT_HANDLER_COMPARATOR = new Comparator<EventHandler>() {
+        @Override
+        public int compare(EventHandler h1, EventHandler h2) {
+            // Rank the handlers by priority descending, followed by registration time descending.
+            // aka. the later registered
+            if (h1.priority != h2.priority) {
+                return h2.priority - h1.priority;
+            } else {
+                return Long.compare(h2.subscriber.registrationTime, h1.subscriber.registrationTime);
+            }
+        }
+    };
+
+    // Used for initializing the default bus
+    private static final Object sLock = new Object();
+    private static EventBus sDefaultBus;
+
+    // The handler to post all events
+    private Handler mHandler;
+
+    // Keep track of whether we have registered a broadcast receiver already, so that we can
+    // unregister ourselves before re-registering again with a new IntentFilter.
+    private boolean mHasRegisteredReceiver;
+
+    /**
+     * Map from event class -> event handler list.  Keeps track of the actual mapping from event
+     * to subscriber method.
+     */
+    private HashMap<Class<? extends Event>, ArrayList<EventHandler>> mEventTypeMap = new HashMap<>();
+
+    /**
+     * Map from subscriber class -> event handler method lists.  Used to determine upon registration
+     * of a new subscriber whether we need to read all the subscriber's methods again using
+     * reflection or whether we can just add the subscriber to the event type map.
+     */
+    private HashMap<Class<? extends Object>, ArrayList<EventHandlerMethod>> mSubscriberTypeMap = new HashMap<>();
+
+    /**
+     * Map from interprocess event name -> interprocess event class.  Used for mapping the event
+     * name after receiving the broadcast, to the event type.  After which a new instance is created
+     * and posted in the local process.
+     */
+    private HashMap<String, Class<? extends InterprocessEvent>> mInterprocessEventNameMap = new HashMap<>();
+
+    /**
+     * Set of all currently registered subscribers
+     */
+    private ArrayList<Subscriber> mSubscribers = new ArrayList<>();
+
+    // For tracing
+    private int mCallCount;
+    private long mCallDurationMicros;
+
+    /**
+     * Private constructor to create an event bus for a given looper.
+     */
+    private EventBus(Looper looper) {
+        mHandler = new Handler(looper);
+    }
+
+    /**
+     * @return the default event bus for the application's main thread.
+     */
+    public static EventBus getDefault() {
+        if (sDefaultBus == null)
+        synchronized (sLock) {
+            if (sDefaultBus == null) {
+                if (DEBUG_TRACE_ALL) {
+                    logWithPid("New EventBus");
+                }
+                sDefaultBus = new EventBus(Looper.getMainLooper());
+            }
+        }
+        return sDefaultBus;
+    }
+
+    /**
+     * Registers a subscriber to receive events with the default priority.
+     *
+     * @param subscriber the subscriber to handle events.  If this is the first instance of the
+     *                   subscriber's class type that has been registered, the class's methods will
+     *                   be scanned for appropriate event handler methods.
+     */
+    public void register(Object subscriber) {
+        registerSubscriber(subscriber, DEFAULT_SUBSCRIBER_PRIORITY, null);
+    }
+
+    /**
+     * Registers a subscriber to receive events with the given priority.
+     *
+     * @param subscriber the subscriber to handle events.  If this is the first instance of the
+     *                   subscriber's class type that has been registered, the class's methods will
+     *                   be scanned for appropriate event handler methods.
+     * @param priority the priority that this subscriber will receive events relative to other
+     *                 subscribers
+     */
+    public void register(Object subscriber, int priority) {
+        registerSubscriber(subscriber, priority, null);
+    }
+
+    /**
+     * Explicitly registers a subscriber to receive interprocess events with the default priority.
+     *
+     * @param subscriber the subscriber to handle events.  If this is the first instance of the
+     *                   subscriber's class type that has been registered, the class's methods will
+     *                   be scanned for appropriate event handler methods.
+     */
+    public void registerInterprocessAsCurrentUser(Context context, Object subscriber) {
+        registerInterprocessAsCurrentUser(context, subscriber, DEFAULT_SUBSCRIBER_PRIORITY);
+    }
+
+    /**
+     * Registers a subscriber to receive interprocess events with the given priority.
+     *
+     * @param subscriber the subscriber to handle events.  If this is the first instance of the
+     *                   subscriber's class type that has been registered, the class's methods will
+     *                   be scanned for appropriate event handler methods.
+     * @param priority the priority that this subscriber will receive events relative to other
+     *                 subscribers
+     */
+    public void registerInterprocessAsCurrentUser(Context context, Object subscriber, int priority) {
+        if (DEBUG_TRACE_ALL) {
+            logWithPid("registerInterprocessAsCurrentUser(" + subscriber.getClass().getSimpleName() + ")");
+        }
+
+        // Register the subscriber normally, and update the broadcast receiver filter if this is
+        // a new subscriber type with interprocess events
+        MutableBoolean hasInterprocessEventsChanged = new MutableBoolean(false);
+        registerSubscriber(subscriber, priority, hasInterprocessEventsChanged);
+        if (DEBUG_TRACE_ALL) {
+            logWithPid("hasInterprocessEventsChanged: " + hasInterprocessEventsChanged.value);
+        }
+        if (hasInterprocessEventsChanged.value) {
+            registerReceiverForInterprocessEvents(context);
+        }
+    }
+
+    /**
+     * Remove all EventHandlers pointing to the specified subscriber.  This does not remove the
+     * mapping of subscriber type to event handler method, in case new instances of this subscriber
+     * are registered.
+     */
+    public void unregister(Object subscriber) {
+        if (DEBUG_TRACE_ALL) {
+            logWithPid("unregister()");
+        }
+
+        // Fail immediately if we are being called from the non-main thread
+        long callingThreadId = Thread.currentThread().getId();
+        if (callingThreadId != mHandler.getLooper().getThread().getId()) {
+            throw new RuntimeException("Can not unregister() a subscriber from a non-main thread.");
+        }
+
+        // Return early if this is not a registered subscriber
+        if (!findRegisteredSubscriber(subscriber, true /* removeFoundSubscriber */)) {
+            return;
+        }
+
+        Class<?> subscriberType = subscriber.getClass();
+        ArrayList<EventHandlerMethod> subscriberMethods = mSubscriberTypeMap.get(subscriberType);
+        if (subscriberMethods != null) {
+            // For each of the event handlers the subscriber handles, remove all references of that
+            // handler
+            for (EventHandlerMethod method : subscriberMethods) {
+                ArrayList<EventHandler> eventHandlers = mEventTypeMap.get(method.eventType);
+                for (int i = eventHandlers.size() - 1; i >= 0; i--) {
+                    if (eventHandlers.get(i).subscriber.getReference() == subscriber) {
+                        eventHandlers.remove(i);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Explicit unregistration for interprocess event subscribers.  This actually behaves exactly
+     * the same as unregister() since we also do not want to stop listening for specific
+     * inter-process messages in case new instances of that subscriber is registered.
+     */
+    public void unregisterInterprocess(Context context, Object subscriber) {
+        if (DEBUG_TRACE_ALL) {
+            logWithPid("unregisterInterprocess()");
+        }
+        unregister(subscriber);
+    }
+
+    /**
+     * Sends an event to the subscribers of the given event type immediately.  This can only be
+     * called from the same thread as the EventBus's looper thread (for the default EventBus, this
+     * is the main application thread).
+     */
+    public void send(Event event) {
+        // Fail immediately if we are being called from the non-main thread
+        long callingThreadId = Thread.currentThread().getId();
+        if (callingThreadId != mHandler.getLooper().getThread().getId()) {
+            throw new RuntimeException("Can not send() a message from a non-main thread.");
+        }
+
+        if (DEBUG_TRACE_ALL) {
+            logWithPid("send(" + event.getClass().getSimpleName() + ")");
+        }
+
+        // Reset the event's cancelled state
+        event.requiresPost = false;
+        event.cancelled = false;
+        queueEvent(event);
+    }
+
+    /**
+     * Post a message to the subscribers of the given event type.  The messages will be posted on
+     * the EventBus's looper thread (for the default EventBus, this is the main application thread).
+     */
+    public void post(Event event) {
+        if (DEBUG_TRACE_ALL) {
+            logWithPid("post(" + event.getClass().getSimpleName() + ")");
+        }
+
+        // Reset the event's cancelled state
+        event.requiresPost = true;
+        event.cancelled = false;
+        queueEvent(event);
+    }
+
+    /** Prevent post()ing an InterprocessEvent */
+    @Deprecated
+    public void post(InterprocessEvent event) {
+        throw new RuntimeException("Not supported, use postInterprocess");
+    }
+
+    /** Prevent send()ing an InterprocessEvent */
+    @Deprecated
+    public void send(InterprocessEvent event) {
+        throw new RuntimeException("Not supported, use postInterprocess");
+    }
+
+    /**
+     * Posts an interprocess event.
+     */
+    public void postInterprocess(Context context, final InterprocessEvent event) {
+        if (DEBUG_TRACE_ALL) {
+            logWithPid("postInterprocess(" + event.getClass().getSimpleName() + ")");
+        }
+        String eventType = event.getClass().getName();
+        Bundle eventBundle = event.toBundle();
+        Intent intent = new Intent(eventType);
+        intent.setPackage(context.getPackageName());
+        intent.putExtra(EXTRA_INTERPROCESS_EVENT_BUNDLE, eventBundle);
+        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT |
+                Intent.FLAG_RECEIVER_FOREGROUND);
+        context.sendBroadcastAsUser(intent, UserHandle.ALL);
+    }
+
+    /**
+     * Receiver for interprocess events.
+     */
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        if (DEBUG_TRACE_ALL) {
+            logWithPid("onReceive(" + intent.getAction() + ", user " + UserHandle.myUserId() + ")");
+        }
+
+        Bundle eventBundle = intent.getBundleExtra(EXTRA_INTERPROCESS_EVENT_BUNDLE);
+        Class<? extends InterprocessEvent> eventType = mInterprocessEventNameMap.get(intent.getAction());
+        try {
+            Constructor<? extends InterprocessEvent> ctor = eventType.getConstructor(Bundle.class);
+            send((Event) ctor.newInstance(eventBundle));
+        } catch (NoSuchMethodException|
+                InvocationTargetException|
+                InstantiationException|
+                IllegalAccessException e) {
+            Log.e(TAG, "Failed to create InterprocessEvent", e);
+        }
+    }
+
+    /**
+     * @return a dump of the current state of the EventBus
+     */
+    public String dump() {
+        StringBuilder output = new StringBuilder();
+        output.append("Registered class types:");
+        output.append("\n");
+        for (Class<?> clz : mSubscriberTypeMap.keySet()) {
+            output.append("\t");
+            output.append(clz.getSimpleName());
+            output.append("\n");
+        }
+        output.append("Event map:");
+        output.append("\n");
+        for (Class<?> clz : mEventTypeMap.keySet()) {
+            output.append("\t");
+            output.append(clz.getSimpleName());
+            output.append(" -> ");
+            output.append("\n");
+            ArrayList<EventHandler> handlers = mEventTypeMap.get(clz);
+            for (EventHandler handler : handlers) {
+                Object subscriber = handler.subscriber.getReference();
+                if (subscriber != null) {
+                    String id = Integer.toHexString(System.identityHashCode(subscriber));
+                    output.append("\t\t");
+                    output.append(subscriber.getClass().getSimpleName());
+                    output.append(" [0x" + id + ", #" + handler.priority + "]");
+                    output.append("\n");
+                }
+            }
+        }
+        return output.toString();
+    }
+
+    /**
+     * Registers a new subscriber.
+     *
+     * @return return whether or not this
+     */
+    private void registerSubscriber(Object subscriber, int priority,
+            MutableBoolean hasInterprocessEventsChangedOut) {
+        // Fail immediately if we are being called from the non-main thread
+        long callingThreadId = Thread.currentThread().getId();
+        if (callingThreadId != mHandler.getLooper().getThread().getId()) {
+            throw new RuntimeException("Can not register() a subscriber from a non-main thread.");
+        }
+
+        // Return immediately if this exact subscriber is already registered
+        if (findRegisteredSubscriber(subscriber, false /* removeFoundSubscriber */)) {
+            return;
+        }
+
+        long t1 = 0;
+        if (DEBUG_TRACE_ALL) {
+            t1 = SystemClock.currentTimeMicro();
+            logWithPid("registerSubscriber(" + subscriber.getClass().getSimpleName() + ")");
+        }
+        Subscriber sub = new Subscriber(subscriber, SystemClock.uptimeMillis());
+        Class<?> subscriberType = subscriber.getClass();
+        ArrayList<EventHandlerMethod> subscriberMethods = mSubscriberTypeMap.get(subscriberType);
+        if (subscriberMethods != null) {
+            if (DEBUG_TRACE_ALL) {
+                logWithPid("Subscriber class type already registered");
+            }
+
+            // If we've parsed this subscriber type before, just add to the set for all the known
+            // events
+            for (EventHandlerMethod method : subscriberMethods) {
+                ArrayList<EventHandler> eventTypeHandlers = mEventTypeMap.get(method.eventType);
+                eventTypeHandlers.add(new EventHandler(sub, method, priority));
+                sortEventHandlersByPriority(eventTypeHandlers);
+            }
+            mSubscribers.add(sub);
+            return;
+        } else {
+            if (DEBUG_TRACE_ALL) {
+                logWithPid("Subscriber class type requires registration");
+            }
+
+            // If we are parsing this type from scratch, ensure we add it to the subscriber type
+            // map, and pull out he handler methods below
+            subscriberMethods = new ArrayList<>();
+            mSubscriberTypeMap.put(subscriberType, subscriberMethods);
+            mSubscribers.add(sub);
+        }
+
+        // Find all the valid event bus handler methods of the subscriber
+        MutableBoolean isInterprocessEvent = new MutableBoolean(false);
+        Method[] methods = subscriberType.getDeclaredMethods();
+        for (Method m : methods) {
+            Class<?>[] parameterTypes = m.getParameterTypes();
+            isInterprocessEvent.value = false;
+            if (isValidEventBusHandlerMethod(m, parameterTypes, isInterprocessEvent)) {
+                Class<? extends Event> eventType = (Class<? extends Event>) parameterTypes[0];
+                ArrayList<EventHandler> eventTypeHandlers = mEventTypeMap.get(eventType);
+                if (eventTypeHandlers == null) {
+                    eventTypeHandlers = new ArrayList<>();
+                    mEventTypeMap.put(eventType, eventTypeHandlers);
+                }
+                if (isInterprocessEvent.value) {
+                    try {
+                        // Enforce that the event must have a Bundle constructor
+                        eventType.getConstructor(Bundle.class);
+
+                        mInterprocessEventNameMap.put(eventType.getName(),
+                                (Class<? extends InterprocessEvent>) eventType);
+                        if (hasInterprocessEventsChangedOut != null) {
+                            hasInterprocessEventsChangedOut.value = true;
+                        }
+                    } catch (NoSuchMethodException e) {
+                        throw new RuntimeException("Expected InterprocessEvent to have a Bundle constructor");
+                    }
+                }
+                EventHandlerMethod method = new EventHandlerMethod(m, eventType);
+                EventHandler handler = new EventHandler(sub, method, priority);
+                eventTypeHandlers.add(handler);
+                subscriberMethods.add(method);
+                sortEventHandlersByPriority(eventTypeHandlers);
+
+                if (DEBUG_TRACE_ALL) {
+                    logWithPid("  * Method: " + m.getName() +
+                            " event: " + parameterTypes[0].getSimpleName() +
+                            " interprocess? " + isInterprocessEvent.value);
+                }
+            }
+        }
+        if (DEBUG_TRACE_ALL) {
+            logWithPid("Registered " + subscriber.getClass().getSimpleName() + " in " +
+                    (SystemClock.currentTimeMicro() - t1) + " microseconds");
+        }
+    }
+
+    /**
+     * Adds a new message.
+     */
+    private void queueEvent(final Event event) {
+        ArrayList<EventHandler> eventHandlers = mEventTypeMap.get(event.getClass());
+        if (eventHandlers == null) {
+            return;
+        }
+        // We need to clone the list in case a subscriber unregisters itself during traversal
+        eventHandlers = (ArrayList<EventHandler>) eventHandlers.clone();
+        for (final EventHandler eventHandler : eventHandlers) {
+            if (eventHandler.subscriber.getReference() != null) {
+                if (event.requiresPost) {
+                    mHandler.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            processEvent(eventHandler, event);
+                        }
+                    });
+                } else {
+                    processEvent(eventHandler, event);
+                }
+            }
+        }
+    }
+
+    /**
+     * Processes and dispatches the given event to the given event handler, on the thread of whoever
+     * calls this method.
+     */
+    private void processEvent(final EventHandler eventHandler, final Event event) {
+        // Skip if the event was already cancelled
+        if (event.cancelled) {
+            if (event.trace || DEBUG_TRACE_ALL) {
+                logWithPid("Event dispatch cancelled");
+            }
+            return;
+        }
+
+        try {
+            if (event.trace || DEBUG_TRACE_ALL) {
+                logWithPid(" -> " + eventHandler.toString());
+            }
+            Object sub = eventHandler.subscriber.getReference();
+            if (sub != null) {
+                long t1 = 0;
+                if (DEBUG_TRACE_ALL) {
+                    t1 = SystemClock.currentTimeMicro();
+                }
+                eventHandler.method.invoke(sub, event);
+                if (DEBUG_TRACE_ALL) {
+                    long duration = (SystemClock.currentTimeMicro() - t1);
+                    mCallDurationMicros += duration;
+                    mCallCount++;
+                    logWithPid(eventHandler.method.toString() + " duration: " + duration +
+                            " microseconds, avg: " + (mCallDurationMicros / mCallCount));
+                }
+            } else {
+                Log.e(TAG, "Failed to deliver event to null subscriber");
+            }
+        } catch (IllegalAccessException e) {
+            Log.e(TAG, "Failed to invoke method", e);
+        } catch (InvocationTargetException e) {
+            throw new RuntimeException(e.getCause());
+        }
+    }
+
+    /**
+     * Re-registers the broadcast receiver for any new messages that we want to listen for.
+     */
+    private void registerReceiverForInterprocessEvents(Context context) {
+        if (DEBUG_TRACE_ALL) {
+            logWithPid("registerReceiverForInterprocessEvents()");
+        }
+        // Rebuild the receiver filter with the new interprocess events
+        IntentFilter filter = new IntentFilter();
+        for (String eventName : mInterprocessEventNameMap.keySet()) {
+            filter.addAction(eventName);
+            if (DEBUG_TRACE_ALL) {
+                logWithPid("  filter: " + eventName);
+            }
+        }
+        // Re-register the receiver with the new filter
+        if (mHasRegisteredReceiver) {
+            context.unregisterReceiver(this);
+        }
+        context.registerReceiverAsUser(this, UserHandle.ALL, filter, PERMISSION_SELF, mHandler);
+        mHasRegisteredReceiver = true;
+    }
+
+    /**
+     * Returns whether this subscriber is currently registered.  If {@param removeFoundSubscriber}
+     * is true, then remove the subscriber before returning.
+     */
+    private boolean findRegisteredSubscriber(Object subscriber, boolean removeFoundSubscriber) {
+        for (int i = mSubscribers.size() - 1; i >= 0; i--) {
+            Subscriber sub = mSubscribers.get(i);
+            if (sub.getReference() == subscriber) {
+                if (removeFoundSubscriber) {
+                    mSubscribers.remove(i);
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * @return whether {@param method} is a valid (normal or interprocess) event bus handler method
+     */
+    private boolean isValidEventBusHandlerMethod(Method method, Class<?>[] parameterTypes,
+            MutableBoolean isInterprocessEventOut) {
+        int modifiers = method.getModifiers();
+        if (Modifier.isPublic(modifiers) &&
+                Modifier.isFinal(modifiers) &&
+                method.getReturnType().equals(Void.TYPE) &&
+                parameterTypes.length == 1) {
+            if (EventBus.InterprocessEvent.class.isAssignableFrom(parameterTypes[0]) &&
+                    method.getName().startsWith(INTERPROCESS_METHOD_PREFIX)) {
+                isInterprocessEventOut.value = true;
+                return true;
+            } else if (EventBus.Event.class.isAssignableFrom(parameterTypes[0]) &&
+                            method.getName().startsWith(METHOD_PREFIX)) {
+                isInterprocessEventOut.value = false;
+                return true;
+            } else {
+                if (DEBUG_TRACE_ALL) {
+                    if (!EventBus.Event.class.isAssignableFrom(parameterTypes[0])) {
+                        logWithPid("  Expected method take an Event-based parameter: " + method.getName());
+                    } else if (!method.getName().startsWith(INTERPROCESS_METHOD_PREFIX) &&
+                            !method.getName().startsWith(METHOD_PREFIX)) {
+                        logWithPid("  Expected method start with method prefix: " + method.getName());
+                    }
+                }
+            }
+        } else {
+            if (DEBUG_TRACE_ALL) {
+                if (!Modifier.isPublic(modifiers)) {
+                    logWithPid("  Expected method to be public: " + method.getName());
+                } else if (!Modifier.isFinal(modifiers)) {
+                    logWithPid("  Expected method to be final: " + method.getName());
+                } else if (!method.getReturnType().equals(Void.TYPE)) {
+                    logWithPid("  Expected method to return null: " + method.getName());
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Sorts the event handlers by priority and registration time.
+     */
+    private void sortEventHandlersByPriority(List<EventHandler> eventHandlers) {
+        Collections.sort(eventHandlers, EVENT_HANDLER_COMPARATOR);
+    }
+
+    /**
+     * Helper method to log the given {@param text} with the current process and user id.
+     */
+    private static void logWithPid(String text) {
+        Log.d(TAG, "[" + android.os.Process.myPid() + ", u" + UserHandle.myUserId() + "] " + text);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/AppWidgetProviderChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/AppWidgetProviderChangedEvent.java
new file mode 100644
index 0000000..52cfe18
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/AppWidgetProviderChangedEvent.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents.events.activity;
+
+import com.android.systemui.recents.RecentsAppWidgetHost;
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * This is sent by the {@link RecentsAppWidgetHost} whenever the search provider widget changes, and
+ * subscribers can update accordingly.
+ */
+public class AppWidgetProviderChangedEvent extends EventBus.Event {
+    // Simple event
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/PackagesChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/PackagesChangedEvent.java
new file mode 100644
index 0000000..3b68574
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/PackagesChangedEvent.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents.events.activity;
+
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.model.RecentsPackageMonitor;
+import com.android.systemui.recents.views.TaskStackView;
+
+/**
+ * This event is sent by {@link RecentsPackageMonitor} when a package on the the system changes.
+ * {@link TaskStackView}s listen for this event, and remove the tasks associated with the removed
+ * packages.
+ */
+public class PackagesChangedEvent extends EventBus.Event {
+
+    public final RecentsPackageMonitor monitor;
+    public final String packageName;
+    public final int userId;
+
+    public PackagesChangedEvent(RecentsPackageMonitor monitor, String packageName, int userId) {
+        this.monitor = monitor;
+        this.packageName = packageName;
+        this.userId = userId;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskEvent.java
new file mode 100644
index 0000000..12e5d3d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskEvent.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents.events.ui;
+
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.model.Task;
+import com.android.systemui.recents.views.TaskView;
+
+/**
+ * This is sent when a {@link TaskView} has been dismissed.
+ */
+public class DismissTaskEvent extends EventBus.Event {
+
+    public final Task task;
+    public final TaskView taskView;
+
+    public DismissTaskEvent(Task task, TaskView taskView) {
+        this.task = task;
+        this.taskView = taskView;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/ResizeTaskEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/ResizeTaskEvent.java
new file mode 100644
index 0000000..e0d83fd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/ResizeTaskEvent.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents.events.ui;
+
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.model.Task;
+
+/**
+ * This is sent when a {@link Task} is resized.
+ */
+public class ResizeTaskEvent extends EventBus.Event {
+
+    public final Task task;
+
+    public ResizeTaskEvent(Task task) {
+        this.task = task;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/ShowApplicationInfoEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/ShowApplicationInfoEvent.java
new file mode 100644
index 0000000..40c30b8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/ShowApplicationInfoEvent.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents.events.ui;
+
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.model.Task;
+
+/**
+ * This is sent when a user wants to show the application info for a {@link Task}.
+ */
+public class ShowApplicationInfoEvent extends EventBus.Event {
+
+    public final Task task;
+
+    public ShowApplicationInfoEvent(Task task) {
+        this.task = task;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index b6d25f5..e0f820d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -55,10 +55,7 @@
 import android.provider.Settings;
 import android.util.Log;
 import android.util.MutableBoolean;
-import android.util.MutableFloat;
-import android.util.MutableInt;
 import android.util.Pair;
-import android.util.Size;
 import android.view.Display;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityManager;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java
index e48e5f0..8f9a293 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java
@@ -21,6 +21,8 @@
 import android.os.Looper;
 import android.os.UserHandle;
 import com.android.internal.content.PackageMonitor;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.PackagesChangedEvent;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 
 import java.util.HashSet;
@@ -31,18 +33,9 @@
  * Recents list.
  */
 public class RecentsPackageMonitor extends PackageMonitor {
-    public interface PackageCallbacks {
-        public void onPackagesChanged(RecentsPackageMonitor monitor, String packageName,
-                                      int userId);
-    }
-
-    PackageCallbacks mCb;
-    SystemServicesProxy mSystemServicesProxy;
 
     /** Registers the broadcast receivers with the specified callbacks. */
-    public void register(Context context, PackageCallbacks cb) {
-        mSystemServicesProxy = new SystemServicesProxy(context);
-        mCb = cb;
+    public void register(Context context) {
         try {
             // We register for events from all users, but will cross-reference them with
             // packages for the current user and any profiles they have
@@ -60,17 +53,13 @@
         } catch (IllegalStateException e) {
             e.printStackTrace();
         }
-        mSystemServicesProxy = null;
-        mCb = null;
     }
 
     @Override
     public void onPackageRemoved(String packageName, int uid) {
-        if (mCb == null) return;
-
         // Notify callbacks that a package has changed
         final int eventUserId = getChangingUserId();
-        mCb.onPackagesChanged(this, packageName, eventUserId);
+        EventBus.getDefault().send(new PackagesChangedEvent(this, packageName, eventUserId));
     }
 
     @Override
@@ -81,11 +70,9 @@
 
     @Override
     public void onPackageModified(String packageName) {
-        if (mCb == null) return;
-
         // Notify callbacks that a package has changed
         final int eventUserId = getChangingUserId();
-        mCb.onPackagesChanged(this, packageName, eventUserId);
+        EventBus.getDefault().send(new PackagesChangedEvent(this, packageName, eventUserId));
     }
 
     /**
@@ -108,7 +95,8 @@
                     // If we know that the component still exists in the package, then skip
                     continue;
                 }
-                if (mSystemServicesProxy.getActivityInfo(cn, userId) != null) {
+                SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
+                if (ssp.getActivityInfo(cn, userId) != null) {
                     existingComponents.add(cn);
                 } else {
                     removedComponents.add(cn);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
index 760382e..39bef81 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -262,8 +262,6 @@
     TaskResourceLoadQueue mLoadQueue;
     TaskResourceLoader mLoader;
 
-    RecentsPackageMonitor mPackageMonitor;
-
     int mMaxThumbnailCacheSize;
     int mMaxIconCacheSize;
     int mNumVisibleTasksLoaded;
@@ -293,7 +291,6 @@
 
         // Initialize the proxy, cache and loaders
         mSystemServicesProxy = new SystemServicesProxy(context);
-        mPackageMonitor = new RecentsPackageMonitor();
         mLoadQueue = new TaskResourceLoadQueue();
         mApplicationIconCache = new DrawableLruCache(iconCacheSize);
         mThumbnailCache = new BitmapLruCache(thumbnailCacheSize);
@@ -519,17 +516,6 @@
         mLoadQueue.clearTasks();
     }
 
-    /** Registers any broadcast receivers. */
-    public void registerReceivers(Context context, RecentsPackageMonitor.PackageCallbacks cb) {
-        // Register the broadcast receiver to handle messages related to packages being added/removed
-        mPackageMonitor.register(context, cb);
-    }
-
-    /** Unregisters any broadcast receivers. */
-    public void unregisterReceivers() {
-        mPackageMonitor.unregister();
-    }
-
     /**
      * Handles signals from the system, trimming memory when requested to prevent us from running
      * out of memory.
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index 20d9203..8eec87e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -18,10 +18,10 @@
 
 import android.content.Context;
 import android.graphics.Color;
+import com.android.systemui.R;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.misc.NamedCounter;
 import com.android.systemui.recents.misc.Utilities;
-import com.android.systemui.R;
 
 import java.util.ArrayList;
 import java.util.Collections;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 73c9be9..de8730d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -18,18 +18,13 @@
 
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
-import android.app.TaskStackBuilder;
 import android.content.Context;
-import android.content.Intent;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Rect;
-import android.net.Uri;
 import android.os.Bundle;
 import android.os.IRemoteCallback;
 import android.os.RemoteException;
-import android.os.UserHandle;
-import android.provider.Settings;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.SparseArray;
@@ -46,8 +41,9 @@
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.RecentsAppWidgetHostView;
 import com.android.systemui.recents.RecentsConfiguration;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.ui.DismissTaskEvent;
 import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.model.RecentsPackageMonitor;
 import com.android.systemui.recents.model.RecentsTaskLoader;
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.model.TaskStack;
@@ -59,8 +55,7 @@
  * This view is the the top level layout that contains TaskStacks (which are laid out according
  * to their SpaceNode bounds.
  */
-public class RecentsView extends FrameLayout implements TaskStackView.TaskStackViewCallbacks,
-        RecentsPackageMonitor.PackageCallbacks {
+public class RecentsView extends FrameLayout implements TaskStackView.TaskStackViewCallbacks {
 
     private static final String TAG = "RecentsView";
 
@@ -73,7 +68,6 @@
         public void onAllTaskViewsDismissed();
         public void onExitToHomeAnimationTriggered();
         public void onScreenPinningRequest();
-        public void onTaskResize(Task t);
         public void runAfterPause(Runnable r);
     }
 
@@ -611,7 +605,7 @@
                     } else {
                         // Dismiss the task and return the user to home if we fail to
                         // launch the task
-                        onTaskViewDismissed(task);
+                        EventBus.getDefault().send(new DismissTaskEvent(task, tv));
                         if (mCb != null) {
                             mCb.onTaskLaunchFailed();
                         }
@@ -648,37 +642,15 @@
     }
 
     @Override
-    public void onTaskViewAppInfoClicked(Task t) {
-        // Create a new task stack with the application info details activity
-        Intent baseIntent = t.key.baseIntent;
-        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
-                Uri.fromParts("package", baseIntent.getComponent().getPackageName(), null));
-        intent.setComponent(intent.resolveActivity(getContext().getPackageManager()));
-        TaskStackBuilder.create(getContext())
-                .addNextIntentWithParentStack(intent).startActivities(null,
-                new UserHandle(t.key.userId));
-    }
-
-    @Override
-    public void onTaskViewDismissed(Task t) {
-        // Remove any stored data from the loader.  We currently don't bother notifying the views
-        // that the data has been unloaded because at the point we call onTaskViewDismissed(), the views
-        // either don't need to be updated, or have already been removed.
-        RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
-        loader.deleteTaskData(t, false);
-
-        // Remove the old task from activity manager
-        loader.getSystemServicesProxy().removeTask(t.key.id);
-    }
-
-    @Override
     public void onAllTaskViewsDismissed(ArrayList<Task> removedTasks) {
+        /* TODO: Not currently enabled
         if (removedTasks != null) {
             int taskCount = removedTasks.size();
             for (int i = 0; i < taskCount; i++) {
                 onTaskViewDismissed(removedTasks.get(i));
             }
         }
+        */
 
         mCb.onAllTaskViewsDismissed();
 
@@ -725,21 +697,4 @@
                     .start();
         }
     }
-
-    @Override
-    public void onTaskResize(Task t) {
-        if (mCb != null) {
-            mCb.onTaskResize(t);
-        }
-    }
-
-    /**** RecentsPackageMonitor.PackageCallbacks Implementation ****/
-
-    @Override
-    public void onPackagesChanged(RecentsPackageMonitor monitor, String packageName, int userId) {
-        // Propagate this event down to each task stack view
-        if (mTaskStackView != null) {
-            mTaskStackView.onPackagesChanged(monitor, packageName, userId);
-        }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
index 7ce50d8..b28cc21 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
@@ -22,7 +22,6 @@
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import com.android.systemui.R;
-import com.android.systemui.recents.RecentsActivity;
 import com.android.systemui.recents.RecentsActivityLaunchState;
 import com.android.systemui.recents.RecentsConfiguration;
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index b5f29a0..67e3f82 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -29,15 +29,17 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.FrameLayout;
-import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.R;
 import com.android.systemui.recents.Constants;
+import com.android.systemui.recents.RecentsActivity;
 import com.android.systemui.recents.RecentsActivityLaunchState;
 import com.android.systemui.recents.RecentsConfiguration;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.PackagesChangedEvent;
+import com.android.systemui.recents.events.ui.DismissTaskEvent;
 import com.android.systemui.recents.misc.DozeTrigger;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.misc.Utilities;
-import com.android.systemui.recents.model.RecentsPackageMonitor;
 import com.android.systemui.recents.model.RecentsTaskLoader;
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.model.TaskStack;
@@ -54,19 +56,15 @@
 /* The visual representation of a task stack view */
 public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCallbacks,
         TaskView.TaskViewCallbacks, TaskStackViewScroller.TaskStackViewScrollerCallbacks,
-        ViewPool.ViewPoolConsumer<TaskView, Task>, RecentsPackageMonitor.PackageCallbacks {
+        ViewPool.ViewPoolConsumer<TaskView, Task> {
 
     /** The TaskView callbacks */
     interface TaskStackViewCallbacks {
         public void onTaskViewClicked(TaskStackView stackView, TaskView tv, TaskStack stack, Task t,
                                       boolean lockToTask, boolean boundsValid, Rect bounds);
-        public void onTaskViewAppInfoClicked(Task t);
-        public void onTaskViewDismissed(Task t);
         public void onAllTaskViewsDismissed(ArrayList<Task> removedTasks);
         public void onTaskStackFilterTriggered();
         public void onTaskStackUnfilterTriggered();
-
-        public void onTaskResize(Task t);
     }
     RecentsConfiguration mConfig;
 
@@ -77,7 +75,7 @@
     TaskStackViewTouchHandler mTouchHandler;
     TaskStackViewCallbacks mCb;
     ViewPool<TaskView, Task> mViewPool;
-    ArrayList<TaskViewTransform> mCurrentTaskTransforms = new ArrayList<TaskViewTransform>();
+    ArrayList<TaskViewTransform> mCurrentTaskTransforms = new ArrayList<>();
     DozeTrigger mUIDozeTrigger;
     DismissView mDismissAllButton;
     boolean mDismissAllButtonAnimating;
@@ -97,9 +95,9 @@
     Matrix mTmpMatrix = new Matrix();
     Rect mTmpRect = new Rect();
     TaskViewTransform mTmpTransform = new TaskViewTransform();
-    HashMap<Task, TaskView> mTmpTaskViewMap = new HashMap<Task, TaskView>();
-    ArrayList<TaskView> mTaskViews = new ArrayList<TaskView>();
-    List<TaskView> mImmutableTaskViews = new ArrayList<TaskView>();
+    HashMap<Task, TaskView> mTmpTaskViewMap = new HashMap<>();
+    ArrayList<TaskView> mTaskViews = new ArrayList<>();
+    List<TaskView> mImmutableTaskViews = new ArrayList<>();
     LayoutInflater mInflater;
     boolean mLayersDisabled;
 
@@ -147,6 +145,18 @@
         mCb = cb;
     }
 
+    @Override
+    protected void onAttachedToWindow() {
+        EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1);
+        super.onAttachedToWindow();
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        EventBus.getDefault().unregister(this);
+    }
+
     /** Sets the task stack */
     void setStack(TaskStack stack) {
         // Set the new stack
@@ -1161,11 +1171,6 @@
             // Fade the dismiss button back in
             showDismissAllButton();
         }
-
-        // Notify the callback that we've removed the task and it can clean up after it. Note, we
-        // do this after onAllTaskViewsDismissed() is called, to allow the home activity to be
-        // started before the call to remove the task.
-        mCb.onTaskViewDismissed(removedTask);
     }
 
     @Override
@@ -1343,27 +1348,6 @@
     /**** TaskViewCallbacks Implementation ****/
 
     @Override
-    public void onTaskViewAppIconClicked(TaskView tv) {
-        if (Constants.DebugFlags.App.EnableTaskFiltering) {
-            if (mStack.hasFilteredTasks()) {
-                mStack.unfilterTasks();
-            } else {
-                mStack.filterTasks(tv.getTask());
-            }
-        }
-    }
-
-    @Override
-    public void onTaskViewAppInfoClicked(TaskView tv) {
-        if (mCb != null) {
-            mCb.onTaskViewAppInfoClicked(tv.getTask());
-
-            // Keep track of app-info invocations
-            MetricsLogger.count(getContext(), "overview_app_info", 1);
-        }
-    }
-
-    @Override
     public void onTaskViewClicked(TaskView tv, Task task, boolean lockToTask) {
         // Cancel any doze triggers
         mUIDozeTrigger.stopDozing();
@@ -1374,33 +1358,6 @@
     }
 
     @Override
-    public void onTaskViewDismissed(TaskView tv) {
-        Task task = tv.getTask();
-        int taskIndex = mStack.indexOfTask(task);
-        boolean taskWasFocused = tv.isFocusedTask();
-        // Announce for accessibility
-        tv.announceForAccessibility(getContext().getString(R.string.accessibility_recents_item_dismissed,
-                tv.getTask().activityLabel));
-        // Remove the task from the view
-        mStack.removeTask(task);
-        // If the dismissed task was focused, then we should focus the new task in the same index
-        if (taskWasFocused) {
-            ArrayList<Task> tasks = mStack.getTasks();
-            int nextTaskIndex = Math.min(tasks.size() - 1, taskIndex - 1);
-            if (nextTaskIndex >= 0) {
-                Task nextTask = tasks.get(nextTaskIndex);
-                TaskView nextTv = getChildViewForTask(nextTask);
-                if (nextTv != null) {
-                    // Focus the next task, and only animate the visible state if we are launched
-                    // from Alt-Tab
-                    RecentsActivityLaunchState launchState = mConfig.getLaunchState();
-                    nextTv.setFocusedTask(launchState.launchedWithAltTab);
-                }
-            }
-        }
-    }
-
-    @Override
     public void onTaskViewClipStateChanged(TaskView tv) {
         if (!mStackViewsDirty) {
             invalidate();
@@ -1414,13 +1371,6 @@
         }
     }
 
-    @Override
-    public void onTaskResize(TaskView tv) {
-        if (mCb != null) {
-            mCb.onTaskResize(tv.getTask());
-        }
-    }
-
     /**** TaskStackViewScroller.TaskStackViewScrollerCallbacks ****/
 
     @Override
@@ -1430,13 +1380,12 @@
         postInvalidateOnAnimation();
     }
 
-    /**** RecentsPackageMonitor.PackageCallbacks Implementation ****/
+    /**** EventBus Events ****/
 
-    @Override
-    public void onPackagesChanged(RecentsPackageMonitor monitor, String packageName, int userId) {
+    public final void onBusEvent(PackagesChangedEvent event) {
         // Compute which components need to be removed
-        HashSet<ComponentName> removedComponents = monitor.computeComponentsRemoved(
-                mStack.getTaskKeys(), packageName, userId);
+        HashSet<ComponentName> removedComponents = event.monitor.computeComponentsRemoved(
+                mStack.getTaskKeys(), event.packageName, event.userId);
 
         // For other tasks, just remove them directly if they no longer exist
         ArrayList<Task> tasks = mStack.getTasks();
@@ -1459,4 +1408,33 @@
             }
         }
     }
+
+    public final void onBusEvent(DismissTaskEvent event) {
+        TaskView tv = event.taskView;
+        Task task = tv.getTask();
+        int taskIndex = mStack.indexOfTask(task);
+        boolean taskWasFocused = tv.isFocusedTask();
+
+        // Announce for accessibility
+        tv.announceForAccessibility(getContext().getString(R.string.accessibility_recents_item_dismissed,
+                tv.getTask().activityLabel));
+
+        // Remove the task from the view
+        mStack.removeTask(task);
+        // If the dismissed task was focused, then we should focus the new task in the same index
+        if (taskWasFocused) {
+            ArrayList<Task> tasks = mStack.getTasks();
+            int nextTaskIndex = Math.min(tasks.size() - 1, taskIndex - 1);
+            if (nextTaskIndex >= 0) {
+                Task nextTask = tasks.get(nextTaskIndex);
+                TaskView nextTv = getChildViewForTask(nextTask);
+                if (nextTv != null) {
+                    // Focus the next task, and only animate the visible state if we are launched
+                    // from Alt-Tab
+                    RecentsActivityLaunchState launchState = mConfig.getLaunchState();
+                    nextTv.setFocusedTask(launchState.launchedWithAltTab);
+                }
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewFilterAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewFilterAlgorithm.java
index e9f6a46..a32b242 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewFilterAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewFilterAlgorithm.java
@@ -16,9 +16,9 @@
 
 package com.android.systemui.recents.views;
 
+import com.android.systemui.R;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.model.Task;
-import com.android.systemui.R;
 
 import java.util.ArrayList;
 import java.util.HashMap;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
index 7f4c0a5..a8e6f47 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
@@ -18,11 +18,11 @@
 
 import android.content.Context;
 import android.graphics.Rect;
+import com.android.systemui.R;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.misc.Utilities;
 import com.android.systemui.recents.model.Task;
-import com.android.systemui.R;
 
 import java.util.ArrayList;
 import java.util.HashMap;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
index f0ae87f..e4fbc76 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
@@ -24,8 +24,8 @@
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.widget.OverScroller;
-import com.android.systemui.recents.misc.Utilities;
 import com.android.systemui.R;
+import com.android.systemui.recents.misc.Utilities;
 
 /* The scrolling logic for a TaskStackView */
 public class TaskStackViewScroller {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index 86eced8..48c5b46 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -24,9 +24,11 @@
 import android.view.ViewConfiguration;
 import android.view.ViewParent;
 import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.R;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.Recents;
-import com.android.systemui.R;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.ui.DismissTaskEvent;
 
 import java.util.List;
 
@@ -435,7 +437,7 @@
         // Re-enable touch events from this task view
         tv.setTouchEnabled(true);
         // Remove the task view from the stack
-        mSv.onTaskViewDismissed(tv);
+        EventBus.getDefault().send(new DismissTaskEvent(tv.getTask(), tv));
         // Keep track of deletions by keyboard
         MetricsLogger.histogram(tv.getContext(), "overview_task_dismissed_source",
                 Constants.Metrics.DismissSourceSwipeGesture);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index bbbaccf..910db87 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -30,34 +30,29 @@
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.ViewOutlineProvider;
-import android.view.accessibility.AccessibilityManager;
 import android.view.animation.AccelerateInterpolator;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.widget.FrameLayout;
-import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.R;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.RecentsActivityLaunchState;
 import com.android.systemui.recents.RecentsConfiguration;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.ui.DismissTaskEvent;
 import com.android.systemui.recents.misc.Utilities;
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
 
 /* A task view */
 public class TaskView extends FrameLayout implements Task.TaskCallbacks,
-        View.OnClickListener, View.OnLongClickListener {
+        View.OnClickListener {
 
     /** The TaskView callbacks */
     interface TaskViewCallbacks {
-        public void onTaskViewAppIconClicked(TaskView tv);
-        public void onTaskViewAppInfoClicked(TaskView tv);
         public void onTaskViewClicked(TaskView tv, Task task, boolean lockToTask);
-        public void onTaskViewDismissed(TaskView tv);
         public void onTaskViewClipStateChanged(TaskView tv);
         public void onTaskViewFocusChanged(TaskView tv, boolean focused);
-
-        public void onTaskResize(TaskView tv);
     }
 
     RecentsConfiguration mConfig;
@@ -535,9 +530,7 @@
         startDeleteTaskAnimation(new Runnable() {
             @Override
             public void run() {
-                if (mCb != null) {
-                    mCb.onTaskViewDismissed(tv);
-                }
+                EventBus.getDefault().send(new DismissTaskEvent(mTask, tv));
             }
         }, 0);
     }
@@ -725,17 +718,7 @@
             mThumbnailView.rebindToTask(mTask);
             mHeaderView.rebindToTask(mTask);
             // Rebind any listeners
-            AccessibilityManager am = (AccessibilityManager) getContext().
-                    getSystemService(Context.ACCESSIBILITY_SERVICE);
-            if (Constants.DebugFlags.App.EnableTaskFiltering || (am != null && am.isEnabled())) {
-                mHeaderView.mApplicationIcon.setOnClickListener(this);
-            }
-            mHeaderView.mDismissButton.setOnClickListener(this);
-            if (mConfig.multiWindowEnabled) {
-                mHeaderView.mMoveTaskButton.setOnClickListener(this);
-            }
             mActionButtonView.setOnClickListener(this);
-            mHeaderView.mApplicationIcon.setOnLongClickListener(this);
         }
         mTaskDataLoaded = true;
     }
@@ -748,13 +731,7 @@
             mThumbnailView.unbindFromTask();
             mHeaderView.unbindFromTask();
             // Unbind any listeners
-            mHeaderView.mApplicationIcon.setOnClickListener(null);
-            mHeaderView.mDismissButton.setOnClickListener(null);
-            if (mConfig.multiWindowEnabled) {
-                mHeaderView.mMoveTaskButton.setOnClickListener(null);
-            }
             mActionButtonView.setOnClickListener(null);
-            mHeaderView.mApplicationIcon.setOnLongClickListener(null);
         }
         mTaskDataLoaded = false;
     }
@@ -768,60 +745,12 @@
 
     @Override
      public void onClick(final View v) {
-        final TaskView tv = this;
-        final boolean delayViewClick = (v != this) && (v != mActionButtonView);
-        if (delayViewClick) {
-            // We purposely post the handler delayed to allow for the touch feedback to draw
-            postDelayed(new Runnable() {
-                @Override
-                public void run() {
-                    if (v == mHeaderView.mApplicationIcon) {
-                        if (Constants.DebugFlags.App.EnableTaskFiltering) {
-                            if (mCb != null) {
-                                mCb.onTaskViewAppIconClicked(tv);
-                            }
-                        } else {
-                            AccessibilityManager am = (AccessibilityManager) getContext().
-                                    getSystemService(Context.ACCESSIBILITY_SERVICE);
-                            if (am != null && am.isEnabled()) {
-                                if (mCb != null) {
-                                    mCb.onTaskViewAppInfoClicked(tv);
-                                }
-                            }
-                        }
-                    } else if (v == mHeaderView.mDismissButton) {
-                        dismissTask();
-                        // Keep track of deletions by the dismiss button
-                        MetricsLogger.histogram(getContext(), "overview_task_dismissed_source",
-                                Constants.Metrics.DismissSourceHeaderButton);
-                    } else if (v == mHeaderView.mMoveTaskButton) {
-                        if (mCb != null) {
-                            mCb.onTaskResize(tv);
-                        }
-                    }
-                }
-            }, 125);
-        } else {
-            if (v == mActionButtonView) {
-                // Reset the translation of the action button before we animate it out
-                mActionButtonView.setTranslationZ(0f);
-            }
-            if (mCb != null) {
-                mCb.onTaskViewClicked(tv, tv.getTask(), (v == mActionButtonView));
-            }
+        if (v == mActionButtonView) {
+            // Reset the translation of the action button before we animate it out
+            mActionButtonView.setTranslationZ(0f);
         }
-    }
-
-    /**** View.OnLongClickListener Implementation ****/
-
-    @Override
-    public boolean onLongClick(View v) {
-        if (v == mHeaderView.mApplicationIcon) {
-            if (mCb != null) {
-                mCb.onTaskViewAppInfoClicked(this);
-                return true;
-            }
+        if (mCb != null) {
+            mCb.onTaskViewClicked(this, mTask, (v == mActionButtonView));
         }
-        return false;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index f68dd64..7de8b7b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -39,14 +39,19 @@
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.ViewOutlineProvider;
+import android.view.accessibility.AccessibilityManager;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.TextView;
+import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.R;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.RecentsConfiguration;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.ui.ResizeTaskEvent;
+import com.android.systemui.recents.events.ui.ShowApplicationInfoEvent;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.misc.Utilities;
 import com.android.systemui.recents.model.RecentsTaskLoader;
@@ -54,10 +59,12 @@
 
 
 /* The task bar view */
-public class TaskViewHeader extends FrameLayout {
+public class TaskViewHeader extends FrameLayout
+        implements View.OnClickListener, View.OnLongClickListener {
 
     RecentsConfiguration mConfig;
     private SystemServicesProxy mSsp;
+    Task mTask;
 
     // Header views
     ImageView mMoveTaskButton;
@@ -144,15 +151,15 @@
     protected void onFinishInflate() {
         // Initialize the icon and description views
         mApplicationIcon = (ImageView) findViewById(R.id.application_icon);
+        mApplicationIcon.setOnLongClickListener(this);
         mActivityDescription = (TextView) findViewById(R.id.activity_description);
         mDismissButton = (ImageView) findViewById(R.id.dismiss_task);
+        mDismissButton.setOnClickListener(this);
         mMoveTaskButton = (ImageView) findViewById(R.id.move_task);
 
         // Hide the backgrounds if they are ripple drawables
-        if (!Constants.DebugFlags.App.EnableTaskFiltering) {
-            if (mApplicationIcon.getBackground() instanceof RippleDrawable) {
-                mApplicationIcon.setBackground(null);
-            }
+        if (mApplicationIcon.getBackground() instanceof RippleDrawable) {
+            mApplicationIcon.setBackground(null);
         }
 
         mBackgroundColorDrawable = (GradientDrawable) getContext().getDrawable(R.drawable
@@ -203,6 +210,8 @@
 
     /** Binds the bar view to the task */
     public void rebindToTask(Task t) {
+        mTask = t;
+
         // If an activity icon is defined, then we use that as the primary icon to show in the bar,
         // otherwise, we fall back to the application icon
         if (t.activityIcon != null) {
@@ -238,6 +247,25 @@
         mMoveTaskButton.setVisibility((mConfig.multiWindowEnabled) ? View.VISIBLE : View.INVISIBLE);
         if (mConfig.multiWindowEnabled) {
             updateResizeTaskBarIcon(t);
+            mMoveTaskButton.setOnClickListener(this);
+        }
+
+        // In accessibility, a single click on the focused app info button will show it
+        AccessibilityManager am = (AccessibilityManager) getContext().
+                getSystemService(Context.ACCESSIBILITY_SERVICE);
+        if (am != null && am.isEnabled()) {
+            mApplicationIcon.setOnClickListener(this);
+        }
+    }
+
+    /** Unbinds the bar view from the task */
+    void unbindFromTask() {
+        mTask = null;
+        mApplicationIcon.setImageDrawable(null);
+        mApplicationIcon.setOnClickListener(null);
+
+        if (mConfig.multiWindowEnabled) {
+            mMoveTaskButton.setOnClickListener(null);
         }
     }
 
@@ -274,11 +302,6 @@
         mMoveTaskButton.setImageResource(resId);
     }
 
-    /** Unbinds the bar view from the task */
-    void unbindFromTask() {
-        mApplicationIcon.setImageDrawable(null);
-    }
-
     /** Animates this task bar dismiss button when launching a task. */
     void startLaunchTaskDismissAnimation() {
         if (mDismissButton.getVisibility() == View.VISIBLE) {
@@ -441,4 +464,30 @@
             }
         }
     }
+
+    @Override
+    public void onClick(View v) {
+        if (v == mApplicationIcon) {
+            // In accessibility, a single click on the focused app info button will show it
+            EventBus.getDefault().send(new ShowApplicationInfoEvent(mTask));
+        } else if (v == mDismissButton) {
+            TaskView tv = (TaskView) getParent().getParent();
+            tv.dismissTask();
+
+            // Keep track of deletions by the dismiss button
+            MetricsLogger.histogram(getContext(), "overview_task_dismissed_source",
+                    Constants.Metrics.DismissSourceHeaderButton);
+        } else if (v == mMoveTaskButton) {
+            EventBus.getDefault().send(new ResizeTaskEvent(mTask));
+        }
+    }
+
+    @Override
+    public boolean onLongClick(View v) {
+        if (v == mApplicationIcon) {
+            EventBus.getDefault().send(new ShowApplicationInfoEvent(mTask));
+            return true;
+        }
+        return false;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
index 6c83bee..690c297 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
@@ -34,9 +34,9 @@
 import android.view.View;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
+import com.android.systemui.R;
 import com.android.systemui.recents.misc.Utilities;
 import com.android.systemui.recents.model.Task;
-import com.android.systemui.R;
 
 
 /**
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index a2967e8..5a27301 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -1583,9 +1583,16 @@
 
             nContextDeinitToClient(mContext);
             mMessageThread.mRun = false;
-            try {
-                mMessageThread.join();
-            } catch(InterruptedException e) {
+
+            // Wait for mMessageThread to join.  Try in a loop, in case this thread gets interrupted
+            // during the wait.
+            boolean hasJoined = false;
+            while (!hasJoined) {
+                try {
+                    mMessageThread.join();
+                    hasJoined = true;
+                } catch(InterruptedException e) {
+                }
             }
 
             nContextDestroy();
diff --git a/services/accessibility/java/com/android/server/accessibility/AutoclickController.java b/services/accessibility/java/com/android/server/accessibility/AutoclickController.java
index 3283378..892e9da 100644
--- a/services/accessibility/java/com/android/server/accessibility/AutoclickController.java
+++ b/services/accessibility/java/com/android/server/accessibility/AutoclickController.java
@@ -32,6 +32,7 @@
 import android.view.MotionEvent.PointerCoords;
 import android.view.MotionEvent.PointerProperties;
 import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
 
 /**
  * Implements "Automatically click on mouse stop" feature.
@@ -56,8 +57,6 @@
  */
 public class AutoclickController implements EventStreamTransformation {
 
-    public static final int DEFAULT_CLICK_DELAY_MS = 600;
-
     private static final String LOG_TAG = AutoclickController.class.getSimpleName();
 
     private EventStreamTransformation mNext;
@@ -78,7 +77,8 @@
         if (event.isFromSource(InputDevice.SOURCE_MOUSE)) {
             if (mClickScheduler == null) {
                 Handler handler = new Handler(mContext.getMainLooper());
-                mClickScheduler = new ClickScheduler(handler, DEFAULT_CLICK_DELAY_MS);
+                mClickScheduler =
+                        new ClickScheduler(handler, AccessibilityManager.AUTOCLICK_DELAY_DEFAULT);
                 mClickDelayObserver = new ClickDelayObserver(mUserId, handler);
                 mClickDelayObserver.start(mContext.getContentResolver(), mClickScheduler);
             }
@@ -230,7 +230,7 @@
             if (mAutoclickDelaySettingUri.equals(uri)) {
                 int delay = Settings.Secure.getIntForUser(
                         mContentResolver, Settings.Secure.ACCESSIBILITY_AUTOCLICK_DELAY,
-                        DEFAULT_CLICK_DELAY_MS, mUserId);
+                        AccessibilityManager.AUTOCLICK_DELAY_DEFAULT, mUserId);
                 mClickScheduler.updateDelay(delay);
             }
         }
diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
index c3f5c43..f6b32f7 100644
--- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
@@ -112,12 +112,6 @@
     // Timeout before trying to decide what the user is trying to do.
     private final int mDetermineUserIntentTimeout;
 
-    // Timeout within which we try to detect a tap.
-    private final int mTapTimeout;
-
-    // Slop between the down and up tap to be a tap.
-    private final int mTouchSlop;
-
     // Slop between the first and second tap to be a double tap.
     private final int mDoubleTapSlop;
 
@@ -142,9 +136,6 @@
     // Command for delayed sending of touch interaction end events.
     private final SendAccessibilityEventDelayed mSendTouchInteractionEndDelayed;
 
-    // Command for delayed sending of a long press.
-    private final PerformLongPressDelayed mPerformLongPressDelayed;
-
     // Command for exiting gesture detection mode after a timeout.
     private final ExitGestureDetectionModeDelayed mExitGestureDetectionModeDelayed;
 
@@ -173,9 +164,6 @@
     // Handle to the accessibility manager service.
     private final AccessibilityManagerService mAms;
 
-    // Temporary rectangle to avoid instantiation.
-    private final Rect mTempRect = new Rect();
-
     // Temporary point to avoid instantiation.
     private final Point mTempPoint = new Point();
 
@@ -226,12 +214,9 @@
         mAms = service;
         mReceivedPointerTracker = new ReceivedPointerTracker();
         mInjectedPointerTracker = new InjectedPointerTracker();
-        mTapTimeout = ViewConfiguration.getTapTimeout();
         mDetermineUserIntentTimeout = ViewConfiguration.getDoubleTapTimeout();
-        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
         mDoubleTapSlop = ViewConfiguration.get(context).getScaledDoubleTapSlop();
         mHandler = new Handler(context.getMainLooper());
-        mPerformLongPressDelayed = new PerformLongPressDelayed();
         mExitGestureDetectionModeDelayed = new ExitGestureDetectionModeDelayed();
         mGestureLibrary = GestureLibraries.fromRawResource(context, R.raw.accessibility_gestures);
         mGestureLibrary.setOrientationStyle(8);
@@ -299,7 +284,6 @@
         // Remove all pending callbacks.
         mSendHoverEnterAndMoveDelayed.cancel();
         mSendHoverExitDelayed.cancel();
-        mPerformLongPressDelayed.cancel();
         mExitGestureDetectionModeDelayed.cancel();
         mSendTouchExplorationEndDelayed.cancel();
         mSendTouchInteractionEndDelayed.cancel();
@@ -437,7 +421,6 @@
                 // we resent the delayed callback and wait again.
                 mSendHoverEnterAndMoveDelayed.cancel();
                 mSendHoverExitDelayed.cancel();
-                mPerformLongPressDelayed.cancel();
 
                 if (mSendTouchExplorationEndDelayed.isPending()) {
                     mSendTouchExplorationEndDelayed.forceSendAndRemove();
@@ -447,18 +430,7 @@
                     mSendTouchInteractionEndDelayed.forceSendAndRemove();
                 }
 
-                // If we have the first tap, schedule a long press and break
-                // since we do not want to schedule hover enter because
-                // the delayed callback will kick in before the long click.
-                // This would lead to a state transition resulting in long
-                // pressing the item below the double taped area which is
-                // not necessary where accessibility focus is.
-                if (mDoubleTapDetector.firstTapDetected()) {
-                    // We got a tap now post a long press action.
-                    mPerformLongPressDelayed.post(event, policyFlags);
-                    break;
-                }
-                if (!mTouchExplorationInProgress) {
+                if (!mDoubleTapDetector.firstTapDetected() && !mTouchExplorationInProgress) {
                     if (!mSendHoverEnterAndMoveDelayed.isPending()) {
                         // Deliver hover enter with a delay to have a chance
                         // to detect what the user is trying to do.
@@ -478,7 +450,6 @@
                 // decide what we will actually do next.
                 mSendHoverEnterAndMoveDelayed.cancel();
                 mSendHoverExitDelayed.cancel();
-                mPerformLongPressDelayed.cancel();
             } break;
             case MotionEvent.ACTION_MOVE: {
                 final int pointerId = receivedTracker.getPrimaryPointerId();
@@ -521,7 +492,6 @@
                                     mVelocityTracker.clear();
                                     mSendHoverEnterAndMoveDelayed.cancel();
                                     mSendHoverExitDelayed.cancel();
-                                    mPerformLongPressDelayed.cancel();
                                     mExitGestureDetectionModeDelayed.post();
                                     // Send accessibility event to announce the start
                                     // of gesture recognition.
@@ -532,28 +502,12 @@
                                     // exploring so start sending events.
                                     mSendHoverEnterAndMoveDelayed.forceSendAndRemove();
                                     mSendHoverExitDelayed.cancel();
-                                    mPerformLongPressDelayed.cancel();
                                     sendMotionEvent(event, MotionEvent.ACTION_HOVER_MOVE,
                                             pointerIdBits, policyFlags);
                                 }
                                 break;
                             }
                         } else {
-                            // Cancel the long press if pending and the user
-                            // moved more than the slop.
-                            if (mPerformLongPressDelayed.isPending()) {
-                                final float deltaX =
-                                        receivedTracker.getReceivedPointerDownX(pointerId)
-                                        - rawEvent.getX(pointerIndex);
-                                final float deltaY =
-                                        receivedTracker.getReceivedPointerDownY(pointerId)
-                                        - rawEvent.getY(pointerIndex);
-                                final double moveDelta = Math.hypot(deltaX, deltaY);
-                                // The user has moved enough for us to decide.
-                                if (moveDelta > mTouchSlop) {
-                                    mPerformLongPressDelayed.cancel();
-                                }
-                            }
                             if (mTouchExplorationInProgress) {
                                 sendTouchExplorationGestureStartAndHoverEnterIfNeeded(policyFlags);
                                 sendMotionEvent(event, MotionEvent.ACTION_HOVER_MOVE, pointerIdBits,
@@ -569,9 +523,7 @@
                             // scheduled sending events.
                             mSendHoverEnterAndMoveDelayed.cancel();
                             mSendHoverExitDelayed.cancel();
-                            mPerformLongPressDelayed.cancel();
                         } else {
-                            mPerformLongPressDelayed.cancel();
                             if (mTouchExplorationInProgress) {
                                 // If the user is touch exploring the second pointer may be
                                 // performing a double tap to activate an item without need
@@ -620,9 +572,7 @@
                             // scheduled sending events.
                             mSendHoverEnterAndMoveDelayed.cancel();
                             mSendHoverExitDelayed.cancel();
-                            mPerformLongPressDelayed.cancel();
                         } else {
-                            mPerformLongPressDelayed.cancel();
                             // We are sending events so send exit and gesture
                             // end since we transition to another state.
                             sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
@@ -643,7 +593,6 @@
                 final int pointerId = event.getPointerId(event.getActionIndex());
                 final int pointerIdBits = (1 << pointerId);
 
-                mPerformLongPressDelayed.cancel();
                 mVelocityTracker.clear();
 
                 if (mSendHoverEnterAndMoveDelayed.isPending()) {
@@ -1110,6 +1059,7 @@
         private final GestureDetector mGestureDetector;
         private boolean mFirstTapDetected;
         private boolean mDoubleTapDetected;
+        private int mPolicyFlags;
 
         DoubleTapDetector(Context context) {
             mGestureDetector = new GestureDetector(context, this);
@@ -1117,6 +1067,7 @@
         }
 
         public void onMotionEvent(MotionEvent event, int policyFlags) {
+            mPolicyFlags = policyFlags;
             switch (event.getActionMasked()) {
                 case MotionEvent.ACTION_DOWN:
                     mDoubleTapDetected = false;
@@ -1135,6 +1086,11 @@
         }
 
         @Override
+        public void onLongPress(MotionEvent e) {
+            maybeSendLongPress(e, mPolicyFlags);
+        }
+
+        @Override
         public boolean onSingleTapUp(MotionEvent event) {
             mFirstTapDetected = true;
             return false;
@@ -1154,6 +1110,38 @@
             return true;
         }
 
+        private void maybeSendLongPress(MotionEvent event, int policyFlags) {
+            if (!mDoubleTapDetected) {
+                return;
+            }
+
+            clear();
+
+            // Pointers should not be zero when running this command.
+            if (mReceivedPointerTracker.getLastReceivedEvent().getPointerCount() == 0) {
+                return;
+            }
+
+            final int pointerIndex = event.getActionIndex();
+            final int pointerId = event.getPointerId(pointerIndex);
+
+            Point clickLocation = mTempPoint;
+            final int result = computeClickLocation(clickLocation);
+
+            if (result == CLICK_LOCATION_NONE) {
+                return;
+            }
+
+            mLongPressingPointerId = pointerId;
+            mLongPressingPointerDeltaX = (int) event.getX(pointerIndex) - clickLocation.x;
+            mLongPressingPointerDeltaY = (int) event.getY(pointerIndex) - clickLocation.y;
+
+            sendHoverExitAndTouchExplorationGestureEndIfNeeded(policyFlags);
+
+            mCurrentState = STATE_DELEGATING;
+            sendDownForAllNotInjectedPointers(event, policyFlags);
+        }
+
         private void maybeFinishDoubleTap(MotionEvent event, int policyFlags) {
             if (!mDoubleTapDetected) {
                 return;
@@ -1169,7 +1157,6 @@
             // Remove pending event deliveries.
             mSendHoverEnterAndMoveDelayed.cancel();
             mSendHoverExitDelayed.cancel();
-            mPerformLongPressDelayed.cancel();
 
             if (mSendTouchExplorationEndDelayed.isPending()) {
                 mSendTouchExplorationEndDelayed.forceSendAndRemove();
@@ -1178,8 +1165,8 @@
                 mSendTouchInteractionEndDelayed.forceSendAndRemove();
             }
 
-            final int pointerId = event.getPointerId(event.getActionIndex());
-            final int pointerIndex = event.findPointerIndex(pointerId);
+            final int pointerIndex = event.getActionIndex();
+            final int pointerId = event.getPointerId(pointerIndex);
 
             Point clickLocation = mTempPoint;
             final int result = computeClickLocation(clickLocation);
@@ -1306,65 +1293,6 @@
     }
 
     /**
-     * Class for delayed sending of long press.
-     */
-    private final class PerformLongPressDelayed implements Runnable {
-        private MotionEvent mEvent;
-        private int mPolicyFlags;
-
-        public void post(MotionEvent prototype, int policyFlags) {
-            mEvent = MotionEvent.obtain(prototype);
-            mPolicyFlags = policyFlags;
-            mHandler.postDelayed(this, ViewConfiguration.getLongPressTimeout());
-        }
-
-        public void cancel() {
-            if (mEvent != null) {
-                mHandler.removeCallbacks(this);
-                clear();
-            }
-        }
-
-        private boolean isPending() {
-            return mHandler.hasCallbacks(this);
-        }
-
-        @Override
-        public void run() {
-            // Pointers should not be zero when running this command.
-            if (mReceivedPointerTracker.getLastReceivedEvent().getPointerCount() == 0) {
-                return;
-            }
-
-            final int pointerId = mEvent.getPointerId(mEvent.getActionIndex());
-            final int pointerIndex = mEvent.findPointerIndex(pointerId);
-
-            Point clickLocation = mTempPoint;
-            final int result = computeClickLocation(clickLocation);
-
-            if (result == CLICK_LOCATION_NONE) {
-                return;
-            }
-
-            mLongPressingPointerId = pointerId;
-            mLongPressingPointerDeltaX = (int) mEvent.getX(pointerIndex) - clickLocation.x;
-            mLongPressingPointerDeltaY = (int) mEvent.getY(pointerIndex) - clickLocation.y;
-
-            sendHoverExitAndTouchExplorationGestureEndIfNeeded(mPolicyFlags);
-
-            mCurrentState = STATE_DELEGATING;
-            sendDownForAllNotInjectedPointers(mEvent, mPolicyFlags);
-            clear();
-        }
-
-        private void clear() {
-            mEvent.recycle();
-            mEvent = null;
-            mPolicyFlags = 0;
-        }
-    }
-
-    /**
      * Class for delayed sending of hover enter and move events.
      */
     class SendHoverEnterAndMoveDelayed implements Runnable {
diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java
index f245985..2aa0390 100644
--- a/services/core/java/com/android/server/GestureLauncherService.java
+++ b/services/core/java/com/android/server/GestureLauncherService.java
@@ -55,7 +55,8 @@
      * Time in milliseconds in which the power button must be pressed twice so it will be considered
      * as a camera launch.
      */
-    private static final long CAMERA_POWER_DOUBLE_TAP_TIME_MS = 300;
+    private static final long CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS = 300;
+    private static final long CAMERA_POWER_DOUBLE_TAP_MIN_TIME_MS = 120;
 
     /** The listener that receives the gesture event. */
     private final GestureEventListener mGestureListener = new GestureEventListener();
@@ -256,14 +257,16 @@
         synchronized (this) {
             doubleTapInterval = event.getEventTime() - mLastPowerDown;
             if (mCameraDoubleTapPowerEnabled
-                    && doubleTapInterval < CAMERA_POWER_DOUBLE_TAP_TIME_MS) {
+                    && doubleTapInterval < CAMERA_POWER_DOUBLE_TAP_MAX_TIME_MS
+                    && doubleTapInterval > CAMERA_POWER_DOUBLE_TAP_MIN_TIME_MS) {
                 launched = true;
                 intercept = interactive;
             }
             mLastPowerDown = event.getEventTime();
         }
         if (launched) {
-            Slog.i(TAG, "Power button double tap gesture detected, launching camera.");
+            Slog.i(TAG, "Power button double tap gesture detected, launching camera. Interval="
+                    + doubleTapInterval + "ms");
             launched = handleCameraLaunchGesture(false /* useWakelock */,
                     StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP);
             if (launched) {
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 9dad7a1..ab1d775 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -37,6 +37,7 @@
 import org.xmlpull.v1.XmlSerializer;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.ActivityManagerNative;
 import android.app.AlertDialog;
 import android.app.AppGlobals;
@@ -280,8 +281,19 @@
     boolean mSystemReady;
 
     /**
-     * Id of the currently selected input method.
+     * Id obtained with {@link InputMethodInfo#getId()} for the currently selected input method.
+     * method.  This is to be synchronized with the secure settings keyed with
+     * {@link Settings.Secure#DEFAULT_INPUT_METHOD}.
+     *
+     * <p>This can be transiently {@code null} when the system is re-initializing input method
+     * settings, e.g., the system locale is just changed.</p>
+     *
+     * <p>Note that {@link #mCurId} is used to track which IME is being connected to
+     * {@link InputMethodManagerService}.</p>
+     *
+     * @see #mCurId
      */
+    @Nullable
     String mCurMethodId;
 
     /**
@@ -311,9 +323,14 @@
     EditorInfo mCurAttribute;
 
     /**
-     * The input method ID of the input method service that we are currently
+     * Id obtained with {@link InputMethodInfo#getId()} for the input method that we are currently
      * connected to or in the process of connecting to.
+     *
+     * <p>This can be {@code null} when no input method is connected.</p>
+     *
+     * @see #mCurMethodId
      */
+    @Nullable
     String mCurId;
 
     /**
@@ -918,7 +935,6 @@
                 || (newLocale != null && !newLocale.equals(mLastSystemLocale))) {
             if (!updateOnlyWhenLocaleChanged) {
                 hideCurrentInputLocked(0, null);
-                mCurMethodId = null;
                 unbindCurrentMethodLocked(true, false);
             }
             if (DEBUG) {
@@ -1474,7 +1490,11 @@
         channel.dispose();
     }
 
-    void unbindCurrentMethodLocked(boolean reportToClient, boolean savePosition) {
+    void unbindCurrentMethodLocked(boolean resetCurrentMethodAndClient, boolean savePosition) {
+        if (resetCurrentMethodAndClient) {
+            mCurMethodId = null;
+        }
+
         if (mVisibleBound) {
             mContext.unbindService(mVisibleConnection);
             mVisibleBound = false;
@@ -1501,9 +1521,8 @@
         mCurId = null;
         clearCurMethodLocked();
 
-        if (reportToClient && mCurClient != null) {
-            executeOrSendMessage(mCurClient.client, mCaller.obtainMessageIO(
-                    MSG_UNBIND_METHOD, mCurSeq, mCurClient.client));
+        if (resetCurrentMethodAndClient) {
+            unbindCurrentClientLocked();
         }
     }
 
@@ -1857,13 +1876,11 @@
                 setInputMethodLocked(id, mSettings.getSelectedInputMethodSubtypeId(id));
             } catch (IllegalArgumentException e) {
                 Slog.w(TAG, "Unknown input method from prefs: " + id, e);
-                mCurMethodId = null;
                 unbindCurrentMethodLocked(true, false);
             }
             mShortcutInputMethodsAndSubtypes.clear();
         } else {
             // There is no longer an input method set, so stop any current one.
-            mCurMethodId = null;
             unbindCurrentMethodLocked(true, false);
         }
         // Here is not the perfect place to reset the switching controller. Ideally
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index c3d32c2..4d32599 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -29,6 +29,7 @@
 
 import android.Manifest;
 import android.annotation.Nullable;
+import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.AppOpsManager;
 import android.app.IActivityManager;
@@ -90,7 +91,6 @@
 import libcore.util.EmptyArray;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IMediaContainerService;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.os.Zygote;
@@ -290,7 +290,7 @@
     private ArrayMap<String, DiskInfo> mDisks = new ArrayMap<>();
     /** Map from volume ID to disk */
     @GuardedBy("mLock")
-    private ArrayMap<String, VolumeInfo> mVolumes = new ArrayMap<>();
+    private final ArrayMap<String, VolumeInfo> mVolumes = new ArrayMap<>();
 
     /** Map from UUID to record */
     @GuardedBy("mLock")
@@ -462,11 +462,7 @@
         public ObbState(String rawPath, String canonicalPath, int callingUid,
                 IObbActionListener token, int nonce) {
             this.rawPath = rawPath;
-            this.canonicalPath = canonicalPath.toString();
-
-            final int userId = UserHandle.getUserId(callingUid);
-            this.ownerPath = buildObbPath(canonicalPath, userId, false);
-            this.voldPath = buildObbPath(canonicalPath, userId, true);
+            this.canonicalPath = canonicalPath;
 
             this.ownerGid = UserHandle.getSharedAppGid(callingUid);
             this.token = token;
@@ -475,8 +471,6 @@
 
         final String rawPath;
         final String canonicalPath;
-        final String ownerPath;
-        final String voldPath;
 
         final int ownerGid;
 
@@ -509,8 +503,6 @@
             StringBuilder sb = new StringBuilder("ObbState{");
             sb.append("rawPath=").append(rawPath);
             sb.append(",canonicalPath=").append(canonicalPath);
-            sb.append(",ownerPath=").append(ownerPath);
-            sb.append(",voldPath=").append(voldPath);
             sb.append(",ownerGid=").append(ownerGid);
             sb.append(",token=").append(token);
             sb.append(",binder=").append(getBinder());
@@ -569,6 +561,7 @@
     private static final int H_VOLUME_MOUNT = 5;
     private static final int H_VOLUME_BROADCAST = 6;
     private static final int H_INTERNAL_BROADCAST = 7;
+    private static final int H_VOLUME_UNMOUNT = 8;
 
     class MountServiceHandler extends Handler {
         public MountServiceHandler(Looper looper) {
@@ -649,6 +642,11 @@
                     }
                     break;
                 }
+                case H_VOLUME_UNMOUNT: {
+                    final VolumeInfo vol = (VolumeInfo) msg.obj;
+                    unmount(vol.getId());
+                    break;
+                }
                 case H_VOLUME_BROADCAST: {
                     final StorageVolume userVol = (StorageVolume) msg.obj;
                     final String envState = userVol.getState();
@@ -683,6 +681,7 @@
         public void onReceive(Context context, Intent intent) {
             final String action = intent.getAction();
             final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+            Preconditions.checkArgument(userId >= 0);
 
             try {
                 if (Intent.ACTION_USER_ADDED.equals(action)) {
@@ -690,6 +689,16 @@
                     final int userSerialNumber = um.getUserSerialNumber(userId);
                     mConnector.execute("volume", "user_added", userId, userSerialNumber);
                 } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
+                    synchronized (mVolumes) {
+                        final int size = mVolumes.size();
+                        for (int i = 0; i < size; i++) {
+                            final VolumeInfo vol = mVolumes.valueAt(i);
+                            if (vol.mountUserId == userId) {
+                                vol.mountUserId = UserHandle.USER_NULL;
+                                mHandler.obtainMessage(H_VOLUME_UNMOUNT, vol).sendToTarget();
+                            }
+                        }
+                    }
                     mConnector.execute("volume", "user_removed", userId);
                 }
             } catch (NativeDaemonConnectorException e) {
@@ -757,17 +766,26 @@
      * paths never changing, so we outright kill them to pick up new state.
      */
     @Deprecated
-    private void killMediaProvider() {
+    private void killMediaProvider(List<UserInfo> users) {
+        if (users == null) return;
+
         final long token = Binder.clearCallingIdentity();
         try {
-            final ProviderInfo provider = mPms.resolveContentProvider(MediaStore.AUTHORITY, 0,
-                    UserHandle.USER_OWNER);
-            if (provider != null) {
-                final IActivityManager am = ActivityManagerNative.getDefault();
-                try {
-                    am.killApplicationWithAppId(provider.applicationInfo.packageName,
-                            UserHandle.getAppId(provider.applicationInfo.uid), "vold reset");
-                } catch (RemoteException e) {
+            for (UserInfo user : users) {
+                // System user does not have media provider, so skip.
+                if (user.isSystemOnly()) continue;
+
+                final ProviderInfo provider =
+                        mPms.resolveContentProvider(MediaStore.AUTHORITY, 0, user.id);
+                if (provider != null) {
+                    final IActivityManager am = ActivityManagerNative.getDefault();
+                    try {
+                        am.killApplicationWithAppId(provider.applicationInfo.packageName,
+                                UserHandle.getAppId(provider.applicationInfo.uid), "vold reset");
+                        // We only need to run this once. It will kill all users' media processes.
+                        break;
+                    } catch (RemoteException e) {
+                    }
                 }
             }
         } finally {
@@ -788,7 +806,9 @@
         Slog.d(TAG, "Thinking about reset, mSystemReady=" + mSystemReady
                 + ", mDaemonConnected=" + mDaemonConnected);
         if (mSystemReady && mDaemonConnected) {
-            killMediaProvider();
+            final UserManager um = UserManager.get(mContext);
+            final List<UserInfo> users = um.getUsers();
+            killMediaProvider(users);
 
             mDisks.clear();
             mVolumes.clear();
@@ -799,8 +819,6 @@
                 mConnector.execute("volume", "reset");
 
                 // Tell vold about all existing and started users
-                final UserManager um = mContext.getSystemService(UserManager.class);
-                final List<UserInfo> users = um.getUsers();
                 for (UserInfo user : users) {
                     mConnector.execute("volume", "user_added", user.id, user.serialNumber);
                 }
@@ -1192,7 +1210,7 @@
                 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE;
             }
 
-            vol.mountUserId = UserHandle.USER_OWNER;
+            vol.mountUserId = ActivityManager.getCurrentUser();
             mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget();
 
         } else if (vol.type == VolumeInfo.TYPE_PRIVATE) {
@@ -2285,7 +2303,7 @@
 
         final NativeDaemonEvent event;
         try {
-            event = mConnector.execute("obb", "path", state.voldPath);
+            event = mConnector.execute("obb", "path", state.canonicalPath);
             event.checkCode(VoldResponseCode.AsecPathResult);
             return event.getMessage();
         } catch (NativeDaemonConnectorException e) {
@@ -3038,14 +3056,14 @@
         protected ObbInfo getObbInfo() throws IOException {
             ObbInfo obbInfo;
             try {
-                obbInfo = mContainerService.getObbInfo(mObbState.ownerPath);
+                obbInfo = mContainerService.getObbInfo(mObbState.canonicalPath);
             } catch (RemoteException e) {
                 Slog.d(TAG, "Couldn't call DefaultContainerService to fetch OBB info for "
-                        + mObbState.ownerPath);
+                        + mObbState.canonicalPath);
                 obbInfo = null;
             }
             if (obbInfo == null) {
-                throw new IOException("Couldn't read OBB file: " + mObbState.ownerPath);
+                throw new IOException("Couldn't read OBB file: " + mObbState.canonicalPath);
             }
             return obbInfo;
         }
@@ -3122,7 +3140,7 @@
 
             int rc = StorageResultCode.OperationSucceeded;
             try {
-                mConnector.execute("obb", "mount", mObbState.voldPath, new SensitiveArg(hashedKey),
+                mConnector.execute("obb", "mount", mObbState.canonicalPath, new SensitiveArg(hashedKey),
                         mObbState.ownerGid);
             } catch (NativeDaemonConnectorException e) {
                 int code = e.getCode();
@@ -3133,7 +3151,7 @@
 
             if (rc == StorageResultCode.OperationSucceeded) {
                 if (DEBUG_OBB)
-                    Slog.d(TAG, "Successfully mounted OBB " + mObbState.voldPath);
+                    Slog.d(TAG, "Successfully mounted OBB " + mObbState.canonicalPath);
 
                 synchronized (mObbMounts) {
                     addObbStateLocked(mObbState);
@@ -3194,7 +3212,7 @@
 
             int rc = StorageResultCode.OperationSucceeded;
             try {
-                final Command cmd = new Command("obb", "unmount", mObbState.voldPath);
+                final Command cmd = new Command("obb", "unmount", mObbState.canonicalPath);
                 if (mForceUnmount) {
                     cmd.appendArg("force");
                 }
@@ -3240,49 +3258,6 @@
         }
     }
 
-    @VisibleForTesting
-    public static String buildObbPath(final String canonicalPath, int userId, boolean forVold) {
-        // TODO: allow caller to provide Environment for full testing
-        // TODO: extend to support OBB mounts on secondary external storage
-
-        // Only adjust paths when storage is emulated
-        if (!Environment.isExternalStorageEmulated()) {
-            return canonicalPath;
-        }
-
-        String path = canonicalPath.toString();
-
-        // First trim off any external storage prefix
-        final UserEnvironment userEnv = new UserEnvironment(userId);
-
-        // /storage/emulated/0
-        final String externalPath = userEnv.getExternalStorageDirectory().getAbsolutePath();
-        // /storage/emulated_legacy
-        final String legacyExternalPath = Environment.getLegacyExternalStorageDirectory()
-                .getAbsolutePath();
-
-        if (path.startsWith(externalPath)) {
-            path = path.substring(externalPath.length() + 1);
-        } else if (path.startsWith(legacyExternalPath)) {
-            path = path.substring(legacyExternalPath.length() + 1);
-        } else {
-            return canonicalPath;
-        }
-
-        // Handle special OBB paths on emulated storage
-        final String obbPath = "Android/obb";
-        if (path.startsWith(obbPath)) {
-            path = path.substring(obbPath.length() + 1);
-
-            final UserEnvironment ownerEnv = new UserEnvironment(UserHandle.USER_OWNER);
-            return new File(ownerEnv.buildExternalStorageAndroidObbDirs()[0], path)
-                    .getAbsolutePath();
-        }
-
-        // Handle normal external storage paths
-        return new File(userEnv.getExternalStorageDirectory(), path).getAbsolutePath();
-    }
-
     private static class Callbacks extends Handler {
         private static final int MSG_STORAGE_STATE_CHANGED = 1;
         private static final int MSG_VOLUME_STATE_CHANGED = 2;
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 24b90d8..d4e798f 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -477,8 +477,8 @@
         }
     }
 
-    boolean isNotResolverActivity() {
-        return !ResolverActivity.class.getName().equals(realActivity.getClassName());
+    boolean isResolverActivity() {
+        return ResolverActivity.class.getName().equals(realActivity.getClassName());
     }
 
     ActivityRecord(ActivityManagerService _service, ProcessRecord _caller,
@@ -605,7 +605,7 @@
                     _intent.getData() == null &&
                     _intent.getType() == null &&
                     (intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
-                    isNotResolverActivity()) {
+                    !isResolverActivity()) {
                 // This sure looks like a home activity!
                 mActivityType = HOME_ACTIVITY_TYPE;
             } else if (realActivity.getClassName().contains(RECENTS_PACKAGE_NAME)) {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index a796ea7..f549af8 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1153,7 +1153,7 @@
         next.results = null;
         next.newIntents = null;
 
-        if (next.isHomeActivity() && next.isNotResolverActivity()) {
+        if (next.isHomeActivity()) {
             ProcessRecord app = next.task.mActivities.get(0).app;
             if (app != null && app != mService.mHomeProcess) {
                 mService.mHomeProcess = app;
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 98b6ee6..ac7b9b1 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1262,7 +1262,7 @@
                         r.userId, System.identityHashCode(r),
                         task.taskId, r.shortComponentName);
             }
-            if (r.isHomeActivity() && r.isNotResolverActivity()) {
+            if (r.isHomeActivity()) {
                 // Home process is the root process of the task.
                 mService.mHomeProcess = task.mActivities.get(0).app;
             }
@@ -2024,6 +2024,14 @@
             reuseTask = inTask;
         } else {
             inTask = null;
+            // Launch ResolverActivity in the source task, so that it stays in the task
+            // bounds when in freeform workspace.
+            // Also put noDisplay activities in the source task. These by itself can
+            // be placed in any task/stack, however it could launch other activities
+            // like ResolverActivity, and we want those to stay in the original task.
+            if (r.isResolverActivity() || r.noDisplay) {
+                addingToTask = true;
+            }
         }
 
         if (inTask == null) {
@@ -3091,7 +3099,7 @@
         Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeTask_" + task.taskId);
 
         final Configuration overrideConfig =  task.updateOverrideConfiguration(bounds);
-        // This variable holds information whether the configuration didn't change in a signficant
+        // This variable holds information whether the configuration didn't change in a significant
         // way and the activity was kept the way it was. If it's false, it means the activity had
         // to be relaunched due to configuration change.
         boolean kept = true;
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index e49a7e4..c4b57f1 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -501,7 +501,6 @@
     private volatile IRingtonePlayer mRingtonePlayer;
 
     private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
-    private int mDeviceRotation = Surface.ROTATION_0;
 
     // Request to override default use of A2DP for media.
     private boolean mBluetoothA2dpEnabled;
@@ -545,8 +544,6 @@
     // If absolute volume is supported in AVRCP device
     private boolean mAvrcpAbsVolSupported = false;
 
-    private AudioOrientationEventListener mOrientationListener;
-
     private static Long mLastDeviceConnectMsgTime = new Long(0);
 
     private AudioManagerInternal.RingerModeDelegate mRingerModeDelegate;
@@ -669,15 +666,7 @@
         }
         mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false);
         if (mMonitorRotation) {
-            mDeviceRotation = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE))
-                    .getDefaultDisplay().getRotation();
-            Log.v(TAG, "monitoring device rotation, initial=" + mDeviceRotation);
-
-            mOrientationListener = new AudioOrientationEventListener(mContext);
-            mOrientationListener.enable();
-
-            // initialize rotation in AudioSystem
-            setRotationForAudioSystem();
+            RotationHelper.init(mContext, mAudioHandler);
         }
 
         context.registerReceiverAsUser(mReceiver, UserHandle.ALL, intentFilter, null, null);
@@ -805,7 +794,7 @@
             setOrientationForAudioSystem();
         }
         if (mMonitorRotation) {
-            setRotationForAudioSystem();
+            RotationHelper.updateOrientation();
         }
 
         synchronized (mBluetoothA2dpEnabledLock) {
@@ -1058,25 +1047,6 @@
         return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
     }
 
-    private class AudioOrientationEventListener
-            extends OrientationEventListener {
-        public AudioOrientationEventListener(Context context) {
-            super(context);
-        }
-
-        @Override
-        public void onOrientationChanged(int orientation) {
-            //Even though we're responding to phone orientation events,
-            //use display rotation so audio stays in sync with video/dialogs
-            int newRotation = ((WindowManager) mContext.getSystemService(
-                    Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
-            if (newRotation != mDeviceRotation) {
-                mDeviceRotation = newRotation;
-                setRotationForAudioSystem();
-            }
-        }
-    }
-
     ///////////////////////////////////////////////////////////////////////////
     // IPC methods
     ///////////////////////////////////////////////////////////////////////////
@@ -5066,14 +5036,13 @@
                 }
             } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
                 if (mMonitorRotation) {
-                    mOrientationListener.onOrientationChanged(0); //argument is ignored anyway
-                    mOrientationListener.enable();
+                    RotationHelper.enable();
                 }
                 AudioSystem.setParameters("screen_state=on");
             } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
                 if (mMonitorRotation) {
                     //reduce wakeups (save current) by only listening when display is on
-                    mOrientationListener.disable();
+                    RotationHelper.disable();
                 }
                 AudioSystem.setParameters("screen_state=off");
             } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
@@ -5322,6 +5291,7 @@
         }
     }
 
+    //TODO move to an external "orientation helper" class
     private void setOrientationForAudioSystem() {
         switch (mDeviceOrientation) {
             case Configuration.ORIENTATION_LANDSCAPE:
@@ -5345,26 +5315,6 @@
         }
     }
 
-    private void setRotationForAudioSystem() {
-        switch (mDeviceRotation) {
-            case Surface.ROTATION_0:
-                AudioSystem.setParameters("rotation=0");
-                break;
-            case Surface.ROTATION_90:
-                AudioSystem.setParameters("rotation=90");
-                break;
-            case Surface.ROTATION_180:
-                AudioSystem.setParameters("rotation=180");
-                break;
-            case Surface.ROTATION_270:
-                AudioSystem.setParameters("rotation=270");
-                break;
-            default:
-                Log.e(TAG, "Unknown device rotation");
-        }
-    }
-
-
     // Handles request to override default use of A2DP for media.
     // Must be called synchronized on mConnectedDevices
     public void setBluetoothA2dpOnInt(boolean on) {
diff --git a/services/core/java/com/android/server/audio/RotationHelper.java b/services/core/java/com/android/server/audio/RotationHelper.java
new file mode 100644
index 0000000..f03e6c7
--- /dev/null
+++ b/services/core/java/com/android/server/audio/RotationHelper.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.audio;
+
+import android.content.Context;
+import android.media.AudioSystem;
+import android.os.Handler;
+import android.util.Log;
+import android.view.OrientationEventListener;
+import android.view.Surface;
+import android.view.WindowManager;
+
+import com.android.server.policy.WindowOrientationListener;
+
+/**
+ * Class to handle device rotation events for AudioService, and forward device rotation
+ * to the audio HALs through AudioSystem.
+ *
+ * The role of this class is to monitor device orientation changes, and upon rotation,
+ * verify the UI orientation. In case of a change, send the new orientation, in increments
+ * of 90deg, through AudioSystem.
+ *
+ * Note that even though we're responding to device orientation events, we always
+ * query the display rotation so audio stays in sync with video/dialogs. This is
+ * done with .getDefaultDisplay().getRotation() from WINDOW_SERVICE.
+ */
+class RotationHelper {
+
+    private static final String TAG = "AudioService.RotationHelper";
+
+    private static AudioOrientationListener sOrientationListener;
+    private static AudioWindowOrientationListener sWindowOrientationListener;
+
+    private static final Object sRotationLock = new Object();
+    private static int sDeviceRotation = Surface.ROTATION_0; // R/W synchronized on sRotationLock
+
+    private static Context sContext;
+
+    /**
+     * post conditions:
+     * - (sWindowOrientationListener != null) xor (sOrientationListener != null)
+     * - sWindowOrientationListener xor sOrientationListener is enabled
+     * - sContext != null
+     */
+    static void init(Context context, Handler handler) {
+        if (context == null) {
+            throw new IllegalArgumentException("Invalid null context");
+        }
+        sContext = context;
+        sWindowOrientationListener = new AudioWindowOrientationListener(context, handler);
+        sWindowOrientationListener.enable();
+        if (!sWindowOrientationListener.canDetectOrientation()) {
+            // cannot use com.android.server.policy.WindowOrientationListener, revert to public
+            // orientation API
+            Log.i(TAG, "Not using WindowOrientationListener, reverting to OrientationListener");
+            sWindowOrientationListener.disable();
+            sWindowOrientationListener = null;
+            sOrientationListener = new AudioOrientationListener(context);
+            sOrientationListener.enable();
+        }
+    }
+
+    static void enable() {
+        if (sWindowOrientationListener != null) {
+            sWindowOrientationListener.enable();
+        } else {
+            sOrientationListener.enable();
+        }
+        updateOrientation();
+    }
+
+    static void disable() {
+        if (sWindowOrientationListener != null) {
+            sWindowOrientationListener.disable();
+        } else {
+            sOrientationListener.disable();
+        }
+    }
+
+    /**
+     * Query current display rotation and publish the change if any.
+     */
+    static void updateOrientation() {
+        // Even though we're responding to device orientation events,
+        // use display rotation so audio stays in sync with video/dialogs
+        int newRotation = ((WindowManager) sContext.getSystemService(
+                Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
+        synchronized(sRotationLock) {
+            if (newRotation != sDeviceRotation) {
+                sDeviceRotation = newRotation;
+                publishRotation(sDeviceRotation);
+            }
+        }
+    }
+
+    private static void publishRotation(int rotation) {
+        Log.v(TAG, "publishing device rotation =" + rotation + " (x90deg)");
+        switch (rotation) {
+            case Surface.ROTATION_0:
+                AudioSystem.setParameters("rotation=0");
+                break;
+            case Surface.ROTATION_90:
+                AudioSystem.setParameters("rotation=90");
+                break;
+            case Surface.ROTATION_180:
+                AudioSystem.setParameters("rotation=180");
+                break;
+            case Surface.ROTATION_270:
+                AudioSystem.setParameters("rotation=270");
+                break;
+            default:
+                Log.e(TAG, "Unknown device rotation");
+        }
+    }
+
+    /**
+     * Uses android.view.OrientationEventListener
+     */
+    final static class AudioOrientationListener extends OrientationEventListener {
+        AudioOrientationListener(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void onOrientationChanged(int orientation) {
+            updateOrientation();
+        }
+    }
+
+    /**
+     * Uses com.android.server.policy.WindowOrientationListener
+     */
+    final static class AudioWindowOrientationListener extends WindowOrientationListener {
+        private static RotationCheckThread sRotationCheckThread;
+
+        AudioWindowOrientationListener(Context context, Handler handler) {
+            super(context, handler);
+        }
+
+        public void onProposedRotationChanged(int rotation) {
+            updateOrientation();
+            if (sRotationCheckThread != null) {
+                sRotationCheckThread.endCheck();
+            }
+            sRotationCheckThread = new RotationCheckThread();
+            sRotationCheckThread.beginCheck();
+        }
+    }
+
+    /**
+     * When com.android.server.policy.WindowOrientationListener report an orientation change,
+     * the UI may not have rotated yet. This thread polls with gradually increasing delays
+     * the new orientation.
+     */
+    final static class RotationCheckThread extends Thread {
+        // how long to wait between each rotation check
+        private final int[] WAIT_TIMES_MS = { 10, 20, 50, 100, 100, 200, 200, 500 };
+        private int mWaitCounter;
+        private final Object mCounterLock = new Object();
+
+        RotationCheckThread() {
+            super("RotationCheck");
+        }
+
+        void beginCheck() {
+            synchronized(mCounterLock) {
+                mWaitCounter = 0;
+            }
+            try {
+                start();
+            } catch (IllegalStateException e) { }
+        }
+
+        void endCheck() {
+            synchronized(mCounterLock) {
+                mWaitCounter = WAIT_TIMES_MS.length;
+            }
+        }
+
+        public void run() {
+            int newRotation;
+            while (mWaitCounter < WAIT_TIMES_MS.length) {
+                updateOrientation();
+                int waitTimeMs;
+                synchronized(mCounterLock) {
+                    waitTimeMs = WAIT_TIMES_MS[mWaitCounter];
+                    mWaitCounter++;
+                }
+                try {
+                    sleep(waitTimeMs);
+                } catch (InterruptedException e) { }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index a441cb2..6e32e5c 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -946,7 +946,7 @@
         }
 
         final int uid = mPm.getPackageUid(PackageManagerService.DEFAULT_CONTAINER_PACKAGE,
-                UserHandle.USER_OWNER);
+                UserHandle.USER_SYSTEM);
         final int gid = UserHandle.getSharedAppGid(uid);
         if (!PackageHelper.fixSdPermissions(cid, gid, null)) {
             throw new PackageManagerException(INSTALL_FAILED_CONTAINER_ERROR,
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 2009ccf..99562f3 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1108,7 +1108,7 @@
             Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
             Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
             if (mContext.bindServiceAsUser(service, mDefContainerConn,
-                    Context.BIND_AUTO_CREATE, UserHandle.OWNER)) {
+                    Context.BIND_AUTO_CREATE, UserHandle.SYSTEM)) {
                 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
                 mBound = true;
                 return true;
@@ -1715,7 +1715,7 @@
                 for (PackageSetting ps : packages) {
                     Slog.d(TAG, "Destroying " + ps.name + " because volume was forgotten");
                     deletePackage(ps.name, new LegacyPackageDeleteObserver(null).getBinder(),
-                            UserHandle.USER_OWNER, PackageManager.DELETE_ALL_USERS);
+                            UserHandle.USER_SYSTEM, PackageManager.DELETE_ALL_USERS);
                 }
 
                 mSettings.onVolumeForgotten(fsUuid);
@@ -1726,7 +1726,7 @@
 
     private void grantRequestedRuntimePermissions(PackageParser.Package pkg, int userId,
             String[] grantedPermissions) {
-        if (userId >= UserHandle.USER_OWNER) {
+        if (userId >= UserHandle.USER_SYSTEM) {
             grantRequestedRuntimePermissionsForUser(pkg, userId, grantedPermissions);
         } else if (userId == UserHandle.USER_ALL) {
             final int[] userIds;
@@ -2276,7 +2276,7 @@
                         mSettings.enableSystemPackageLPw(packageName);
 
                         try {
-                            scanPackageTracedLI(scanFile, reparseFlags, scanFlags, 0, null);
+                            scanPackageTracedLI(scanFile, reparseFlags, scanFlags, 0, UserHandle.SYSTEM);
                         } catch (PackageManagerException e) {
                             Slog.e(TAG, "Failed to parse original system package: "
                                     + e.getMessage());
@@ -2401,8 +2401,9 @@
 
     private String getRequiredVerifierLPr() {
         final Intent verification = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
+        // We only care about verifier that's installed under system user.
         final List<ResolveInfo> receivers = queryIntentReceivers(verification, PACKAGE_MIME_TYPE,
-                PackageManager.GET_DISABLED_COMPONENTS, 0 /* TODO: Which userId? */);
+                PackageManager.GET_DISABLED_COMPONENTS, UserHandle.USER_SYSTEM);
 
         String requiredVerifier = null;
 
@@ -2417,7 +2418,7 @@
             final String packageName = info.activityInfo.packageName;
 
             if (checkPermission(android.Manifest.permission.PACKAGE_VERIFICATION_AGENT,
-                    packageName, UserHandle.USER_OWNER) != PackageManager.PERMISSION_GRANTED) {
+                    packageName, UserHandle.USER_SYSTEM) != PackageManager.PERMISSION_GRANTED) {
                 continue;
             }
 
@@ -2437,7 +2438,7 @@
         installerIntent.setDataAndType(Uri.fromFile(new File("foo.apk")), PACKAGE_MIME_TYPE);
 
         final List<ResolveInfo> installers = queryIntentActivities(installerIntent,
-                PACKAGE_MIME_TYPE, 0, 0);
+                PACKAGE_MIME_TYPE, 0, UserHandle.USER_SYSTEM);
 
         String requiredInstaller = null;
 
@@ -2467,7 +2468,7 @@
     private ComponentName getIntentFilterVerifierComponentNameLPr() {
         final Intent verification = new Intent(Intent.ACTION_INTENT_FILTER_NEEDS_VERIFICATION);
         final List<ResolveInfo> receivers = queryIntentReceivers(verification, PACKAGE_MIME_TYPE,
-                PackageManager.GET_DISABLED_COMPONENTS, 0 /* userId */);
+                PackageManager.GET_DISABLED_COMPONENTS, UserHandle.USER_SYSTEM);
 
         ComponentName verifierComponentName = null;
 
@@ -2488,7 +2489,7 @@
             }
 
             if (checkPermission(android.Manifest.permission.INTENT_FILTER_VERIFICATION_AGENT,
-                    packageName, UserHandle.USER_OWNER) != PackageManager.PERMISSION_GRANTED) {
+                    packageName, UserHandle.USER_SYSTEM) != PackageManager.PERMISSION_GRANTED) {
                 continue;
             }
 
@@ -2784,8 +2785,7 @@
             if((ps == null) || (ps.pkg == null) || (ps.pkg.applicationInfo == null)) {
                 return -1;
             }
-            p = ps.pkg;
-            return p != null ? UserHandle.getUid(userId, p.applicationInfo.uid) : -1;
+            return UserHandle.getUid(userId, ps.pkg.applicationInfo.uid);
         }
     }
 
@@ -5690,7 +5690,7 @@
             }
             try {
                 scanPackageTracedLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK,
-                        scanFlags, currentTime, null);
+                        scanFlags, currentTime, UserHandle.SYSTEM);
             } catch (PackageManagerException e) {
                 Slog.w(TAG, "Failed to parse " + file + ": " + e.getMessage());
 
@@ -5796,6 +5796,8 @@
      */
     private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
             long currentTime, UserHandle user) throws PackageManagerException {
+        Preconditions.checkNotNull(user);
+
         if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
         parseFlags |= mDefParseFlags;
         PackageParser pp = new PackageParser();
@@ -5837,7 +5839,7 @@
         }
         boolean updatedPkgBetter = false;
         // First check if this is a system package that may involve an update
-        if (updatedPkg != null && (parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
+        if (updatedPkg != null && (parseFlags & PackageParser.PARSE_IS_SYSTEM) != 0) {
             // If new package is not located in "/system/priv-app" (e.g. due to an OTA),
             // it needs to drop FLAG_PRIVILEGED.
             if (locationIsPrivileged(scanFile)) {
@@ -6932,7 +6934,7 @@
         } else {
             // This is a normal package, need to make its data directory.
             dataPath = Environment.getDataUserPackageDirectory(pkg.volumeUuid,
-                    UserHandle.USER_OWNER, pkg.packageName);
+                    UserHandle.USER_SYSTEM, pkg.packageName);
 
             boolean uidError = false;
             if (dataPath.exists()) {
@@ -7090,7 +7092,7 @@
             // if they already exist
             if (!TextUtils.isEmpty(pkg.volumeUuid)) {
                 for (int userId : userIds) {
-                    if (userId != 0) {
+                    if (userId != UserHandle.USER_SYSTEM) {
                         mInstaller.createUserData(pkg.volumeUuid, pkg.packageName,
                                 UserHandle.getUid(userId, pkg.applicationInfo.uid), userId,
                                 pkg.applicationInfo.seinfo);
@@ -7218,7 +7220,6 @@
                                 for (int j=0; j<sysPs.pkg.libraryNames.size(); j++) {
                                     if (name.equals(sysPs.pkg.libraryNames.get(j))) {
                                         allowed = true;
-                                        allowed = true;
                                         break;
                                     }
                                 }
@@ -9603,7 +9604,7 @@
         if (am != null) {
             try {
                 am.startService(null, intent, null, mContext.getOpPackageName(),
-                        UserHandle.USER_OWNER);
+                        UserHandle.USER_SYSTEM);
             } catch (RemoteException e) {
             }
         }
@@ -10322,7 +10323,8 @@
                                 + " to BM for possible restore");
                         Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "restore", token);
                         try {
-                            if (bm.isBackupServiceActive(UserHandle.USER_OWNER)) {
+                            // TODO: http://b/22388012
+                            if (bm.isBackupServiceActive(UserHandle.USER_SYSTEM)) {
                                 bm.restoreAtInstall(res.pkg.applicationInfo.packageName, token);
                             } else {
                                 doRestore = false;
@@ -10803,14 +10805,11 @@
             mArgs = args;
 
             if (ret == PackageManager.INSTALL_SUCCEEDED) {
-                 /*
-                 * ADB installs appear as UserHandle.USER_ALL, and can only be performed by
-                 * UserHandle.USER_OWNER, so use the package verifier for UserHandle.USER_OWNER.
-                 */
-                int userIdentifier = getUser().getIdentifier();
-                if (userIdentifier == UserHandle.USER_ALL
-                        && ((installFlags & PackageManager.INSTALL_FROM_ADB) != 0)) {
-                    userIdentifier = UserHandle.USER_OWNER;
+                // TODO: http://b/22976637
+                // Apps installed for "all" users use the device owner to verify the app
+                UserHandle verifierUser = getUser();
+                if (verifierUser == UserHandle.ALL) {
+                    verifierUser = UserHandle.SYSTEM;
                 }
 
                 /*
@@ -10818,9 +10817,9 @@
                  * do, then we'll defer to them to verify the packages.
                  */
                 final int requiredUid = mRequiredVerifierPackage == null ? -1
-                        : getPackageUid(mRequiredVerifierPackage, userIdentifier);
+                        : getPackageUid(mRequiredVerifierPackage, verifierUser.getIdentifier());
                 if (!origin.existing && requiredUid != -1
-                        && isVerificationEnabled(userIdentifier, installFlags)) {
+                        && isVerificationEnabled(verifierUser.getIdentifier(), installFlags)) {
                     final Intent verification = new Intent(
                             Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
                     verification.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
@@ -10830,7 +10829,7 @@
 
                     final List<ResolveInfo> receivers = queryIntentReceivers(verification,
                             PACKAGE_MIME_TYPE, PackageManager.GET_DISABLED_COMPONENTS,
-                            0 /* TODO: Which userId? */);
+                            verifierUser.getIdentifier());
 
                     if (DEBUG_VERIFY) {
                         Slog.d(TAG, "Found " + receivers.size() + " verifiers for intent "
@@ -10885,12 +10884,6 @@
                     final List<ComponentName> sufficientVerifiers = matchVerifiers(pkgLite,
                             receivers, verificationState);
 
-                    // Apps installed for "all" users use the device owner to verify the app
-                    UserHandle verifierUser = getUser();
-                    if (verifierUser == UserHandle.ALL) {
-                        verifierUser = UserHandle.OWNER;
-                    }
-
                     /*
                      * If any sufficient verifiers were listed in the package
                      * manifest, attempt to ask them.
@@ -12121,7 +12114,8 @@
                         (oldExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0);
                 int oldScanFlags = SCAN_UPDATE_SIGNATURE | SCAN_UPDATE_TIME;
                 try {
-                    scanPackageTracedLI(restoreFile, oldParseFlags, oldScanFlags, origUpdateTime, null);
+                    scanPackageTracedLI(restoreFile, oldParseFlags, oldScanFlags, origUpdateTime,
+                            UserHandle.SYSTEM);
                 } catch (PackageManagerException e) {
                     Slog.e(TAG, "Failed to restore package : " + pkgName + " after failed upgrade: "
                             + e.getMessage());
@@ -12616,7 +12610,7 @@
 
         final int verifierUid = getPackageUid(
                 mIntentFilterVerifierComponent.getPackageName(),
-                (userId == UserHandle.USER_ALL) ? UserHandle.USER_OWNER : userId);
+                (userId == UserHandle.USER_ALL) ? UserHandle.USER_SYSTEM : userId);
 
         mHandler.removeMessages(START_INTENT_FILTER_VERIFICATIONS);
         final Message msg = mHandler.obtainMessage(START_INTENT_FILTER_VERIFICATIONS);
@@ -12816,11 +12810,14 @@
         Preconditions.checkNotNull(packageName);
         Preconditions.checkNotNull(observer);
         final int uid = Binder.getCallingUid();
-        if (UserHandle.getUserId(uid) != userId) {
+        final boolean deleteAllUsers = (flags & PackageManager.DELETE_ALL_USERS) != 0;
+        final int[] users = deleteAllUsers ? sUserManager.getUserIds() : new int[]{ userId };
+        if (UserHandle.getUserId(uid) != userId || (deleteAllUsers && users.length > 1)) {
             mContext.enforceCallingPermission(
                     android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
                     "deletePackage for user " + userId);
         }
+
         if (isUserRestricted(userId, UserManager.DISALLOW_UNINSTALL_APPS)) {
             try {
                 observer.onPackageDeleted(packageName,
@@ -12830,25 +12827,15 @@
             return;
         }
 
-        boolean uninstallBlocked = false;
-        if ((flags & PackageManager.DELETE_ALL_USERS) != 0) {
-            int[] users = sUserManager.getUserIds();
-            for (int i = 0; i < users.length; ++i) {
-                if (getBlockUninstallForUser(packageName, users[i])) {
-                    uninstallBlocked = true;
-                    break;
+        for (int currentUserId : users) {
+            if (getBlockUninstallForUser(packageName, currentUserId)) {
+                try {
+                    observer.onPackageDeleted(packageName,
+                            PackageManager.DELETE_FAILED_OWNER_BLOCKED, null);
+                } catch (RemoteException re) {
                 }
+                return;
             }
-        } else {
-            uninstallBlocked = getBlockUninstallForUser(packageName, userId);
-        }
-        if (uninstallBlocked) {
-            try {
-                observer.onPackageDeleted(packageName, PackageManager.DELETE_FAILED_OWNER_BLOCKED,
-                        null);
-            } catch (RemoteException re) {
-            }
-            return;
         }
 
         if (DEBUG_REMOVE) {
@@ -12859,13 +12846,11 @@
             public void run() {
                 mHandler.removeCallbacks(this);
                 final int returnCode = deletePackageX(packageName, userId, flags);
-                if (observer != null) {
-                    try {
-                        observer.onPackageDeleted(packageName, returnCode, null);
-                    } catch (RemoteException e) {
-                        Log.i(TAG, "Observer no longer exists.");
-                    } //end catch
-                } //end if
+                try {
+                    observer.onPackageDeleted(packageName, returnCode, null);
+                } catch (RemoteException e) {
+                    Log.i(TAG, "Observer no longer exists.");
+                } //end catch
             } //end run
         });
     }
@@ -13063,7 +13048,7 @@
                             final int userIdToKill = mSettings.updateSharedUserPermsLPw(deletedPs,
                                     userId);
                             if (userIdToKill == UserHandle.USER_ALL
-                                    || userIdToKill >= UserHandle.USER_OWNER) {
+                                    || userIdToKill >= UserHandle.USER_SYSTEM) {
                                 // If gids changed for this user, kill all affected packages.
                                 mHandler.post(new Runnable() {
                                     @Override
@@ -13180,7 +13165,8 @@
 
         final PackageParser.Package newPkg;
         try {
-            newPkg = scanPackageTracedLI(disabledPs.codePath, parseFlags, SCAN_NO_PATHS, 0, null);
+            newPkg = scanPackageTracedLI(disabledPs.codePath, parseFlags, SCAN_NO_PATHS, 0,
+                    UserHandle.SYSTEM);
         } catch (PackageManagerException e) {
             Slog.w(TAG, "Failed to restore system package:" + newPs.name + ": " + e.getMessage());
             return false;
@@ -13431,7 +13417,7 @@
         }
         final ClearStorageConnection conn = new ClearStorageConnection();
         if (mContext.bindServiceAsUser(
-                containerIntent, conn, Context.BIND_AUTO_CREATE, UserHandle.OWNER)) {
+                containerIntent, conn, Context.BIND_AUTO_CREATE, UserHandle.SYSTEM)) {
             try {
                 for (int curUser : users) {
                     long timeout = SystemClock.uptimeMillis() + 5000;
@@ -15743,7 +15729,8 @@
                 synchronized (mInstallLock) {
                     PackageParser.Package pkg = null;
                     try {
-                        pkg = scanPackageTracedLI(new File(codePath), parseFlags, 0, 0, null);
+                        pkg = scanPackageTracedLI(new File(codePath), parseFlags, 0, 0,
+                                UserHandle.SYSTEM);
                     } catch (PackageManagerException e) {
                         Slog.w(TAG, "Failed to scan " + codePath + ": " + e.getMessage());
                     }
@@ -15903,7 +15890,8 @@
             synchronized (mInstallLock) {
                 final PackageParser.Package pkg;
                 try {
-                    pkg = scanPackageTracedLI(ps.codePath, parseFlags, SCAN_INITIAL, 0L, null);
+                    pkg = scanPackageTracedLI(ps.codePath, parseFlags, SCAN_INITIAL, 0,
+                            UserHandle.SYSTEM);
                     loaded.add(pkg.applicationInfo);
                 } catch (PackageManagerException e) {
                     Slog.w(TAG, "Failed to scan " + ps.codePath + ": " + e.getMessage());
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 6386a91..31fc24b 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -131,6 +131,8 @@
     private static final String XML_SUFFIX = ".xml";
 
     private static final int MIN_USER_ID = 10;
+    // We need to keep process uid within Integer.MAX_VALUE.
+    private static final int MAX_USER_ID = Integer.MAX_VALUE / UserHandle.PER_USER_RANGE;
 
     private static final int USER_VERSION = 6;
 
@@ -844,7 +846,7 @@
         int userVersion = mUserVersion;
         if (userVersion < 1) {
             // Assign a proper name for the owner, if not initialized correctly before
-            UserInfo user = mUsers.get(UserHandle.USER_OWNER);
+            UserInfo user = mUsers.get(UserHandle.USER_SYSTEM);
             if ("Primary".equals(user.name)) {
                 user.name = mContext.getResources().getString(com.android.internal.R.string.owner_name);
                 scheduleWriteUserLocked(user);
@@ -854,7 +856,7 @@
 
         if (userVersion < 2) {
             // Owner should be marked as initialized
-            UserInfo user = mUsers.get(UserHandle.USER_OWNER);
+            UserInfo user = mUsers.get(UserHandle.USER_SYSTEM);
             if ((user.flags & UserInfo.FLAG_INITIALIZED) == 0) {
                 user.flags |= UserInfo.FLAG_INITIALIZED;
                 scheduleWriteUserLocked(user);
@@ -1518,6 +1520,11 @@
         long ident = Binder.clearCallingIdentity();
         try {
             final UserInfo user;
+            int currentUser = ActivityManager.getCurrentUser();
+            if (currentUser == userHandle) {
+                Log.w(LOG_TAG, "Current user cannot be removed");
+                return false;
+            }
             synchronized (mPackagesLock) {
                 user = mUsers.get(userHandle);
                 if (userHandle == 0 || user == null || mRemovingUserIds.get(userHandle)) {
@@ -2005,14 +2012,14 @@
     private int getNextAvailableIdLocked() {
         synchronized (mPackagesLock) {
             int i = MIN_USER_ID;
-            while (i < Integer.MAX_VALUE) {
+            while (i < MAX_USER_ID) {
                 if (mUsers.indexOfKey(i) < 0 && !mRemovingUserIds.get(i)) {
-                    break;
+                    return i;
                 }
                 i++;
             }
-            return i;
         }
+        throw new IllegalStateException("No user id available!");
     }
 
     private String packageToRestrictionsFileName(String packageName) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index c265000..4f30a15 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -778,6 +778,8 @@
         private final Runnable mUpdateRotationRunnable = new Runnable() {
             @Override
             public void run() {
+                // send interaction hint to improve redraw performance
+                mPowerManagerInternal.powerHint(PowerManagerInternal.POWER_HINT_INTERACTION, 0);
                 updateRotation(false);
             }
         };
diff --git a/services/core/java/com/android/server/wm/DimBehindController.java b/services/core/java/com/android/server/wm/DimBehindController.java
new file mode 100644
index 0000000..c56af39
--- /dev/null
+++ b/services/core/java/com/android/server/wm/DimBehindController.java
@@ -0,0 +1,291 @@
+package com.android.server.wm;
+
+import static com.android.server.wm.WindowManagerService.DEBUG_DIM_LAYER;
+
+import android.graphics.Rect;
+import android.util.ArrayMap;
+import android.util.Slog;
+import android.util.TypedValue;
+
+import java.io.PrintWriter;
+
+/**
+ * Centralizes the control of dim layers used for
+ * {@link android.view.WindowManager.LayoutParams#FLAG_DIM_BEHIND}.
+ */
+class DimBehindController {
+    private static final String TAG = "DimBehindController";
+
+    /** Amount of time in milliseconds to animate the dim surface from one value to another,
+     * when no window animation is driving it. */
+    private static final int DEFAULT_DIM_DURATION = 200;
+
+    // Shared dim layer for fullscreen users. {@link DimBehindState#dimLayer} will point to this
+    // instead of creating a new object per fullscreen task on a display.
+    private DimLayer mSharedFullScreenDimLayer;
+
+    private ArrayMap<DimLayer.DimLayerUser, DimBehindState> mState = new ArrayMap<>();
+
+    private DisplayContent mDisplayContent;
+
+    private Rect mTmpBounds = new Rect();
+
+    DimBehindController(DisplayContent displayContent) {
+        mDisplayContent = displayContent;
+    }
+
+    /** Updates the dim layer bounds, recreating it if needed. */
+    void updateDimLayer(DimLayer.DimLayerUser dimLayerUser) {
+        DimBehindState state = getOrCreateDimBehindState(dimLayerUser);
+        final boolean previousFullscreen = state.dimLayer != null
+                && state.dimLayer == mSharedFullScreenDimLayer;
+        DimLayer newDimLayer;
+        final int displayId = mDisplayContent.getDisplayId();
+        if (dimLayerUser.isFullscreen()) {
+            if (previousFullscreen) {
+                // Nothing to do here...
+                return;
+            }
+            // Use shared fullscreen dim layer
+            newDimLayer = mSharedFullScreenDimLayer;
+            if (newDimLayer == null) {
+                if (state.dimLayer != null) {
+                    // Re-purpose the previous dim layer.
+                    newDimLayer = state.dimLayer;
+                } else {
+                    // Create new full screen dim layer.
+                    newDimLayer = new DimLayer(mDisplayContent.mService, dimLayerUser, displayId);
+                }
+                dimLayerUser.getBounds(mTmpBounds);
+                newDimLayer.setBounds(mTmpBounds);
+                mSharedFullScreenDimLayer = newDimLayer;
+            } else if (state.dimLayer != null) {
+                state.dimLayer. destroySurface();
+            }
+        } else {
+            newDimLayer = (state.dimLayer == null || previousFullscreen)
+                    ? new DimLayer(mDisplayContent.mService, dimLayerUser, displayId)
+                    : state.dimLayer;
+            dimLayerUser.getBounds(mTmpBounds);
+            newDimLayer.setBounds(mTmpBounds);
+        }
+        state.dimLayer = newDimLayer;
+    }
+
+    private DimBehindState getOrCreateDimBehindState(DimLayer.DimLayerUser dimLayerUser) {
+        if (DEBUG_DIM_LAYER) Slog.v(TAG, "getDimBehindState, dimLayerUser="
+                + dimLayerUser.toShortString());
+        DimBehindState state = mState.get(dimLayerUser);
+        if (state == null) {
+            state = new DimBehindState();
+            mState.put(dimLayerUser, state);
+        }
+        return state;
+    }
+
+    private void setContinueDimming(DimLayer.DimLayerUser dimLayerUser) {
+        DimBehindState state = mState.get(dimLayerUser);
+        if (state == null) {
+            if (DEBUG_DIM_LAYER) Slog.w(TAG, "setContinueDimming, no state for: "
+                    + dimLayerUser.toShortString());
+            return;
+        }
+        state.continueDimming = true;
+    }
+
+    boolean isDimming() {
+        for (int i = mState.size() - 1; i >= 0; i--) {
+            DimBehindState state = mState.valueAt(i);
+            if (state.dimLayer != null && state.dimLayer.isDimming()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    void resetDimming() {
+        for (int i = mState.size() - 1; i >= 0; i--) {
+            mState.valueAt(i).continueDimming = false;
+        }
+    }
+
+    private boolean getContinueDimming(DimLayer.DimLayerUser dimLayerUser) {
+        DimBehindState state = mState.get(dimLayerUser);
+        return state != null && state.continueDimming;
+    }
+
+    void startDimmingIfNeeded(DimLayer.DimLayerUser dimLayerUser,
+            WindowStateAnimator newWinAnimator) {
+        // Only set dim params on the highest dimmed layer.
+        // Don't turn on for an unshown surface, or for any layer but the highest dimmed layer.
+        DimBehindState state = getOrCreateDimBehindState(dimLayerUser);
+        if (DEBUG_DIM_LAYER) Slog.v(TAG, "startDimmingIfNeeded,"
+                + " dimLayerUser=" + dimLayerUser.toShortString()
+                + " newWinAnimator=" + newWinAnimator
+                + " state.animator=" + state.animator);
+        if (newWinAnimator.mSurfaceShown && (state.animator == null
+                || !state.animator.mSurfaceShown
+                || state.animator.mAnimLayer <= newWinAnimator.mAnimLayer)) {
+            state.animator = newWinAnimator;
+            if (state.animator.mWin.mAppToken == null && !dimLayerUser.isFullscreen()) {
+                // Dim should cover the entire screen for system windows.
+                mDisplayContent.getLogicalDisplayRect(mTmpBounds);
+                state.dimLayer.setBounds(mTmpBounds);
+            }
+        }
+    }
+
+    void stopDimmingIfNeeded() {
+        if (DEBUG_DIM_LAYER) Slog.v(TAG, "stopDimmingIfNeeded, mState.size()=" + mState.size());
+        for (int i = mState.size() - 1; i >= 0; i--) {
+            DimLayer.DimLayerUser dimLayerUser = mState.keyAt(i);
+            stopDimmingIfNeeded(dimLayerUser);
+        }
+    }
+
+    private void stopDimmingIfNeeded(DimLayer.DimLayerUser dimLayerUser) {
+        // No need to check if state is null, we know the key has a value.
+        DimBehindState state = mState.get(dimLayerUser);
+        if (DEBUG_DIM_LAYER) Slog.v(TAG, "stopDimmingIfNeeded,"
+                + " dimLayerUser=" + dimLayerUser.toShortString()
+                + " state.continueDimming=" + state.continueDimming
+                + " state.dimLayer.isDimming=" + state.dimLayer.isDimming());
+        if (!state.continueDimming && state.dimLayer.isDimming()) {
+            state.animator = null;
+            dimLayerUser.getBounds(mTmpBounds);
+            state.dimLayer.setBounds(mTmpBounds);
+        }
+    }
+
+    boolean animateDimLayers() {
+        int fullScreen = -1;
+        for (int i = mState.size() - 1; i >= 0; i--) {
+            DimLayer.DimLayerUser dimLayerUser = mState.keyAt(i);
+            if (dimLayerUser.isFullscreen()) {
+                fullScreen = i;
+                if (mState.valueAt(i).continueDimming) {
+                    break;
+                }
+            }
+        }
+        if (fullScreen != -1) {
+            return animateDimLayers(mState.keyAt(fullScreen));
+        } else {
+            boolean result = false;
+            for (int i = mState.size() - 1; i >= 0; i--) {
+                result |= animateDimLayers(mState.keyAt(i));
+            }
+            return result;
+        }
+    }
+
+    private boolean animateDimLayers(DimLayer.DimLayerUser dimLayerUser) {
+        DimBehindState state = mState.get(dimLayerUser);
+        if (DEBUG_DIM_LAYER) Slog.v(TAG, "animateDimLayers,"
+                + " dimLayerUser=" + dimLayerUser.toShortString()
+                + " state.animator=" + state.animator
+                + " state.continueDimming=" + state.continueDimming);
+        final int dimLayer;
+        final float dimAmount;
+        if (state.animator == null) {
+            dimLayer = state.dimLayer.getLayer();
+            dimAmount = 0;
+        } else {
+            dimLayer = state.animator.mAnimLayer - WindowManagerService.LAYER_OFFSET_DIM;
+            dimAmount = state.animator.mWin.mAttrs.dimAmount;
+        }
+        final float targetAlpha = state.dimLayer.getTargetAlpha();
+        if (targetAlpha != dimAmount) {
+            if (state.animator == null) {
+                state.dimLayer.hide(DEFAULT_DIM_DURATION);
+            } else {
+                long duration = (state.animator.mAnimating && state.animator.mAnimation != null)
+                        ? state.animator.mAnimation.computeDurationHint()
+                        : DEFAULT_DIM_DURATION;
+                if (targetAlpha > dimAmount) {
+                    duration = getDimBehindFadeDuration(duration);
+                }
+                state.dimLayer.show(dimLayer, dimAmount, duration);
+            }
+        } else if (state.dimLayer.getLayer() != dimLayer) {
+            state.dimLayer.setLayer(dimLayer);
+        }
+        if (state.dimLayer.isAnimating()) {
+            if (!mDisplayContent.mService.okToDisplay()) {
+                // Jump to the end of the animation.
+                state.dimLayer.show();
+            } else {
+                return state.dimLayer.stepAnimation();
+            }
+        }
+        return false;
+    }
+
+    boolean isDimming(DimLayer.DimLayerUser dimLayerUser, WindowStateAnimator winAnimator) {
+        DimBehindState state = mState.get(dimLayerUser);
+        return state != null && state.animator == winAnimator && state.dimLayer.isDimming();
+    }
+
+    private long getDimBehindFadeDuration(long duration) {
+        TypedValue tv = new TypedValue();
+        mDisplayContent.mService.mContext.getResources().getValue(
+                com.android.internal.R.fraction.config_dimBehindFadeDuration, tv, true);
+        if (tv.type == TypedValue.TYPE_FRACTION) {
+            duration = (long) tv.getFraction(duration, duration);
+        } else if (tv.type >= TypedValue.TYPE_FIRST_INT && tv.type <= TypedValue.TYPE_LAST_INT) {
+            duration = tv.data;
+        }
+        return duration;
+    }
+
+    void close() {
+        for (int i = mState.size() - 1; i >= 0; i--) {
+            DimBehindState state = mState.valueAt(i);
+            state.dimLayer.destroySurface();
+        }
+        mState.clear();
+        mSharedFullScreenDimLayer = null;
+    }
+
+    void removeDimLayerUser(DimLayer.DimLayerUser dimLayerUser) {
+        mState.remove(dimLayerUser);
+    }
+
+    void applyDimBehind(DimLayer.DimLayerUser dimLayerUser, WindowStateAnimator animator) {
+        if (dimLayerUser == null) {
+            Slog.e(TAG, "Trying to apply dim layer for: " + this
+                    + ", but no dim layer user found.");
+            return;
+        }
+        if (!getContinueDimming(dimLayerUser)) {
+            setContinueDimming(dimLayerUser);
+            if (!isDimming(dimLayerUser, animator)) {
+                if (DEBUG_DIM_LAYER) Slog.v(TAG, "Win " + this + " start dimming.");
+                startDimmingIfNeeded(dimLayerUser, animator);
+            }
+        }
+    }
+
+    private static class DimBehindState {
+        // The particular window with FLAG_DIM_BEHIND set. If null, hide dimLayer.
+        WindowStateAnimator animator;
+        // Set to false at the start of performLayoutAndPlaceSurfaces. If it is still false by the
+        // end then stop any dimming.
+        boolean continueDimming;
+        DimLayer dimLayer;
+    }
+
+    void dump(String prefix, PrintWriter pw) {
+        pw.println(prefix + "DimBehindController");
+        for (int i = 0, n = mState.size(); i < n; i++) {
+            pw.println(prefix + "  " + mState.keyAt(i).toShortString());
+            pw.print(prefix + "    ");
+            DimBehindState state = mState.valueAt(i);
+            pw.print("dimLayer=" + (state.dimLayer == mSharedFullScreenDimLayer ? "shared" :
+                    state.dimLayer));
+            pw.print(", animator=" + state.animator);
+            pw.println(", continueDimming=" + state.continueDimming + "}");
+
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/wm/DimLayer.java b/services/core/java/com/android/server/wm/DimLayer.java
index 538d6b84..8c479d8 100644
--- a/services/core/java/com/android/server/wm/DimLayer.java
+++ b/services/core/java/com/android/server/wm/DimLayer.java
@@ -65,6 +65,9 @@
         boolean isFullscreen();
         /** Returns the display info. of the dim layer user. */
         DisplayInfo getDisplayInfo();
+        /** Gets the bounds of the dim layer user. */
+        void getBounds(Rect outBounds);
+        String toShortString();
     }
     /** The user of this dim layer. */
     final DimLayerUser mUser;
@@ -239,8 +242,9 @@
                 mDuration = duration;
             }
         }
-        if (DEBUG) Slog.v(TAG, "show: mStartAlpha=" + mStartAlpha + " mStartTime=" + mStartTime);
         mTargetAlpha = alpha;
+        if (DEBUG) Slog.v(TAG, "show: mStartAlpha=" + mStartAlpha + " mStartTime=" + mStartTime
+                + " mTargetAlpha=" + mTargetAlpha);
     }
 
     /** Immediate hide.
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 6b5ecdc..f13f350 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -115,6 +115,8 @@
 
     final DockedStackDividerController mDividerControllerLocked;
 
+    final DimBehindController mDimBehindController;
+
     /**
      * @param display May not be null.
      * @param service You know.
@@ -128,6 +130,7 @@
         mService = service;
         initializeDisplayBaseInfo();
         mDividerControllerLocked = new DockedStackDividerController(service.mContext, this);
+        mDimBehindController = new DimBehindController(this);
     }
 
     int getDisplayId() {
@@ -246,6 +249,7 @@
     }
 
     void detachStack(TaskStack stack) {
+        mDimBehindController.removeDimLayerUser(stack);
         mStacks.remove(stack);
     }
 
@@ -382,54 +386,23 @@
     }
 
     boolean animateDimLayers() {
-        boolean result = false;
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ArrayList<Task> tasks = mStacks.get(stackNdx).getTasks();
-            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
-                final Task task = tasks.get(taskNdx);
-                result |= task.animateDimLayers();
-                if (task.isFullscreen()) {
-                    // No point in continuing as this task covers the entire screen.
-                    // Also, fullscreen tasks all share the same dim layer, so we don't want
-                    // processing of fullscreen task below this one affecting the dim layer state.
-                    return result;
-                }
-            }
-        }
-        return result;
+        return mDimBehindController.animateDimLayers();
     }
 
     void resetDimming() {
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ArrayList<Task> tasks = mStacks.get(stackNdx).getTasks();
-            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
-                tasks.get(taskNdx).clearContinueDimming();
-            }
-        }
+        mDimBehindController.resetDimming();
     }
 
     boolean isDimming() {
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ArrayList<Task> tasks = mStacks.get(stackNdx).getTasks();
-            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
-                if (tasks.get(taskNdx).isDimming()) {
-                    return true;
-                }
-            }
-        }
-        return false;
+        return mDimBehindController.isDimming();
     }
 
     void stopDimmingIfNeeded() {
-        for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ArrayList<Task> tasks = mStacks.get(stackNdx).getTasks();
-            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
-                tasks.get(taskNdx).stopDimmingIfNeeded();
-            }
-        }
+        mDimBehindController.stopDimmingIfNeeded();
     }
 
     void close() {
+        mDimBehindController.close();
         for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
             mStacks.get(stackNdx).close();
         }
@@ -576,6 +549,7 @@
             }
         }
         pw.println();
+        mDimBehindController.dump(prefix + "  ", pw);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 8c5d319..b9028e3 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import static android.app.ActivityManager.DOCKED_STACK_ID;
+import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
@@ -25,16 +26,15 @@
 import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
 import static com.android.server.wm.TaskStack.DOCKED_BOTTOM;
-import static com.android.server.wm.TaskStack.DOCKED_INVALID;
 import static com.android.server.wm.TaskStack.DOCKED_LEFT;
 import static com.android.server.wm.TaskStack.DOCKED_RIGHT;
 import static com.android.server.wm.TaskStack.DOCKED_TOP;
 
 import android.content.Context;
+import android.content.res.Configuration;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.os.RemoteException;
-import android.util.Slog;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
@@ -58,7 +58,6 @@
     private Rect mOriginalRect = new Rect();
     private int mDockSide;
 
-
     DockedStackDividerController(Context context, DisplayContent displayContent) {
         mContext = context;
         mDisplayContent = displayContent;
@@ -66,13 +65,16 @@
                 com.android.internal.R.dimen.docked_stack_divider_thickness);
     }
 
-    private void addDivider() {
+    private void addDivider(Configuration configuration) {
         View view = LayoutInflater.from(mContext).inflate(
                 com.android.internal.R.layout.docked_stack_divider, null);
         view.setOnTouchListener(this);
         WindowManagerGlobal manager = WindowManagerGlobal.getInstance();
+        final boolean landscape = configuration.orientation == ORIENTATION_LANDSCAPE;
+        final int width = landscape ? mDividerWidth : MATCH_PARENT;
+        final int height = landscape ? MATCH_PARENT : mDividerWidth;
         WindowManager.LayoutParams params = new WindowManager.LayoutParams(
-                mDividerWidth, MATCH_PARENT, TYPE_DOCK_DIVIDER,
+                width, height, TYPE_DOCK_DIVIDER,
                 FLAG_TOUCHABLE_WHEN_WAKING | FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL
                         | FLAG_WATCH_OUTSIDE_TOUCH | FLAG_SPLIT_TOUCH,
                 PixelFormat.OPAQUE);
@@ -92,10 +94,13 @@
         return mView != null;
     }
 
-    void update() {
+    void update(Configuration configuration, boolean forceUpdate) {
+        if (forceUpdate && mView != null) {
+            removeDivider();
+        }
         TaskStack stack = mDisplayContent.getDockedStackLocked();
         if (stack != null && mView == null) {
-            addDivider();
+            addDivider(configuration);
         } else if (stack == null && mView != null) {
             removeDivider();
         }
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 1f986dd..c4600e0 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -29,7 +29,6 @@
 import android.util.EventLog;
 import android.util.Slog;
 import android.util.SparseArray;
-import android.util.TypedValue;
 import android.view.DisplayInfo;
 import android.view.Surface;
 
@@ -39,10 +38,6 @@
 import java.util.ArrayList;
 
 class Task implements DimLayer.DimLayerUser {
-    /** Amount of time in milliseconds to animate the dim surface from one value to another,
-     * when no window animation is driving it. */
-    private static final int DEFAULT_DIM_DURATION = 200;
-
     // Return value from {@link setBounds} indicating no change was made to the Task bounds.
     static final int BOUNDS_CHANGE_NONE = 0;
     // Return value from {@link setBounds} indicating the position of the Task bounds changed.
@@ -78,17 +73,6 @@
     // Whether the task is currently being drag-resized
     private boolean mDragResizing;
 
-    // The particular window with FLAG_DIM_BEHIND set. If null, hide mDimLayer.
-    WindowStateAnimator mDimWinAnimator;
-    // Used to support {@link android.view.WindowManager.LayoutParams#FLAG_DIM_BEHIND}
-    private DimLayer mDimLayer;
-    // Set to false at the start of performLayoutAndPlaceSurfaces. If it is still false by the end
-    // then stop any dimming.
-    private boolean mContinueDimming;
-    // Shared dim layer for fullscreen tasks. {@link #mDimLayer} will point to this instead
-    // of creating a new object per fullscreen task on a display.
-    private static final SparseArray<DimLayer> sSharedFullscreenDimLayers = new SparseArray<>();
-
     Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds,
             Configuration config) {
         mTaskId = taskId;
@@ -128,6 +112,10 @@
         if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing taskId=" + mTaskId);
         EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "removeTask");
         mDeferRemoval = false;
+        DisplayContent content = getDisplayContent();
+        if (content != null) {
+            content.mDimBehindController.removeDimLayerUser(this);
+        }
         mStack.removeTask(this);
         mService.mTaskIdToTask.delete(mTaskId);
     }
@@ -228,7 +216,9 @@
 
         mBounds.set(bounds);
         mRotation = rotation;
-        updateDimLayer();
+        if (displayContent != null) {
+            displayContent.mDimBehindController.updateDimLayer(this);
+        }
         mOverrideConfig = mFullscreen ? Configuration.EMPTY : config;
         return boundsChange;
     }
@@ -261,7 +251,8 @@
     }
 
     /** Bounds of the task with other system factors taken into consideration. */
-    void getBounds(Rect out) {
+    @Override
+    public void getBounds(Rect out) {
         if (useCurrentBounds()) {
             // No need to adjust the output bounds if fullscreen or the docked stack is visible
             // since it is already what we want to represent to the rest of the system.
@@ -303,142 +294,12 @@
         if (setBounds(mTmpRect2, mOverrideConfig) != BOUNDS_CHANGE_NONE) {
             // Post message to inform activity manager of the bounds change simulating
             // a one-way call. We do this to prevent a deadlock between window manager
-            // lock and activity manager lock been held.
-            mService.mH.sendMessage(mService.mH.obtainMessage(
-                            RESIZE_TASK, mTaskId, RESIZE_MODE_SYSTEM_SCREEN_ROTATION, mBounds));
-        }
-    }
-
-    /** Updates the dim layer bounds, recreating it if needed. */
-    private void updateDimLayer() {
-        DimLayer newDimLayer;
-        final boolean previousFullscreen =
-                mDimLayer != null && sSharedFullscreenDimLayers.indexOfValue(mDimLayer) > -1;
-        final int displayId = mStack.getDisplayContent().getDisplayId();
-        if (mFullscreen) {
-            if (previousFullscreen) {
-                // Nothing to do here...
-                return;
+            // lock and activity manager lock been held. Only tasks within the freeform stack
+            // are resizeable independently of their stack resizing.
+            if (mStack.mStackId == FREEFORM_WORKSPACE_STACK_ID) {
+                mService.mH.sendMessage(mService.mH.obtainMessage(
+                        RESIZE_TASK, mTaskId, RESIZE_MODE_SYSTEM_SCREEN_ROTATION, mBounds));
             }
-            // Use shared fullscreen dim layer
-            newDimLayer = sSharedFullscreenDimLayers.get(displayId);
-            if (newDimLayer == null) {
-                if (mDimLayer != null) {
-                    // Re-purpose the previous dim layer.
-                    newDimLayer = mDimLayer;
-                } else {
-                    // Create new full screen dim layer.
-                    newDimLayer = new DimLayer(mService, this, displayId);
-                }
-                newDimLayer.setBounds(mBounds);
-                sSharedFullscreenDimLayers.put(displayId, newDimLayer);
-            } else if (mDimLayer != null) {
-                mDimLayer.destroySurface();
-            }
-        } else {
-            newDimLayer = (mDimLayer == null || previousFullscreen)
-                    ? new DimLayer(mService, this, displayId) : mDimLayer;
-            newDimLayer.setBounds(mBounds);
-        }
-        mDimLayer = newDimLayer;
-    }
-
-    boolean animateDimLayers() {
-        final int dimLayer;
-        final float dimAmount;
-        if (mDimWinAnimator == null) {
-            dimLayer = mDimLayer.getLayer();
-            dimAmount = 0;
-        } else {
-            dimLayer = mDimWinAnimator.mAnimLayer - WindowManagerService.LAYER_OFFSET_DIM;
-            dimAmount = mDimWinAnimator.mWin.mAttrs.dimAmount;
-        }
-        final float targetAlpha = mDimLayer.getTargetAlpha();
-        if (targetAlpha != dimAmount) {
-            if (mDimWinAnimator == null) {
-                mDimLayer.hide(DEFAULT_DIM_DURATION);
-            } else {
-                long duration = (mDimWinAnimator.mAnimating && mDimWinAnimator.mAnimation != null)
-                        ? mDimWinAnimator.mAnimation.computeDurationHint()
-                        : DEFAULT_DIM_DURATION;
-                if (targetAlpha > dimAmount) {
-                    duration = getDimBehindFadeDuration(duration);
-                }
-                mDimLayer.show(dimLayer, dimAmount, duration);
-            }
-        } else if (mDimLayer.getLayer() != dimLayer) {
-            mDimLayer.setLayer(dimLayer);
-        }
-        if (mDimLayer.isAnimating()) {
-            if (!mService.okToDisplay()) {
-                // Jump to the end of the animation.
-                mDimLayer.show();
-            } else {
-                return mDimLayer.stepAnimation();
-            }
-        }
-        return false;
-    }
-
-    private long getDimBehindFadeDuration(long duration) {
-        TypedValue tv = new TypedValue();
-        mService.mContext.getResources().getValue(
-                com.android.internal.R.fraction.config_dimBehindFadeDuration, tv, true);
-        if (tv.type == TypedValue.TYPE_FRACTION) {
-            duration = (long)tv.getFraction(duration, duration);
-        } else if (tv.type >= TypedValue.TYPE_FIRST_INT && tv.type <= TypedValue.TYPE_LAST_INT) {
-            duration = tv.data;
-        }
-        return duration;
-    }
-
-    void clearContinueDimming() {
-        mContinueDimming = false;
-    }
-
-    void setContinueDimming() {
-        mContinueDimming = true;
-    }
-
-    boolean getContinueDimming() {
-        return mContinueDimming;
-    }
-
-    boolean isDimming() {
-        return mDimLayer.isDimming();
-    }
-
-    boolean isDimming(WindowStateAnimator winAnimator) {
-        return mDimWinAnimator == winAnimator && isDimming();
-    }
-
-    void startDimmingIfNeeded(WindowStateAnimator newWinAnimator) {
-        // Only set dim params on the highest dimmed layer.
-        // Don't turn on for an unshown surface, or for any layer but the highest dimmed layer.
-        if (newWinAnimator.mSurfaceShown && (mDimWinAnimator == null
-                || !mDimWinAnimator.mSurfaceShown
-                || mDimWinAnimator.mAnimLayer < newWinAnimator.mAnimLayer)) {
-            mDimWinAnimator = newWinAnimator;
-            if (mDimWinAnimator.mWin.mAppToken == null
-                    && !mFullscreen && mStack.getDisplayContent() != null) {
-                // Dim should cover the entire screen for system windows.
-                mStack.getDisplayContent().getLogicalDisplayRect(mTmpRect);
-                mDimLayer.setBounds(mTmpRect);
-            }
-        }
-    }
-
-    void stopDimmingIfNeeded() {
-        if (!mContinueDimming && isDimming()) {
-            mDimWinAnimator = null;
-            mDimLayer.setBounds(mBounds);
-        }
-    }
-
-    void close() {
-        if (mDimLayer != null) {
-            mDimLayer.destroySurface();
-            mDimLayer = null;
         }
     }
 
@@ -491,16 +352,14 @@
         return "{taskId=" + mTaskId + " appTokens=" + mAppTokens + " mdr=" + mDeferRemoval + "}";
     }
 
+    @Override
+    public String toShortString() {
+        return "Task=" + mTaskId;
+    }
+
     public void printTo(String prefix, PrintWriter pw) {
         pw.print(prefix); pw.print("taskId="); pw.print(mTaskId);
                 pw.print(prefix); pw.print("appTokens="); pw.print(mAppTokens);
                 pw.print(prefix); pw.print("mdr="); pw.println(mDeferRemoval);
-        if (mDimLayer.isDimming()) {
-            pw.print(prefix); pw.println("mDimLayer:");
-            mDimLayer.printTo(prefix + " ", pw);
-            pw.print(prefix); pw.print("mDimWinAnimator="); pw.println(mDimWinAnimator);
-        } else {
-            pw.println();
-        }
     }
 }
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index 9da7406..207da47 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -146,13 +146,18 @@
                         }
                         synchronized (mService.mWindowMap) {
                             mDragEnded = notifyMoveLocked(newX, newY);
+                            mTask.getBounds(mTmpRect);
                         }
-                        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wm.TaskPositioner.resizeTask");
-                        try {
-                            mService.mActivityManager.resizeTask(
-                                    mTask.mTaskId, mWindowDragBounds, RESIZE_MODE_USER);
-                        } catch(RemoteException e) {}
-                        Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+                        if (!mTmpRect.equals(mWindowDragBounds)) {
+                            Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,
+                                    "wm.TaskPositioner.resizeTask");
+                            try {
+                                mService.mActivityManager.resizeTask(
+                                        mTask.mTaskId, mWindowDragBounds, RESIZE_MODE_USER);
+                            } catch (RemoteException e) {
+                            }
+                            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+                        }
                     } break;
 
                     case MotionEvent.ACTION_UP: {
@@ -171,11 +176,12 @@
                 }
 
                 if (mDragEnded) {
+                    final boolean wasResizing = mResizing;
                     synchronized (mService.mWindowMap) {
                         endDragLocked();
                     }
                     try {
-                        if (mResizing) {
+                        if (wasResizing) {
                             // We were using fullscreen surface during resizing. Request
                             // resizeTask() one last time to restore surface to window size.
                             mService.mActivityManager.resizeTask(
@@ -462,6 +468,16 @@
         return mTask.mStack.getDisplayInfo();
     }
 
+    @Override
+    public void getBounds(Rect out) {
+        // This dim layer user doesn't need this.
+    }
+
+    @Override
+    public String toShortString() {
+        return TAG;
+    }
+
     private int getDragLayerLocked() {
         return mService.mPolicy.windowTypeToLayerLw(WindowManager.LayoutParams.TYPE_DRAG)
                 * WindowManagerService.TYPE_LAYER_MULTIPLIER
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index f030b9a..a630993 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -175,6 +175,10 @@
             return false;
         }
 
+        if (mDisplayContent != null) {
+            mDisplayContent.mDimBehindController.updateDimLayer(this);
+        }
+
         mAnimationBackgroundSurface.setBounds(bounds);
         mBounds.set(bounds);
         mRotation = rotation;
@@ -201,7 +205,8 @@
     }
 
     /** Bounds of the stack with other system factors taken into consideration. */
-    void getBounds(Rect out) {
+    @Override
+    public void getBounds(Rect out) {
         if (useCurrentBounds()) {
             // No need to adjust the output bounds if fullscreen or the docked stack is visible
             // since it is already what we want to represent to the rest of the system.
@@ -550,9 +555,6 @@
             mAnimationBackgroundSurface.destroySurface();
             mAnimationBackgroundSurface = null;
         }
-        for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
-            mTasks.get(taskNdx).close();
-        }
         mDisplayContent = null;
     }
 
@@ -609,6 +611,11 @@
         return "{stackId=" + mStackId + " tasks=" + mTasks + "}";
     }
 
+    @Override
+    public String toShortString() {
+        return "Stack=" + mStackId;
+    }
+
     /**
      * For docked workspace provides information which side of the screen was the dock anchored.
      */
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 74572cf..1b72876 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -216,6 +216,7 @@
     static final boolean DEBUG_STACK = false;
     static final boolean DEBUG_DISPLAY = false;
     static final boolean DEBUG_POWER = false;
+    static final boolean DEBUG_DIM_LAYER = false;
     static final boolean SHOW_SURFACE_ALLOC = false;
     static final boolean SHOW_TRANSACTIONS = false;
     static final boolean SHOW_LIGHT_TRANSACTIONS = false || SHOW_TRANSACTIONS;
@@ -3419,12 +3420,20 @@
         }
 
         synchronized(mWindowMap) {
+            final boolean orientationChanged = mCurConfiguration.orientation != config.orientation;
             mCurConfiguration = new Configuration(config);
             if (mWaitingForConfig) {
                 mWaitingForConfig = false;
                 mLastFinishedFreezeSource = "new-config";
             }
             mWindowPlacerLocked.performSurfacePlacement();
+            if (orientationChanged) {
+                for (int i = mDisplayContents.size() - 1; i >= 0; i--) {
+                    DisplayContent content = mDisplayContents.valueAt(i);
+                    Message.obtain(mH, H.UPDATE_DOCKED_STACK_DIVIDER, H.DOCK_DIVIDER_FORCE_UPDATE,
+                            H.UNUSED, content).sendToTarget();
+                }
+            }
         }
     }
 
@@ -7164,6 +7173,21 @@
         public static final int RESIZE_STACK = 43;
         public static final int RESIZE_TASK = 44;
 
+        /**
+         * Used to indicate in the message that the dock divider needs to be updated only if it's
+         * necessary.
+         */
+        static final int DOCK_DIVIDER_NO_FORCE_UPDATE = 0;
+        /**
+         * Used to indicate in the message that the dock divider should be force-removed before
+         * updating, so new configuration can be applied.
+         */
+        static final int DOCK_DIVIDER_FORCE_UPDATE = 1;
+        /**
+         * Used to denote that an integer field in a message will not be used.
+         */
+        public static final int UNUSED = 0;
+
         @Override
         public void handleMessage(Message msg) {
             if (DEBUG_WINDOW_TRACE) {
@@ -7705,8 +7729,9 @@
                 break;
                 case UPDATE_DOCKED_STACK_DIVIDER: {
                     DisplayContent content = (DisplayContent) msg.obj;
+                    final boolean forceUpdate = msg.arg1 == DOCK_DIVIDER_FORCE_UPDATE;
                     synchronized (mWindowMap) {
-                        content.mDividerControllerLocked.update();
+                        content.mDividerControllerLocked.update(mCurConfiguration, forceUpdate);
                     }
                 }
                 break;
@@ -8356,8 +8381,10 @@
                 layerChanged = true;
                 anyLayerChanged = true;
             }
-            final Task task = w.getTask();
-            if (layerChanged && task != null && task.isDimming(winAnimator)) {
+            final DimLayer.DimLayerUser dimLayerUser = w.getDimLayerUser();
+            final DisplayContent displayContent = w.getDisplayContent();
+            if (layerChanged && dimLayerUser != null && displayContent != null &&
+                    displayContent.mDimBehindController.isDimming(dimLayerUser, winAnimator)) {
                 // Force an animation pass just to update the mDimLayer layer.
                 scheduleAnimationLocked();
             }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 55ddbc0..8ace990 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -29,6 +29,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 import static com.android.server.wm.WindowManagerService.DEBUG_CONFIGURATION;
+import static com.android.server.wm.WindowManagerService.DEBUG_DIM_LAYER;
 import static com.android.server.wm.WindowManagerService.DEBUG_LAYOUT;
 import static com.android.server.wm.WindowManagerService.DEBUG_ORIENTATION;
 import static com.android.server.wm.WindowManagerService.DEBUG_POWER;
@@ -698,10 +699,10 @@
             final int height = Math.min(mFrame.height(), mContentFrame.height());
             final int width = Math.min(mContentFrame.width(), mFrame.width());
             final DisplayMetrics displayMetrics = getDisplayContent().getDisplayMetrics();
-            final int minVisibleHeight =
-                    mService.dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, displayMetrics);
-            final int minVisibleWidth =
-                    mService.dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, displayMetrics);
+            final int minVisibleHeight = WindowManagerService.dipToPixel(
+                    MINIMUM_VISIBLE_HEIGHT_IN_DP, displayMetrics);
+            final int minVisibleWidth = WindowManagerService.dipToPixel(
+                    MINIMUM_VISIBLE_WIDTH_IN_DP, displayMetrics);
             final int top = Math.max(mContentFrame.top,
                     Math.min(mFrame.top, mContentFrame.bottom - minVisibleHeight));
             final int left = Math.max(mContentFrame.left + minVisibleWidth - width,
@@ -889,7 +890,7 @@
 
     @Override
     public boolean isVoiceInteraction() {
-        return mAppToken != null ? mAppToken.voiceInteraction : false;
+        return mAppToken != null && mAppToken.voiceInteraction;
     }
 
     boolean setInsetsChanged() {
@@ -934,7 +935,10 @@
                 return task.mStack;
             }
         }
-        return null;
+        // Some system windows (e.g. "Power off" dialog) don't have a task, but we would still
+        // associate them with some stack to enable dimming.
+        return mAttrs.type >= WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW
+                && mDisplayContent != null ? mDisplayContent.getHomeStack() : null;
     }
 
     /**
@@ -970,7 +974,8 @@
         }
         if (forTouch && inFreeformWorkspace()) {
             final DisplayMetrics displayMetrics = getDisplayContent().getDisplayMetrics();
-            final int delta = mService.dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, displayMetrics);
+            final int delta = WindowManagerService.dipToPixel(
+                    RESIZE_HANDLE_WIDTH_IN_DP, displayMetrics);
             bounds.inset(-delta, -delta);
         }
     }
@@ -1031,8 +1036,7 @@
             return false;
         }
         final AppWindowToken atoken = mAppToken;
-        final boolean animating = atoken != null
-                ? (atoken.mAppAnimator.animation != null) : false;
+        final boolean animating = atoken != null && atoken.mAppAnimator.animation != null;
         return mHasSurface && !mDestroying && !mExiting
                 && (atoken == null ? mPolicyVisibility : !atoken.hiddenRequested)
                 && ((!mAttachedHidden && mViewVisibility == View.VISIBLE
@@ -1114,8 +1118,7 @@
      * of a transition that has not yet been started.
      */
     boolean isReadyForDisplay() {
-        if (mRootToken.waitingToShow &&
-                mService.mAppTransition.isTransitionSet()) {
+        if (mRootToken.waitingToShow && mService.mAppTransition.isTransitionSet()) {
             return false;
         }
         return mHasSurface && mPolicyVisibility && !mDestroying
@@ -1295,19 +1298,20 @@
     }
 
     void handleFlagDimBehind() {
-        if ((mAttrs.flags & FLAG_DIM_BEHIND) != 0 && isDisplayedLw() && !mExiting) {
-            final Task task = getTask();
-            if (task == null) {
-                return;
-            }
-            task.setContinueDimming();
-            if (!task.isDimming(mWinAnimator)) {
-                if (WindowManagerService.localLOGV) Slog.v(TAG, "Win " + this + " start dimming.");
-                task.startDimmingIfNeeded(mWinAnimator);
-            }
+        if ((mAttrs.flags & FLAG_DIM_BEHIND) != 0 && mDisplayContent != null && !mExiting
+                && isDisplayedLw()) {
+            mDisplayContent.mDimBehindController.applyDimBehind(getDimLayerUser(), mWinAnimator);
         }
     }
 
+    DimLayer.DimLayerUser getDimLayerUser() {
+        Task task = getTask();
+        if (task != null) {
+            return task;
+        }
+        return getStack();
+    }
+
     void maybeRemoveReplacedWindow() {
         AppWindowToken token = mAppToken;
         if (token != null && token.mReplacingWindow) {
@@ -1512,11 +1516,9 @@
 
     @Override
     public boolean isDimming() {
-        Task task = getTask();
-        if (task == null) {
-            return false;
-        }
-        return task.isDimming(mWinAnimator);
+        final DimLayer.DimLayerUser dimLayerUser = getDimLayerUser();
+        return dimLayerUser != null && mDisplayContent != null &&
+                mDisplayContent.mDimBehindController.isDimming(dimLayerUser, mWinAnimator);
     }
 
     public void setShowToOwnerOnlyLocked(boolean showToOwnerOnly) {
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 60bf571..ed53501 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1516,12 +1516,7 @@
                         mDsDy * w.mHScale, mDtDy * w.mVScale);
                 mAnimator.setPendingLayoutChanges(w.getDisplayId(),
                         WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
-                if ((w.mAttrs.flags & LayoutParams.FLAG_DIM_BEHIND) != 0) {
-                    final Task task = w.getTask();
-                    if (task != null) {
-                        task.startDimmingIfNeeded(this);
-                    }
-                }
+                w.handleFlagDimBehind();
             } catch (RuntimeException e) {
                 // If something goes wrong with the surface (such
                 // as running out of memory), don't take down the
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index df0a1c9..112646a 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -642,9 +642,7 @@
                     handleNotObscuredLocked(w, innerDw, innerDh);
                 }
 
-                if (task != null && !task.getContinueDimming()) {
-                    w.handleFlagDimBehind();
-                }
+                w.handleFlagDimBehind();
 
                 if (isDefaultDisplay && obscuredChanged
                         && mWallpaperControllerLocked.isWallpaperTarget(w) && w.isVisibleLw()) {
@@ -967,7 +965,8 @@
         }
 
         mService.mPolicy.finishLayoutLw();
-        mService.mH.obtainMessage(UPDATE_DOCKED_STACK_DIVIDER, displayContent).sendToTarget();
+        mService.mH.obtainMessage(UPDATE_DOCKED_STACK_DIVIDER,
+                DOCK_DIVIDER_NO_FORCE_UPDATE, UNUSED, displayContent).sendToTarget();
     }
 
     /**
diff --git a/services/tests/servicestests/src/com/android/server/MountServiceTests.java b/services/tests/servicestests/src/com/android/server/MountServiceTests.java
index 9c88b40..ecfe0db 100644
--- a/services/tests/servicestests/src/com/android/server/MountServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/MountServiceTests.java
@@ -27,8 +27,6 @@
 import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Log;
 
-import static com.android.server.MountService.buildObbPath;
-
 import com.android.frameworks.servicestests.R;
 
 import java.io.File;
@@ -42,16 +40,6 @@
 
     private static final String OBB_MOUNT_PREFIX = "/mnt/obb/";
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
-    }
-
     private static void assertStartsWith(String message, String prefix, String actual) {
         if (!actual.startsWith(prefix)) {
             throw new ComparisonFailure(message, prefix, actual);
@@ -195,8 +183,7 @@
         final ObbObserver observer = new ObbObserver();
 
         assertTrue("unmountObb call on test1.obb should succeed",
- sm.unmountObb(file.getPath(),
-                false, observer));
+                sm.unmountObb(file.getPath(), false, observer));
 
         assertTrue("Unmount should have completed",
                 observer.waitForCompletion());
@@ -284,34 +271,4 @@
         unmountObb(sm, file1, OnObbStateChangeListener.UNMOUNTED);
         unmountObb(sm, file2, OnObbStateChangeListener.UNMOUNTED);
     }
-
-    public void testBuildObbPath() {
-        final int userId = 10;
-
-        // Paths outside external storage should remain untouched
-        assertEquals("/storage/random/foo",
-                buildObbPath("/storage/random/foo", userId, true));
-        assertEquals("/storage/random/foo",
-                buildObbPath("/storage/random/foo", userId, false));
-
-        // Paths on user-specific emulated storage
-        assertEquals("/mnt/shell/emulated/10/foo",
-                buildObbPath("/storage/emulated_legacy/foo", userId, true));
-        assertEquals("/storage/emulated/10/foo",
-                buildObbPath("/storage/emulated_legacy/foo", userId, false));
-        assertEquals("/mnt/shell/emulated/10/foo",
-                buildObbPath("/storage/emulated/10/foo", userId, true));
-        assertEquals("/storage/emulated/10/foo",
-                buildObbPath("/storage/emulated/10/foo", userId, false));
-
-        // Paths on shared OBB emulated storage
-        assertEquals("/mnt/shell/emulated/obb/foo",
-                buildObbPath("/storage/emulated_legacy/Android/obb/foo", userId, true));
-        assertEquals("/storage/emulated/0/Android/obb/foo",
-                buildObbPath("/storage/emulated_legacy/Android/obb/foo", userId, false));
-        assertEquals("/mnt/shell/emulated/obb/foo",
-                buildObbPath("/storage/emulated/10/Android/obb/foo", userId, true));
-        assertEquals("/storage/emulated/0/Android/obb/foo",
-                buildObbPath("/storage/emulated/10/Android/obb/foo", userId, false));
-    }
 }
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 7f813ec..3160e39 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -753,7 +753,7 @@
                                         UsbManager.USB_FUNCTION_MTP)
                                 || UsbManager.containsFunction(mCurrentFunctions,
                                         UsbManager.USB_FUNCTION_PTP);
-                        if (active && mCurrentUser != UserHandle.USER_NULL) {
+                        if (mUsbDataUnlocked && active && mCurrentUser != UserHandle.USER_NULL) {
                             Slog.v(TAG, "Current user switched to " + mCurrentUser
                                     + "; resetting USB host stack for MTP or PTP");
                             setEnabledFunctions(mCurrentFunctions, true);
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/MultiProducerActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/MultiProducerActivity.java
index b458d9b..7628c5c 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/MultiProducerActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/MultiProducerActivity.java
@@ -188,7 +188,7 @@
                 // This call should be done while the rendernode's displaylist is produced.
                 // For simplicity of this test we do this before we kick off the draw.
                 mContent.getLocationInSurface(surfaceOrigin);
-                mRenderer.setContentOverdrawProtectionBounds(surfaceOrigin[0], surfaceOrigin[1],
+                mRenderer.setContentDrawBounds(surfaceOrigin[0], surfaceOrigin[1],
                         surfaceOrigin[0] + mContent.getWidth(),
                         surfaceOrigin[1] + mContent.getHeight());
                 // Determine new position for frame.