Merge "WorkSource can now track package names."
diff --git a/api/current.txt b/api/current.txt
index 72e7601..1cf14aa 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -29106,7 +29106,7 @@
     method public void setRelativeScrollPosition(int, int);
     method public deprecated void setRemoteAdapter(int, int, android.content.Intent);
     method public void setRemoteAdapter(int, android.content.Intent);
-    method public void setRemoteAdapter(int, java.util.ArrayList<android.widget.RemoteViews>);
+    method public void setRemoteAdapter(int, java.util.ArrayList<android.widget.RemoteViews>, int);
     method public void setScrollPosition(int, int);
     method public void setShort(int, java.lang.String, short);
     method public void setString(int, java.lang.String, java.lang.String);
diff --git a/core/java/android/net/DhcpResults.java b/core/java/android/net/DhcpResults.java
index 2f300de..a3f70da 100644
--- a/core/java/android/net/DhcpResults.java
+++ b/core/java/android/net/DhcpResults.java
@@ -18,6 +18,7 @@
 
 import android.os.Parcelable;
 import android.os.Parcel;
+import android.text.TextUtils;
 import android.util.Log;
 
 import java.net.InetAddress;
@@ -211,11 +212,13 @@
     }
 
     public boolean addDns(String addrString) {
-        try {
-            linkProperties.addDns(NetworkUtils.numericToInetAddress(addrString));
-        } catch (IllegalArgumentException e) {
-            Log.e(TAG, "addDns failed with addrString " + addrString);
-            return true;
+        if (TextUtils.isEmpty(addrString) == false) {
+            try {
+                linkProperties.addDns(NetworkUtils.numericToInetAddress(addrString));
+            } catch (IllegalArgumentException e) {
+                Log.e(TAG, "addDns failed with addrString " + addrString);
+                return true;
+            }
         }
         return false;
     }
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 788ab74..d69fef0 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -2087,6 +2087,10 @@
                                         + "Parcelable.Creator object called "
                                         + " CREATOR on class " + name);
                 }
+                catch (NullPointerException e) {
+                    throw new BadParcelableException("Parcelable protocol requires "
+                            + "the CREATOR object to be static on class " + name);
+                }
                 if (creator == null) {
                     throw new BadParcelableException("Parcelable protocol requires a "
                                         + "Parcelable.Creator object called "
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 4dbc4b4..441214c 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2610,6 +2610,7 @@
             MOVED_TO_GLOBAL.add(Settings.Global.ADB_ENABLED);
             MOVED_TO_GLOBAL.add(Settings.Global.ASSISTED_GPS_ENABLED);
             MOVED_TO_GLOBAL.add(Settings.Global.BLUETOOTH_ON);
+            MOVED_TO_GLOBAL.add(Settings.Global.BUGREPORT_IN_POWER_MENU);
             MOVED_TO_GLOBAL.add(Settings.Global.CDMA_CELL_BROADCAST_SMS);
             MOVED_TO_GLOBAL.add(Settings.Global.CDMA_ROAMING_MODE);
             MOVED_TO_GLOBAL.add(Settings.Global.CDMA_SUBSCRIPTION_MODE);
@@ -3081,8 +3082,10 @@
         /**
          * When the user has enable the option to have a "bug report" command
          * in the power menu.
+         * @deprecated Use {@link android.provider.Settings.Global#BUGREPORT_IN_POWER_MENU} instead
          * @hide
          */
+        @Deprecated
         public static final String BUGREPORT_IN_POWER_MENU = "bugreport_in_power_menu";
 
         /**
@@ -4037,7 +4040,7 @@
          * @hide
          */
         public static final String[] SETTINGS_TO_BACKUP = {
-            BUGREPORT_IN_POWER_MENU,
+            BUGREPORT_IN_POWER_MENU,                            // moved to global
             ALLOW_MOCK_LOCATION,
             PARENTAL_CONTROL_ENABLED,
             PARENTAL_CONTROL_REDIRECT_URL,
@@ -4316,6 +4319,13 @@
         public static final String STAY_ON_WHILE_PLUGGED_IN = "stay_on_while_plugged_in";
 
         /**
+         * When the user has enable the option to have a "bug report" command
+         * in the power menu.
+         * @hide
+         */
+        public static final String BUGREPORT_IN_POWER_MENU = "bugreport_in_power_menu";
+
+        /**
          * Whether ADB is enabled.
          */
         public static final String ADB_ENABLED = "adb_enabled";
@@ -5359,6 +5369,7 @@
          * @hide
          */
         public static final String[] SETTINGS_TO_BACKUP = {
+            BUGREPORT_IN_POWER_MENU,
             STAY_ON_WHILE_PLUGGED_IN,
             MODE_RINGER,
             AUTO_TIME,
diff --git a/core/java/android/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java
index 3c984b5..352cb22 100644
--- a/core/java/android/text/format/DateFormat.java
+++ b/core/java/android/text/format/DateFormat.java
@@ -452,6 +452,16 @@
      * @hide
      */
     public static boolean hasSeconds(CharSequence inFormat) {
+        return hasDesignator(inFormat, SECONDS);
+    }
+
+    /**
+     * Test if a format string contains the given designator. Always returns
+     * {@code false} if the input format is {@code null}.
+     *
+     * @hide
+     */
+    public static boolean hasDesignator(CharSequence inFormat, char designator) {
         if (inFormat == null) return false;
 
         final int length = inFormat.length();
@@ -465,7 +475,7 @@
 
             if (c == QUOTE) {
                 count = skipQuotedText(inFormat, i, length);
-            } else if (c == SECONDS) {
+            } else if (c == designator) {
                 return true;
             }
         }
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 86d04b6..7ecdcbe 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -43,6 +43,7 @@
 
 import java.io.File;
 import java.io.PrintWriter;
+import java.util.Arrays;
 import java.util.concurrent.locks.ReentrantLock;
 
 import static javax.microedition.khronos.egl.EGL10.*;
@@ -88,10 +89,12 @@
      *
      * Possible values:
      * "true", to enable profiling
-     * "visual", to enable profiling and visualize the results on screen
+     * "visual_bars", to enable profiling and visualize the results on screen
+     * "visual_lines", to enable profiling and visualize the results on screen
      * "false", to disable profiling
      *
-     * @see #PROFILE_PROPERTY_VISUALIZE
+     * @see #PROFILE_PROPERTY_VISUALIZE_BARS
+     * @see #PROFILE_PROPERTY_VISUALIZE_LINES
      *
      * @hide
      */
@@ -99,11 +102,19 @@
 
     /**
      * Value for {@link #PROFILE_PROPERTY}. When the property is set to this
-     * value, profiling data will be visualized on screen.
+     * value, profiling data will be visualized on screen as a bar chart.
      *
      * @hide
      */
-    public static final String PROFILE_PROPERTY_VISUALIZE = "visual";
+    public static final String PROFILE_PROPERTY_VISUALIZE_BARS = "visual_bars";
+
+    /**
+     * Value for {@link #PROFILE_PROPERTY}. When the property is set to this
+     * value, profiling data will be visualized on screen as a line chart.
+     *
+     * @hide
+     */
+    public static final String PROFILE_PROPERTY_VISUALIZE_LINES = "visual_lines";
 
     /**
      * System property used to specify the number of frames to be used
@@ -619,6 +630,100 @@
         mRequested = requested;
     }
 
+    /**
+     * Describes a series of frames that should be drawn on screen as a graph.
+     * Each frame is composed of 1 or more elements.
+     */
+    abstract class GraphDataProvider {
+        /**
+         * Draws the graph as bars. Frame elements are stacked on top of
+         * each other.
+         */
+        public static final int GRAPH_TYPE_BARS = 0;
+        /**
+         * Draws the graph as lines. The number of series drawn corresponds
+         * to the number of elements.
+         */
+        public static final int GRAPH_TYPE_LINES = 1;
+
+        /**
+         * Returns the type of graph to render.
+         *
+         * @return {@link #GRAPH_TYPE_BARS} or {@link #GRAPH_TYPE_LINES}
+         */
+        abstract int getGraphType();
+
+        /**
+         * This method is invoked before the graph is drawn. This method
+         * can be used to compute sizes, etc.
+         *
+         * @param metrics The display metrics
+         */
+        abstract void prepare(DisplayMetrics metrics);
+
+        /**
+         * @return The size in pixels of a vertical unit.
+         */
+        abstract int getVerticalUnitSize();
+
+        /**
+         * @return The size in pixels of a horizontal unit.
+         */
+        abstract int getHorizontalUnitSize();
+
+        /**
+         * @return The size in pixels of the margin between horizontal units.
+         */
+        abstract int getHorizontaUnitMargin();
+
+        /**
+         * An optional threshold value.
+         *
+         * @return A value >= 0 to draw the threshold, a negative value
+         *         to ignore it.
+         */
+        abstract float getThreshold();
+
+        /**
+         * The data to draw in the graph. The number of elements in the
+         * array must be at least {@link #getFrameCount()} * {@link #getElementCount()}.
+         * If a value is negative the following values will be ignored.
+         */
+        abstract float[] getData();
+
+        /**
+         * Returns the number of frames to render in the graph.
+         */
+        abstract int getFrameCount();
+
+        /**
+         * Returns the number of elements in each frame. This directly affects
+         * the number of series drawn in the graph.
+         */
+        abstract int getElementCount();
+
+        /**
+         * Returns the current frame, if any. If the returned value is negative
+         * the current frame is ignored.
+         */
+        abstract int getCurrentFrame();
+
+        /**
+         * Prepares the paint to draw the specified element (or series.)
+         */
+        abstract void setupGraphPaint(Paint paint, int elementIndex);
+
+        /**
+         * Prepares the paint to draw the threshold.
+         */
+        abstract void setupThresholdPaint(Paint paint);
+
+        /**
+         * Prepares the paint to draw the current frame indicator.
+         */
+        abstract void setupCurrentFramePaint(Paint paint);
+    }
+
     @SuppressWarnings({"deprecation"})
     static abstract class GlRenderer extends HardwareRenderer {
         static final int SURFACE_STATE_ERROR = 0;
@@ -627,6 +732,14 @@
 
         static final int FUNCTOR_PROCESS_DELAY = 4;
 
+        private static final int PROFILE_DRAW_MARGIN = 0;
+        private static final int PROFILE_DRAW_WIDTH = 3;
+        private static final int[] PROFILE_DRAW_COLORS = { 0xcf3e66cc, 0xcfdc3912, 0xcfe69800 };
+        private static final int PROFILE_DRAW_CURRENT_FRAME_COLOR = 0xcf5faa4d;
+        private static final int PROFILE_DRAW_THRESHOLD_COLOR = 0xff5faa4d;
+        private static final int PROFILE_DRAW_THRESHOLD_STROKE_WIDTH = 2;
+        private static final int PROFILE_DRAW_DP_PER_MS = 7;
+
         static EGL10 sEgl;
         static EGLDisplay sEglDisplay;
         static EGLConfig sEglConfig;
@@ -660,12 +773,13 @@
         boolean mUpdateDirtyRegions;
 
         boolean mProfileEnabled;
-        boolean mProfileVisualizerEnabled;
+        int mProfileVisualizerType = -1;
         float[] mProfileData;
         ReentrantLock mProfileLock;
         int mProfileCurrentFrame = -PROFILE_FRAME_DATA_COUNT;
 
-        float[][] mProfileRects;
+        GraphDataProvider mDebugDataProvider;
+        float[][] mProfileShapes;
         Paint mProfilePaint;
 
         boolean mDebugDirtyRegions;
@@ -688,20 +802,32 @@
             loadSystemProperties(null);
         }
 
+        private static final String[] VISUALIZERS = {
+                PROFILE_PROPERTY_VISUALIZE_BARS,
+                PROFILE_PROPERTY_VISUALIZE_LINES
+        };
+
         @Override
         boolean loadSystemProperties(Surface surface) {
             boolean value;
             boolean changed = false;
 
             String profiling = SystemProperties.get(PROFILE_PROPERTY);
-            value = PROFILE_PROPERTY_VISUALIZE.equalsIgnoreCase(profiling);
+            int graphType = Arrays.binarySearch(VISUALIZERS, profiling);
+            value = graphType >= 0;
 
-            if (value != mProfileVisualizerEnabled) {
+            if (graphType != mProfileVisualizerType) {
                 changed = true;
-                mProfileVisualizerEnabled = value;
+                mProfileVisualizerType = graphType;
 
-                mProfileRects = null;
+                mProfileShapes = null;
                 mProfilePaint = null;
+
+                if (value) {
+                    mDebugDataProvider = new DrawPerformanceDataProvider(graphType);
+                } else {
+                    mDebugDataProvider = null;
+                }
             }
 
             // If on-screen profiling is not enabled, we need to check whether
@@ -728,6 +854,7 @@
                 } else {
                     mProfileData = null;
                     mProfileLock = null;
+                    mProfileVisualizerType = -1;
                 }
 
                 mProfileCurrentFrame = -PROFILE_FRAME_DATA_COUNT;
@@ -1283,7 +1410,7 @@
                 }
             }
 
-            if (mProfileEnabled && mProfileVisualizerEnabled) dirty = null;
+            if (mDebugDataProvider != null) dirty = null;
 
             return dirty;
         }
@@ -1459,20 +1586,102 @@
             }
             return SURFACE_STATE_SUCCESS;
         }
+
+        private static int dpToPx(int dp, float density) {
+            return (int) (dp * density + 0.5f);
+        }
+
+        class DrawPerformanceDataProvider extends GraphDataProvider {
+            private final int mGraphType;
+
+            private int mVerticalUnit;
+            private int mHorizontalUnit;
+            private int mHorizontalMargin;
+            private int mThresholdStroke;
+
+            DrawPerformanceDataProvider(int graphType) {
+                mGraphType = graphType;
+            }
+
+            @Override
+            void prepare(DisplayMetrics metrics) {
+                final float density = metrics.density;
+
+                mVerticalUnit = dpToPx(PROFILE_DRAW_DP_PER_MS, density);
+                mHorizontalUnit = dpToPx(PROFILE_DRAW_WIDTH, density);
+                mHorizontalMargin = dpToPx(PROFILE_DRAW_MARGIN, density);
+                mThresholdStroke = dpToPx(PROFILE_DRAW_THRESHOLD_STROKE_WIDTH, density);
+            }
+
+            @Override
+            int getGraphType() {
+                return mGraphType;
+            }
+
+            @Override
+            int getVerticalUnitSize() {
+                return mVerticalUnit;
+            }
+
+            @Override
+            int getHorizontalUnitSize() {
+                return mHorizontalUnit;
+            }
+
+            @Override
+            int getHorizontaUnitMargin() {
+                return mHorizontalMargin;
+            }
+
+            @Override
+            float[] getData() {
+                return mProfileData;
+            }
+
+            @Override
+            float getThreshold() {
+                return 16;
+            }
+
+            @Override
+            int getFrameCount() {
+                return mProfileData.length / PROFILE_FRAME_DATA_COUNT;
+            }
+
+            @Override
+            int getElementCount() {
+                return PROFILE_FRAME_DATA_COUNT;
+            }
+
+            @Override
+            int getCurrentFrame() {
+                return mProfileCurrentFrame / PROFILE_FRAME_DATA_COUNT;
+            }
+
+            @Override
+            void setupGraphPaint(Paint paint, int elementIndex) {
+                paint.setColor(PROFILE_DRAW_COLORS[elementIndex]);
+                if (mGraphType == GRAPH_TYPE_LINES) paint.setStrokeWidth(mThresholdStroke);
+            }
+
+            @Override
+            void setupThresholdPaint(Paint paint) {
+                paint.setColor(PROFILE_DRAW_THRESHOLD_COLOR);
+                paint.setStrokeWidth(mThresholdStroke);
+            }
+
+            @Override
+            void setupCurrentFramePaint(Paint paint) {
+                paint.setColor(PROFILE_DRAW_CURRENT_FRAME_COLOR);
+                if (mGraphType == GRAPH_TYPE_LINES) paint.setStrokeWidth(mThresholdStroke);
+            }
+        }
     }
 
     /**
      * Hardware renderer using OpenGL ES 2.0.
      */
     static class Gl20Renderer extends GlRenderer {
-        private static final int PROFILE_DRAW_MARGIN = 0;
-        private static final int PROFILE_DRAW_WIDTH = 3;
-        private static final int[] PROFILE_DRAW_COLORS = { 0xcf3e66cc, 0xcfdc3912, 0xcfe69800 };
-        private static final int PROFILE_DRAW_CURRENT_FRAME_COLOR = 0xcf5faa4d;
-        private static final int PROFILE_DRAW_THRESHOLD_COLOR = 0xff5faa4d;
-        private static final int PROFILE_DRAW_THRESHOLD_STROKE_WIDTH = 2;
-        private static final int PROFILE_DRAW_DP_PER_MS = 7;
-
         private GLES20Canvas mGlCanvas;
 
         private DisplayMetrics mDisplayMetrics;
@@ -1581,101 +1790,149 @@
 
         @Override
         void drawProfileData(View.AttachInfo attachInfo) {
-            if (mProfileEnabled && mProfileVisualizerEnabled) {
-                initProfileDrawData(attachInfo);
+            if (mDebugDataProvider != null) {
+                final GraphDataProvider provider = mDebugDataProvider;
+                initProfileDrawData(attachInfo, provider);
 
-                final int pxPerMs = (int) (PROFILE_DRAW_DP_PER_MS * mDisplayMetrics.density + 0.5f);
-                final int margin = (int) (PROFILE_DRAW_MARGIN * mDisplayMetrics.density + 0.5f);
-                final int width = (int) (PROFILE_DRAW_WIDTH * mDisplayMetrics.density + 0.5f);
+                final int height = provider.getVerticalUnitSize();
+                final int margin = provider.getHorizontaUnitMargin();
+                final int width = provider.getHorizontalUnitSize();
 
                 int x = 0;
                 int count = 0;
                 int current = 0;
 
-                for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) {
-                    if (mProfileData[i] < 0.0f) break;
+                final float[] data = provider.getData();
+                final int elementCount = provider.getElementCount();
+                final int graphType = provider.getGraphType();
+
+                int totalCount = provider.getFrameCount() * elementCount;
+                if (graphType == GraphDataProvider.GRAPH_TYPE_LINES) {
+                    totalCount -= elementCount;
+                }
+
+                for (int i = 0; i < totalCount; i += elementCount) {
+                    if (data[i] < 0.0f) break;
 
                     int index = count * 4;
-                    if (i == mProfileCurrentFrame) current = index;
+                    if (i == provider.getCurrentFrame() * elementCount) current = index;
 
                     x += margin;
                     int x2 = x + width;
 
                     int y2 = mHeight;
-                    int y1 = (int) (y2 - mProfileData[i] * pxPerMs);
+                    int y1 = (int) (y2 - data[i] * height);
 
-                    float[] r = mProfileRects[0];
-                    r[index] = x;
-                    r[index + 1] = y1;
-                    r[index + 2] = x2;
-                    r[index + 3] = y2;
+                    switch (graphType) {
+                        case GraphDataProvider.GRAPH_TYPE_BARS: {
+                            for (int j = 0; j < elementCount; j++) {
+                                //noinspection MismatchedReadAndWriteOfArray
+                                final float[] r = mProfileShapes[j];
+                                r[index] = x;
+                                r[index + 1] = y1;
+                                r[index + 2] = x2;
+                                r[index + 3] = y2;
 
-                    y2 = y1;
-                    y1 = (int) (y2 - mProfileData[i + 1] * pxPerMs);
+                                y2 = y1;
+                                if (j < elementCount - 1) {
+                                    y1 = (int) (y2 - data[i + j + 1] * height);
+                                }
+                            }
+                        } break;
+                        case GraphDataProvider.GRAPH_TYPE_LINES: {
+                            for (int j = 0; j < elementCount; j++) {
+                                //noinspection MismatchedReadAndWriteOfArray
+                                final float[] r = mProfileShapes[j];
+                                r[index] = (x + x2) * 0.5f;
+                                r[index + 1] = index == 0 ? y1 : r[index - 1];
+                                r[index + 2] = r[index] + width;
+                                r[index + 3] = y1;
 
-                    r = mProfileRects[1];
-                    r[index] = x;
-                    r[index + 1] = y1;
-                    r[index + 2] = x2;
-                    r[index + 3] = y2;
+                                y2 = y1;
+                                if (j < elementCount - 1) {
+                                    y1 = (int) (y2 - data[i + j + 1] * height);
+                                }
+                            }
+                        } break;
+                    }
 
-                    y2 = y1;
-                    y1 = (int) (y2 - mProfileData[i + 2] * pxPerMs);
-
-                    r = mProfileRects[2];
-                    r[index] = x;
-                    r[index + 1] = y1;
-                    r[index + 2] = x2;
-                    r[index + 3] = y2;
 
                     x += width;
-
                     count++;
                 }
+
                 x += margin;
 
-                drawGraph(count);
-                drawCurrentFrame(current);
-                drawThreshold(x, pxPerMs);
+                drawGraph(graphType, count);
+                drawCurrentFrame(graphType, current);
+                drawThreshold(x, height);
             }
         }
 
-        private void drawGraph(int count) {
-            for (int i = 0; i < mProfileRects.length; i++) {
-                mProfilePaint.setColor(PROFILE_DRAW_COLORS[i]);
-                mGlCanvas.drawRects(mProfileRects[i], count, mProfilePaint);
-            }
-        }
-
-        private void drawCurrentFrame(int index) {
-            mProfilePaint.setColor(PROFILE_DRAW_CURRENT_FRAME_COLOR);
-            mGlCanvas.drawRect(mProfileRects[2][index], mProfileRects[2][index + 1],
-                    mProfileRects[2][index + 2], mProfileRects[0][index + 3], mProfilePaint);
-        }
-
-        private void drawThreshold(int x, int pxPerMs) {
-            mProfilePaint.setColor(PROFILE_DRAW_THRESHOLD_COLOR);
-            mProfilePaint.setStrokeWidth((int)
-                    (PROFILE_DRAW_THRESHOLD_STROKE_WIDTH * mDisplayMetrics.density + 0.5f));
-            int y = mHeight - 16 * pxPerMs;
-            mGlCanvas.drawLine(0.0f, y, x, y, mProfilePaint);
-            mProfilePaint.setStrokeWidth(1.0f);
-        }
-
-        private void initProfileDrawData(View.AttachInfo attachInfo) {
-            if (mProfileRects == null) {
-                mProfileRects = new float[PROFILE_FRAME_DATA_COUNT][];
-                for (int i = 0; i < mProfileRects.length; i++) {
-                    int count = mProfileData.length / PROFILE_FRAME_DATA_COUNT;
-                    mProfileRects[i] = new float[count * 4];
+        private void drawGraph(int graphType, int count) {
+            for (int i = 0; i < mProfileShapes.length; i++) {
+                mDebugDataProvider.setupGraphPaint(mProfilePaint, i);
+                switch (graphType) {
+                    case GraphDataProvider.GRAPH_TYPE_BARS:
+                        mGlCanvas.drawRects(mProfileShapes[i], count, mProfilePaint);
+                        break;
+                    case GraphDataProvider.GRAPH_TYPE_LINES:
+                        mGlCanvas.drawLines(mProfileShapes[i], 0, count * 4, mProfilePaint);
+                        break;
                 }
+            }
+        }
+
+        private void drawCurrentFrame(int graphType, int index) {
+            if (index >= 0) {
+                mDebugDataProvider.setupCurrentFramePaint(mProfilePaint);
+                switch (graphType) {
+                    case GraphDataProvider.GRAPH_TYPE_BARS:
+                        mGlCanvas.drawRect(mProfileShapes[2][index], mProfileShapes[2][index + 1],
+                                mProfileShapes[2][index + 2], mProfileShapes[0][index + 3],
+                                mProfilePaint);
+                        break;
+                    case GraphDataProvider.GRAPH_TYPE_LINES:
+                        mGlCanvas.drawLine(mProfileShapes[2][index], mProfileShapes[2][index + 1],
+                                mProfileShapes[2][index], mHeight, mProfilePaint);
+                        break;
+                }
+            }
+        }
+
+        private void drawThreshold(int x, int height) {
+            float threshold = mDebugDataProvider.getThreshold();
+            if (threshold > 0.0f) {
+                mDebugDataProvider.setupThresholdPaint(mProfilePaint);
+                int y = (int) (mHeight - threshold * height);
+                mGlCanvas.drawLine(0.0f, y, x, y, mProfilePaint);
+            }
+        }
+
+        private void initProfileDrawData(View.AttachInfo attachInfo, GraphDataProvider provider) {
+            if (mProfileShapes == null) {
+                final int elementCount = provider.getElementCount();
+                final int frameCount = provider.getFrameCount();
+
+                mProfileShapes = new float[elementCount][];
+                for (int i = 0; i < elementCount; i++) {
+                    mProfileShapes[i] = new float[frameCount * 4];
+                }
+
                 mProfilePaint = new Paint();
             }
 
+            mProfilePaint.reset();
+            if (provider.getGraphType() == GraphDataProvider.GRAPH_TYPE_LINES) {
+                mProfilePaint.setAntiAlias(true);
+            }
+
             if (mDisplayMetrics == null) {
                 mDisplayMetrics = new DisplayMetrics();
             }
+
             attachInfo.mDisplay.getMetrics(mDisplayMetrics);
+            provider.prepare(mDisplayMetrics);
         }
 
         @Override
diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java
index d4e27bc..e711b94 100644
--- a/core/java/android/view/VolumePanel.java
+++ b/core/java/android/view/VolumePanel.java
@@ -337,6 +337,11 @@
         listenToRingerMode();
     }
 
+    public void setLayoutDirection(int layoutDirection) {
+        mPanel.setLayoutDirection(layoutDirection);
+        updateStates();
+    }
+
     private void listenToRingerMode() {
         final IntentFilter filter = new IntentFilter();
         filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
@@ -460,6 +465,8 @@
     private void updateSlider(StreamControl sc) {
         sc.seekbarView.setProgress(getStreamVolume(sc.streamType));
         final boolean muted = isMuted(sc.streamType);
+        // Force reloading the image resource
+        sc.icon.setImageDrawable(null);
         sc.icon.setImageResource(muted ? sc.iconMuteRes : sc.iconRes);
         if (sc.streamType == AudioManager.STREAM_RING &&
                 mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE) {
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 441b7b0..1abea2b 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1865,9 +1865,6 @@
     }
 
     private static synchronized WebViewFactoryProvider getFactory() {
-        // For now the main purpose of this function (and the factory abstration) is to keep
-        // us honest and minimize usage of WebViewClassic internals when binding the proxy.
-        checkThread();
         return WebViewFactory.getProvider();
     }
 
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 57e3c8b..79fc51e 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -487,13 +487,15 @@
     }
 
     private class SetRemoteViewsAdapterList extends Action {
-        public SetRemoteViewsAdapterList(int id, ArrayList<RemoteViews> list) {
+        public SetRemoteViewsAdapterList(int id, ArrayList<RemoteViews> list, int viewTypeCount) {
             this.viewId = id;
             this.list = list;
+            this.viewTypeCount = viewTypeCount;
         }
 
         public SetRemoteViewsAdapterList(Parcel parcel) {
             viewId = parcel.readInt();
+            viewTypeCount = parcel.readInt();
             int count = parcel.readInt();
             list = new ArrayList<RemoteViews>();
 
@@ -506,6 +508,7 @@
         public void writeToParcel(Parcel dest, int flags) {
             dest.writeInt(TAG);
             dest.writeInt(viewId);
+            dest.writeInt(viewTypeCount);
 
             if (list == null || list.size() == 0) {
                 dest.writeInt(0);
@@ -540,18 +543,18 @@
             if (target instanceof AbsListView) {
                 AbsListView v = (AbsListView) target;
                 Adapter a = v.getAdapter();
-                if (a instanceof RemoteViewsListAdapter) {
+                if (a instanceof RemoteViewsListAdapter && viewTypeCount <= a.getViewTypeCount()) {
                     ((RemoteViewsListAdapter) a).setViewsList(list);
                 } else {
-                    v.setAdapter(new RemoteViewsListAdapter(v.getContext(), list));
+                    v.setAdapter(new RemoteViewsListAdapter(v.getContext(), list, viewTypeCount));
                 }
             } else if (target instanceof AdapterViewAnimator) {
                 AdapterViewAnimator v = (AdapterViewAnimator) target;
                 Adapter a = v.getAdapter();
-                if (a instanceof RemoteViewsListAdapter) {
+                if (a instanceof RemoteViewsListAdapter && viewTypeCount <= a.getViewTypeCount()) {
                     ((RemoteViewsListAdapter) a).setViewsList(list);
                 } else {
-                    v.setAdapter(new RemoteViewsListAdapter(v.getContext(), list));
+                    v.setAdapter(new RemoteViewsListAdapter(v.getContext(), list, viewTypeCount));
                 }
             }
         }
@@ -560,6 +563,7 @@
             return "SetRemoteViewsAdapterList";
         }
 
+        int viewTypeCount;
         ArrayList<RemoteViews> list;
         public final static int TAG = 15;
     }
@@ -2099,9 +2103,13 @@
      *
      * @param viewId The id of the {@link AdapterView}
      * @param list The list of RemoteViews which will populate the view specified by viewId.
+     * @param viewTypeCount The maximum number of unique layout id's used to construct the list of
+     *      RemoteViews. This count cannot change during the life-cycle of a given widget, so this
+     *      parameter should account for the maximum possible number of types that may appear in the
+     *      See {@link Adapter#getViewTypeCount()}.
      */
-    public void setRemoteAdapter(int viewId, ArrayList<RemoteViews> list) {
-        addAction(new SetRemoteViewsAdapterList(viewId, list));
+    public void setRemoteAdapter(int viewId, ArrayList<RemoteViews> list, int viewTypeCount) {
+        addAction(new SetRemoteViewsAdapterList(viewId, list, viewTypeCount));
     }
 
     /**
diff --git a/core/java/android/widget/RemoteViewsListAdapter.java b/core/java/android/widget/RemoteViewsListAdapter.java
index 9598771..e490458 100644
--- a/core/java/android/widget/RemoteViewsListAdapter.java
+++ b/core/java/android/widget/RemoteViewsListAdapter.java
@@ -30,10 +30,13 @@
     private Context mContext;
     private ArrayList<RemoteViews> mRemoteViewsList;
     private ArrayList<Integer> mViewTypes = new ArrayList<Integer>();
+    private int mViewTypeCount;
 
-    public RemoteViewsListAdapter(Context context, ArrayList<RemoteViews> remoteViews) {
+    public RemoteViewsListAdapter(Context context, ArrayList<RemoteViews> remoteViews,
+            int viewTypeCount) {
         mContext = context;
         mRemoteViewsList = remoteViews;
+        mViewTypeCount = viewTypeCount;
         init();
     }
 
@@ -52,6 +55,11 @@
                 mViewTypes.add(rv.getLayoutId());
             }
         }
+
+        if (mViewTypes.size() > mViewTypeCount || mViewTypeCount < 1) {
+            throw new RuntimeException("Invalid view type count -- view type count must be >= 1" +
+                    "and must be as large as the total number of distinct view types");
+        }
     }
 
     @Override
@@ -77,6 +85,7 @@
     public View getView(int position, View convertView, ViewGroup parent) {
         if (position < getCount()) {
             RemoteViews rv = mRemoteViewsList.get(position);
+            rv.setIsWidgetCollectionChild(true);
             View v;
             if (convertView != null && rv != null &&
                     convertView.getId() == rv.getLayoutId()) {
@@ -102,7 +111,7 @@
     }
 
     public int getViewTypeCount() {
-        return mViewTypes.size();
+        return mViewTypeCount;
     }
 
     @Override
diff --git a/core/java/android/widget/TextClock.java b/core/java/android/widget/TextClock.java
index 290d9b5..5bf21c0 100644
--- a/core/java/android/widget/TextClock.java
+++ b/core/java/android/widget/TextClock.java
@@ -386,6 +386,16 @@
     }
 
     /**
+     * Returns the current format string. Always valid after constructor has
+     * finished, and will never be {@code null}.
+     *
+     * @hide
+     */
+    public CharSequence getFormat() {
+        return mFormat;
+    }
+
+    /**
      * Selects either one of {@link #getFormat12Hour()} or {@link #getFormat24Hour()}
      * depending on whether the user has selected 24-hour format.
      * 
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index 296add3..f5f22b2 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -28,23 +28,21 @@
 int ifc_disable(const char *ifname);
 int ifc_reset_connections(const char *ifname, int reset_mask);
 
-int dhcp_do_request(const char *ifname,
+int dhcp_do_request(const char * const ifname,
                     const char *ipaddr,
                     const char *gateway,
                     uint32_t *prefixLength,
-                    const char *dns1,
-                    const char *dns2,
+                    const char *dns[],
                     const char *server,
                     uint32_t *lease,
                     const char *vendorInfo,
                     const char *domains);
 
-int dhcp_do_request_renew(const char *ifname,
+int dhcp_do_request_renew(const char * const ifname,
                     const char *ipaddr,
                     const char *gateway,
                     uint32_t *prefixLength,
-                    const char *dns1,
-                    const char *dns2,
+                    const char *dns[],
                     const char *server,
                     uint32_t *lease,
                     const char *vendorInfo,
@@ -120,6 +118,9 @@
     char gateway[PROPERTY_VALUE_MAX];
     char    dns1[PROPERTY_VALUE_MAX];
     char    dns2[PROPERTY_VALUE_MAX];
+    char    dns3[PROPERTY_VALUE_MAX];
+    char    dns4[PROPERTY_VALUE_MAX];
+    const char *dns[5] = {dns1, dns2, dns3, dns4, NULL};
     char  server[PROPERTY_VALUE_MAX];
     uint32_t lease;
     char vendorInfo[PROPERTY_VALUE_MAX];
@@ -130,10 +131,10 @@
 
     if (renew) {
         result = ::dhcp_do_request_renew(nameStr, ipaddr, gateway, &prefixLength,
-                dns1, dns2, server, &lease, vendorInfo, domains);
+                dns, server, &lease, vendorInfo, domains);
     } else {
         result = ::dhcp_do_request(nameStr, ipaddr, gateway, &prefixLength,
-                dns1, dns2, server, &lease, vendorInfo, domains);
+                dns, server, &lease, vendorInfo, domains);
     }
     env->ReleaseStringUTFChars(ifname, nameStr);
     if (result == 0) {
@@ -168,6 +169,15 @@
 
         result = env->CallBooleanMethod(dhcpResults,
                 dhcpResultsFieldIds.addDns, env->NewStringUTF(dns2));
+
+        if (result == 0) {
+            result = env->CallBooleanMethod(dhcpResults,
+                    dhcpResultsFieldIds.addDns, env->NewStringUTF(dns3));
+            if (result == 0) {
+                result = env->CallBooleanMethod(dhcpResults,
+                        dhcpResultsFieldIds.addDns, env->NewStringUTF(dns4));
+            }
+        }
     }
 
     if (result == 0) {
diff --git a/core/res/res/drawable-ldrtl-hdpi/ic_audio_notification.png b/core/res/res/drawable-ldrtl-hdpi/ic_audio_notification.png
new file mode 100644
index 0000000..62ef692
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/ic_audio_notification.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/ic_audio_notification_mute.png b/core/res/res/drawable-ldrtl-hdpi/ic_audio_notification_mute.png
new file mode 100644
index 0000000..40123e3
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/ic_audio_notification_mute.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/ic_audio_phone.png b/core/res/res/drawable-ldrtl-hdpi/ic_audio_phone.png
new file mode 100644
index 0000000..968f5ee
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/ic_audio_phone.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/ic_audio_ring_notif.png b/core/res/res/drawable-ldrtl-hdpi/ic_audio_ring_notif.png
new file mode 100644
index 0000000..e5f0dcf
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/ic_audio_ring_notif.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/ic_audio_ring_notif_mute.png b/core/res/res/drawable-ldrtl-hdpi/ic_audio_ring_notif_mute.png
new file mode 100644
index 0000000..371e32f
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/ic_audio_ring_notif_mute.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/ic_audio_ring_notif_vibrate.png b/core/res/res/drawable-ldrtl-hdpi/ic_audio_ring_notif_vibrate.png
new file mode 100644
index 0000000..e05e8f5
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/ic_audio_ring_notif_vibrate.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/ic_audio_vol.png b/core/res/res/drawable-ldrtl-hdpi/ic_audio_vol.png
new file mode 100644
index 0000000..81a8422
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/ic_audio_vol.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/ic_audio_vol_mute.png b/core/res/res/drawable-ldrtl-hdpi/ic_audio_vol_mute.png
new file mode 100644
index 0000000..371e32f
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/ic_audio_vol_mute.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/ic_lock_airplane_mode_off.png b/core/res/res/drawable-ldrtl-hdpi/ic_lock_airplane_mode_off.png
new file mode 100644
index 0000000..7b1eee6
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/ic_lock_airplane_mode_off.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/ic_menu_cc.png b/core/res/res/drawable-ldrtl-hdpi/ic_menu_cc.png
new file mode 100644
index 0000000..aedf9b1
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/ic_menu_cc.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-hdpi/stat_sys_adb.png b/core/res/res/drawable-ldrtl-hdpi/stat_sys_adb.png
new file mode 100644
index 0000000..a7dc29d
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-hdpi/stat_sys_adb.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-ldpi/ic_lock_airplane_mode_off.png b/core/res/res/drawable-ldrtl-ldpi/ic_lock_airplane_mode_off.png
new file mode 100644
index 0000000..c093420
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-ldpi/ic_lock_airplane_mode_off.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-ldpi/ic_menu_cc.png b/core/res/res/drawable-ldrtl-ldpi/ic_menu_cc.png
new file mode 100644
index 0000000..1f21884
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-ldpi/ic_menu_cc.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-ldpi/stat_sys_adb.png b/core/res/res/drawable-ldrtl-ldpi/stat_sys_adb.png
new file mode 100644
index 0000000..d726b7a
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-ldpi/stat_sys_adb.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/ic_audio_notification.png b/core/res/res/drawable-ldrtl-mdpi/ic_audio_notification.png
new file mode 100644
index 0000000..d9843e0
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/ic_audio_notification.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/ic_audio_notification_mute.png b/core/res/res/drawable-ldrtl-mdpi/ic_audio_notification_mute.png
new file mode 100644
index 0000000..2159cab
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/ic_audio_notification_mute.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/ic_audio_phone.png b/core/res/res/drawable-ldrtl-mdpi/ic_audio_phone.png
new file mode 100644
index 0000000..b5af351
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/ic_audio_phone.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/ic_audio_ring_notif.png b/core/res/res/drawable-ldrtl-mdpi/ic_audio_ring_notif.png
new file mode 100644
index 0000000..6341be6
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/ic_audio_ring_notif.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/ic_audio_ring_notif_mute.png b/core/res/res/drawable-ldrtl-mdpi/ic_audio_ring_notif_mute.png
new file mode 100644
index 0000000..b4c3a54
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/ic_audio_ring_notif_mute.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/ic_audio_ring_notif_vibrate.png b/core/res/res/drawable-ldrtl-mdpi/ic_audio_ring_notif_vibrate.png
new file mode 100644
index 0000000..835773e
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/ic_audio_ring_notif_vibrate.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/ic_audio_vol.png b/core/res/res/drawable-ldrtl-mdpi/ic_audio_vol.png
new file mode 100644
index 0000000..947d1f9
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/ic_audio_vol.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/ic_audio_vol_mute.png b/core/res/res/drawable-ldrtl-mdpi/ic_audio_vol_mute.png
new file mode 100644
index 0000000..b4c3a54
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/ic_audio_vol_mute.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/ic_lock_airplane_mode_off.png b/core/res/res/drawable-ldrtl-mdpi/ic_lock_airplane_mode_off.png
new file mode 100644
index 0000000..cba5500
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/ic_lock_airplane_mode_off.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/ic_menu_cc.png b/core/res/res/drawable-ldrtl-mdpi/ic_menu_cc.png
new file mode 100644
index 0000000..0335dec
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/ic_menu_cc.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-mdpi/stat_sys_adb.png b/core/res/res/drawable-ldrtl-mdpi/stat_sys_adb.png
new file mode 100644
index 0000000..265c421
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-mdpi/stat_sys_adb.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/ic_audio_notification.png b/core/res/res/drawable-ldrtl-xhdpi/ic_audio_notification.png
new file mode 100644
index 0000000..43aedea
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/ic_audio_notification.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/ic_audio_notification_mute.png b/core/res/res/drawable-ldrtl-xhdpi/ic_audio_notification_mute.png
new file mode 100644
index 0000000..4e87f77
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/ic_audio_notification_mute.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/ic_audio_phone.png b/core/res/res/drawable-ldrtl-xhdpi/ic_audio_phone.png
new file mode 100644
index 0000000..1066d03
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/ic_audio_phone.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/ic_audio_ring_notif.png b/core/res/res/drawable-ldrtl-xhdpi/ic_audio_ring_notif.png
new file mode 100644
index 0000000..daf9213
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/ic_audio_ring_notif.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/ic_audio_ring_notif_mute.png b/core/res/res/drawable-ldrtl-xhdpi/ic_audio_ring_notif_mute.png
new file mode 100644
index 0000000..83d3bdd
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/ic_audio_ring_notif_mute.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/ic_audio_ring_notif_vibrate.png b/core/res/res/drawable-ldrtl-xhdpi/ic_audio_ring_notif_vibrate.png
new file mode 100644
index 0000000..4de95aa
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/ic_audio_ring_notif_vibrate.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/ic_audio_vol.png b/core/res/res/drawable-ldrtl-xhdpi/ic_audio_vol.png
new file mode 100644
index 0000000..8132926
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/ic_audio_vol.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/ic_audio_vol_mute.png b/core/res/res/drawable-ldrtl-xhdpi/ic_audio_vol_mute.png
new file mode 100644
index 0000000..83d3bdd
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/ic_audio_vol_mute.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/ic_lock_airplane_mode_off.png b/core/res/res/drawable-ldrtl-xhdpi/ic_lock_airplane_mode_off.png
new file mode 100644
index 0000000..6820a23
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/ic_lock_airplane_mode_off.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/ic_menu_cc.png b/core/res/res/drawable-ldrtl-xhdpi/ic_menu_cc.png
new file mode 100644
index 0000000..c8690bd
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/ic_menu_cc.png
Binary files differ
diff --git a/core/res/res/drawable-ldrtl-xhdpi/stat_sys_adb.png b/core/res/res/drawable-ldrtl-xhdpi/stat_sys_adb.png
new file mode 100644
index 0000000..e342556
--- /dev/null
+++ b/core/res/res/drawable-ldrtl-xhdpi/stat_sys_adb.png
Binary files differ
diff --git a/core/tests/coretests/src/android/text/format/DateFormatTest.java b/core/tests/coretests/src/android/text/format/DateFormatTest.java
new file mode 100644
index 0000000..5f36cfd
--- /dev/null
+++ b/core/tests/coretests/src/android/text/format/DateFormatTest.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2012 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.text.format;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import junit.framework.TestCase;
+
+public class DateFormatTest extends TestCase {
+    @SmallTest
+    public void testHasDesignator() throws Exception {
+        assertTrue(DateFormat.hasDesignator("hh:mm:ss", DateFormat.MINUTE));
+        assertTrue(DateFormat.hasDesignator("myyyy", DateFormat.MINUTE));
+        assertTrue(DateFormat.hasDesignator("mmm", DateFormat.MINUTE));
+
+        assertFalse(DateFormat.hasDesignator("hh:MM:ss", DateFormat.MINUTE));
+    }
+
+    @SmallTest
+    public void testHasDesignatorEscaped() throws Exception {
+        assertTrue(DateFormat.hasDesignator("hh:mm 'LOL'", DateFormat.MINUTE));
+
+        assertFalse(DateFormat.hasDesignator("hh:mm 'yyyy'", DateFormat.YEAR));
+    }
+}
diff --git a/docs/downloads/training/BitmapFun.zip b/docs/downloads/training/BitmapFun.zip
index e48bfd3..882ce03 100644
--- a/docs/downloads/training/BitmapFun.zip
+++ b/docs/downloads/training/BitmapFun.zip
Binary files differ
diff --git a/docs/html/distribute/googleplay/promote/badge-files.jd b/docs/html/distribute/googleplay/promote/badge-files.jd
index 92001ed..ede1e21 100644
--- a/docs/html/distribute/googleplay/promote/badge-files.jd
+++ b/docs/html/distribute/googleplay/promote/badge-files.jd
@@ -21,9 +21,9 @@
        <a href="{@docRoot}downloads/brand/en_generic_rgb_wo.ai">English (English)</a><br/>
 
        <a href="{@docRoot}downloads/brand/af_generic_rgb_wo.ai">Afrikaans (Afrikaans)</a><br/>
-
+<!--
        <a href="{@docRoot}downloads/brand/ar_generic_rgb_wo.ai">العربية (Arabic)</a><br/>
-
+-->
        <a href="{@docRoot}downloads/brand/be_generic_rgb_wo.ai">Беларуская (Belarusian)</a><br/>
        
        <a href="{@docRoot}downloads/brand/bg_generic_rgb_wo.ai">български (Bulgarian)</a><br/>
@@ -61,9 +61,9 @@
        <a href="{@docRoot}downloads/brand/de_generic_rgb_wo.ai">Deutsch (German)</a><br/>
 
        <a href="{@docRoot}downloads/brand/el_generic_rgb_wo.ai">Ελληνικά (Greek)</a><br/>
-
+<!--
        <a href="{@docRoot}downloads/brand/iw-he_generic_rgb_wo.ai">עברית (Hebrew)</a><br/>
-
+-->
        <a href="{@docRoot}downloads/brand/hu_generic_rgb_wo.ai">Magyar (Hungarian)</a><br/>
 
        <a href="{@docRoot}downloads/brand/id-in_generic_rgb_wo.ai">Bahasa Indonesia (Indonesian)</a><br/>
diff --git a/docs/html/distribute/googleplay/promote/badges.jd b/docs/html/distribute/googleplay/promote/badges.jd
index 0027f59..081c8f7 100644
--- a/docs/html/distribute/googleplay/promote/badges.jd
+++ b/docs/html/distribute/googleplay/promote/badges.jd
@@ -199,8 +199,10 @@
           onchange="changeBadgeLang()">
     <option title="Afrikaans"
             value="af">Afrikaans</option>
+<!--
     <option title="Arabic"
             value="ar">العربية</option>
+-->
     <option title="Belarusian"
             value="be">Беларуская</option>
     <option title="Bulgarian"
@@ -237,8 +239,10 @@
             value="el">Ελληνικά</option>
     <option title="English"
             value="en" selected="true">English</option>
+<!--
     <option title="Hebrew"
             value="iw-he">עברית</option>
+-->
     <option title="Hungarian"
             value="hu">Magyar</option>
     <option title="Indonesian"
diff --git a/docs/html/training/displaying-bitmaps/cache-bitmap.jd b/docs/html/training/displaying-bitmaps/cache-bitmap.jd
index 2a333cc..417ec5b 100644
--- a/docs/html/training/displaying-bitmaps/cache-bitmap.jd
+++ b/docs/html/training/displaying-bitmaps/cache-bitmap.jd
@@ -101,19 +101,20 @@
 &#64;Override
 protected void onCreate(Bundle savedInstanceState) {
     ...
-    // Get memory class of this device, exceeding this amount will throw an
-    // OutOfMemory exception.
-    final int memClass = ((ActivityManager) context.getSystemService(
-            Context.ACTIVITY_SERVICE)).getMemoryClass();
+    // Get max available VM memory, exceeding this amount will throw an
+    // OutOfMemory exception. Stored in kilobytes as LruCache takes an
+    // int in its constructor.
+    final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
 
     // Use 1/8th of the available memory for this memory cache.
-    final int cacheSize = 1024 * 1024 * memClass / 8;
+    final int cacheSize = maxMemory / 8;
 
     mMemoryCache = new LruCache&lt;String, Bitmap&gt;(cacheSize) {
         &#64;Override
         protected int sizeOf(String key, Bitmap bitmap) {
-            // The cache size will be measured in bytes rather than number of items.
-            return bitmap.getByteCount();
+            // The cache size will be measured in kilobytes rather than
+            // number of items.
+            return bitmap.getByteCount() / 1024;
         }
     };
     ...
diff --git a/docs/html/training/displaying-bitmaps/load-bitmap.jd b/docs/html/training/displaying-bitmaps/load-bitmap.jd
index c0a5709..283f272 100644
--- a/docs/html/training/displaying-bitmaps/load-bitmap.jd
+++ b/docs/html/training/displaying-bitmaps/load-bitmap.jd
@@ -110,12 +110,17 @@
     int inSampleSize = 1;
 
     if (height > reqHeight || width > reqWidth) {
-        if (width > height) {
-            inSampleSize = Math.round((float)height / (float)reqHeight);
-        } else {
-            inSampleSize = Math.round((float)width / (float)reqWidth);
-        }
+
+        // Calculate ratios of height and width to requested height and width
+        final int heightRatio = Math.round((float) height / (float) reqHeight);
+        final int widthRatio = Math.round((float) width / (float) reqWidth);
+
+        // Choose the smallest ratio as inSampleSize value, this will guarantee
+        // a final image with both dimensions larger than or equal to the
+        // requested height and width.
+        inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
     }
+
     return inSampleSize;
 }
 </pre>
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 9aac0e6..ed2a8da 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -5708,17 +5708,19 @@
     private void onRegisterVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) {
         synchronized(mRCStack) {
             // The stack traversal order doesn't matter because there is only one stack entry
-            //  with this RCC ID, and we can stop iterating over the stack entries once the matching
-            //  ID has been found.
-            // FIXME optimize by traversing stack from top to bottom, the matching ID is more likely
-            //  at the top of the stack
-            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
-            while(stackIterator.hasNext()) {
-                RemoteControlStackEntry rcse = stackIterator.next();
-                if (rcse.mRccId == rccId) {
-                    rcse.mRemoteVolumeObs = rvo;
-                    break;
+            //  with this RCC ID, but the matching ID is more likely at the top of the stack, so
+            //  start iterating from the top.
+            try {
+                for (int index = mRCStack.size()-1; index >= 0; index--) {
+                    final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
+                    if (rcse.mRccId == rccId) {
+                        rcse.mRemoteVolumeObs = rvo;
+                        break;
+                    }
                 }
+            } catch (ArrayIndexOutOfBoundsException e) {
+                // not expected to happen, indicates improper concurrent modification
+                Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
             }
         }
     }
@@ -5813,18 +5815,20 @@
         IRemoteVolumeObserver rvo = null;
         synchronized (mRCStack) {
             // The stack traversal order doesn't matter because there is only one stack entry
-            //  with this RCC ID, and we can stop iterating over the stack entries once the matching
-            //  ID has been found.
-            // FIXME optimize by traversing stack from top to bottom, the matching ID is more likely
-            //  at the top of the stack
-            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
-            while(stackIterator.hasNext()) {
-                RemoteControlStackEntry rcse = stackIterator.next();
-                //FIXME OPTIMIZE store this info in mMainRemote so we don't have to iterate?
-                if (rcse.mRccId == rccId) {
-                    rvo = rcse.mRemoteVolumeObs;
-                    break;
+            //  with this RCC ID, but the matching ID is more likely at the top of the stack, so
+            //  start iterating from the top.
+            try {
+                for (int index = mRCStack.size()-1; index >= 0; index--) {
+                    final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
+                    //FIXME OPTIMIZE store this info in mMainRemote so we don't have to iterate?
+                    if (rcse.mRccId == rccId) {
+                        rvo = rcse.mRemoteVolumeObs;
+                        break;
+                    }
                 }
+            } catch (ArrayIndexOutOfBoundsException e) {
+                // not expected to happen, indicates improper concurrent modification
+                Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
             }
         }
         if (rvo != null) {
@@ -5866,18 +5870,20 @@
         IRemoteVolumeObserver rvo = null;
         synchronized (mRCStack) {
             // The stack traversal order doesn't matter because there is only one stack entry
-            //  with this RCC ID, and we can stop iterating over the stack entries once the matching
-            //  ID has been found.
-            // FIXME optimize by traversing stack from top to bottom, the matching ID is more likely
-            //  at the top of the stack
-            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
-            while(stackIterator.hasNext()) {
-                RemoteControlStackEntry rcse = stackIterator.next();
-                if (rcse.mRccId == rccId) {
+            //  with this RCC ID, but the matching ID is more likely at the top of the stack, so
+            //  start iterating from the top.
+            try {
+                for (int index = mRCStack.size()-1; index >= 0; index--) {
+                    final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
                     //FIXME OPTIMIZE store this info in mMainRemote so we don't have to iterate?
-                    rvo = rcse.mRemoteVolumeObs;
-                    break;
+                    if (rcse.mRccId == rccId) {
+                        rvo = rcse.mRemoteVolumeObs;
+                        break;
+                    }
                 }
+            } catch (ArrayIndexOutOfBoundsException e) {
+                // not expected to happen, indicates improper concurrent modification
+                Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
             }
         }
         if (rvo != null) {
@@ -5991,6 +5997,7 @@
                     }
                 }
             }
+            mVolumePanel.setLayoutDirection(config.getLayoutDirection());
         } catch (Exception e) {
             Log.e(TAG, "Error retrieving device orientation: " + e);
         }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index cccce9d..fc0ff55 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -71,7 +71,7 @@
     // database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
     // is properly propagated through your change.  Not doing so will result in a loss of user
     // settings.
-    private static final int DATABASE_VERSION = 95;
+    private static final int DATABASE_VERSION = 96;
 
     private Context mContext;
     private int mUserHandle;
@@ -1488,7 +1488,6 @@
             // Redo this step, since somehow it didn't work the first time for some users
             if (mUserHandle == UserHandle.USER_OWNER) {
                 db.beginTransaction();
-                SQLiteStatement stmt = null;
                 try {
                     // Migrate now-global settings
                     String[] settingsToMove = hashsetToStringArray(SettingsProvider.sSystemGlobalKeys);
@@ -1499,7 +1498,6 @@
                     db.setTransactionSuccessful();
                 } finally {
                     db.endTransaction();
-                    if (stmt != null) stmt.close();
                 }
             }
             upgradeVersion = 94;
@@ -1524,6 +1522,20 @@
             upgradeVersion = 95;
         }
 
+        if (upgradeVersion == 95) {
+            if (mUserHandle == UserHandle.USER_OWNER) {
+                db.beginTransaction();
+                try {
+                    String[] settingsToMove = { Settings.Global.BUGREPORT_IN_POWER_MENU };
+                    moveSettingsToNewTable(db, TABLE_SECURE, TABLE_GLOBAL, settingsToMove, true);
+                    db.setTransactionSuccessful();
+                } finally {
+                    db.endTransaction();
+                }
+            }
+            upgradeVersion = 96;
+        }
+
         // *** Remember to update DATABASE_VERSION above!
 
         if (upgradeVersion != currentVersion) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 3227a34..01596dc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -838,9 +838,14 @@
     }
 
     public void refreshAllStatusBarIcons() {
-        final int count = mStatusIcons.getChildCount();
+        refreshAllIconsForLayout(mStatusIcons);
+        refreshAllIconsForLayout(mNotificationIcons);
+    }
+
+    private void refreshAllIconsForLayout(LinearLayout ll) {
+        final int count = ll.getChildCount();
         for (int n = 0; n < count; n++) {
-            View child = mStatusIcons.getChildAt(n);
+            View child = ll.getChildAt(n);
             if (child instanceof StatusBarIconView) {
                 ((StatusBarIconView) child).updateDrawable();
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
index a6500a2..4ff3862 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
@@ -471,6 +471,8 @@
                     ImageView iv = (ImageView) view.findViewById(R.id.rssi_image);
                     ImageView iov = (ImageView) view.findViewById(R.id.rssi_overlay_image);
                     TextView tv = (TextView) view.findViewById(R.id.rssi_textview);
+                    // Force refresh
+                    iv.setImageDrawable(null);
                     iv.setImageResource(rssiState.signalIconId);
 
                     if (rssiState.dataTypeIconId > 0) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
index 00991c1..1037137 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettingsModel.java
@@ -139,7 +139,7 @@
         public void startObserving() {
             final ContentResolver cr = mContext.getContentResolver();
             cr.registerContentObserver(
-                    Settings.Secure.getUriFor(Settings.Secure.BUGREPORT_IN_POWER_MENU), false, this);
+                    Settings.Global.getUriFor(Settings.Global.BUGREPORT_IN_POWER_MENU), false, this);
         }
     }
 
@@ -544,7 +544,7 @@
         final ContentResolver cr = mContext.getContentResolver();
         boolean enabled = false;
         try {
-            enabled = (Settings.Secure.getInt(cr, Settings.Secure.BUGREPORT_IN_POWER_MENU) != 0);
+            enabled = (Settings.Global.getInt(cr, Settings.Global.BUGREPORT_IN_POWER_MENU) != 0);
         } catch (SettingNotFoundException e) {
         }
 
diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java
index 3dc77d4..761eb2d 100755
--- a/policy/src/com/android/internal/policy/impl/GlobalActions.java
+++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java
@@ -260,8 +260,8 @@
         mItems.add(mAirplaneModeOn);
 
         // next: bug report, if enabled
-        if (Settings.Secure.getInt(mContext.getContentResolver(),
-                Settings.Secure.BUGREPORT_IN_POWER_MENU, 0) != 0) {
+        if (Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.BUGREPORT_IN_POWER_MENU, 0) != 0) {
             mItems.add(
                 new SinglePressAction(com.android.internal.R.drawable.stat_sys_adb,
                         R.string.global_action_bug_report) {
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java
index b4fe0c7..ad5e257 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardWidgetPager.java
@@ -27,6 +27,7 @@
 import android.content.Context;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.text.format.DateFormat;
 import android.util.AttributeSet;
 import android.util.Slog;
 import android.view.Gravity;
@@ -38,10 +39,12 @@
 import android.view.accessibility.AccessibilityManager;
 import android.view.animation.DecelerateInterpolator;
 import android.widget.FrameLayout;
+import android.widget.TextClock;
 
 import com.android.internal.widget.LockPatternUtils;
 
 import java.util.ArrayList;
+import java.util.TimeZone;
 
 public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwitchListener,
         OnLongClickListener, ChallengeLayout.OnBouncerStateChangedListener {
@@ -51,6 +54,9 @@
     protected static float OVERSCROLL_MAX_ROTATION = 30;
     private static final boolean PERFORM_OVERSCROLL_ROTATION = true;
 
+    private static final int FLAG_HAS_LOCAL_HOUR = 0x1;
+    private static final int FLAG_HAS_LOCAL_MINUTE = 0x2;
+
     protected KeyguardViewStateManager mViewStateManager;
     private LockPatternUtils mLockPatternUtils;
 
@@ -131,16 +137,21 @@
 
     @Override
     public void onPageSwitched(View newPage, int newPageIndex) {
-        boolean showingStatusWidget = false;
+        boolean showingClock = false;
         if (newPage instanceof ViewGroup) {
             ViewGroup vg = (ViewGroup) newPage;
             if (vg.getChildAt(0) instanceof KeyguardStatusView) {
-                showingStatusWidget = true;
+                showingClock = true;
             }
         }
 
+        if (newPage != null &&
+                findClockInHierarchy(newPage) == (FLAG_HAS_LOCAL_HOUR | FLAG_HAS_LOCAL_MINUTE)) {
+            showingClock = true;
+        }
+
         // Disable the status bar clock if we're showing the default status widget
-        if (showingStatusWidget) {
+        if (showingClock) {
             setSystemUiVisibility(getSystemUiVisibility() | View.STATUS_BAR_DISABLE_CLOCK);
         } else {
             setSystemUiVisibility(getSystemUiVisibility() & ~View.STATUS_BAR_DISABLE_CLOCK);
@@ -857,4 +868,53 @@
     protected boolean shouldSetTopAlignedPivotForWidget(int childIndex) {
         return !isCameraPage(childIndex) && super.shouldSetTopAlignedPivotForWidget(childIndex);
     }
+
+    /**
+     * Search given {@link View} hierarchy for {@link TextClock} instances that
+     * show various time components. Returns combination of
+     * {@link #FLAG_HAS_LOCAL_HOUR} and {@link #FLAG_HAS_LOCAL_MINUTE}.
+     */
+    private static int findClockInHierarchy(View view) {
+        if (view instanceof TextClock) {
+            return getClockFlags((TextClock) view);
+        } else if (view instanceof ViewGroup) {
+            int flags = 0;
+            final ViewGroup group = (ViewGroup) view;
+            final int size = group.getChildCount();
+            for (int i = 0; i < size; i++) {
+                flags |= findClockInHierarchy(group.getChildAt(i));
+            }
+            return flags;
+        } else {
+            return 0;
+        }
+    }
+
+    /**
+     * Return combination of {@link #FLAG_HAS_LOCAL_HOUR} and
+     * {@link #FLAG_HAS_LOCAL_MINUTE} describing the time represented described
+     * by the given {@link TextClock}.
+     */
+    private static int getClockFlags(TextClock clock) {
+        int flags = 0;
+
+        final String timeZone = clock.getTimeZone();
+        if (timeZone != null && !TimeZone.getDefault().equals(TimeZone.getTimeZone(timeZone))) {
+            // Ignore clocks showing another timezone
+            return 0;
+        }
+
+        final CharSequence format = clock.getFormat();
+        final char hour = clock.is24HourModeEnabled() ? DateFormat.HOUR_OF_DAY
+                : DateFormat.HOUR;
+
+        if (DateFormat.hasDesignator(format, hour)) {
+            flags |= FLAG_HAS_LOCAL_HOUR;
+        }
+        if (DateFormat.hasDesignator(format, DateFormat.MINUTE)) {
+            flags |= FLAG_HAS_LOCAL_MINUTE;
+        }
+
+        return flags;
+    }
 }
diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java
index cbd00f3..fa758a8 100644
--- a/services/java/com/android/server/AlarmManagerService.java
+++ b/services/java/com/android/server/AlarmManagerService.java
@@ -956,16 +956,12 @@
         }
         
         public void scheduleTimeTickEvent() {
-            Calendar calendar = Calendar.getInstance();
             final long currentTime = System.currentTimeMillis();
-            calendar.setTimeInMillis(currentTime);
-            calendar.add(Calendar.MINUTE, 1);
-            calendar.set(Calendar.SECOND, 0);
-            calendar.set(Calendar.MILLISECOND, 0);
+            final long nextTime = 60000 * ((currentTime / 60000) + 1);
 
             // Schedule this event for the amount of time that it would take to get to
             // the top of the next minute.
-            final long tickEventDelay = calendar.getTimeInMillis() - currentTime;
+            final long tickEventDelay = nextTime - currentTime;
 
             set(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + tickEventDelay,
                     mTimeTickSender);
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 81ae101..91ac1de 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -782,9 +782,6 @@
         if (!isSystemIme(imi)) {
             return false;
         }
-        if (imi.isAuxiliaryIme()) {
-            return false;
-        }
         if (imi.getIsDefaultResourceId() != 0) {
             try {
                 Resources res = context.createPackageContext(
@@ -808,9 +805,6 @@
         if (!isSystemIme(imi)) {
             return false;
         }
-        if (imi.isAuxiliaryIme()) {
-            return false;
-        }
         return containsSubtypeOf(imi, ENGLISH_LOCALE.getLanguage());
     }
 
@@ -2864,9 +2858,6 @@
         List<Pair<String, ArrayList<String>>> enabledInputMethodsList = mSettings
                 .getEnabledInputMethodsAndSubtypeListLocked();
 
-        if (DEBUG) {
-            Slog.d(TAG, (enabled ? "Enable " : "Disable ") + id);
-        }
         if (enabled) {
             for (Pair<String, ArrayList<String>> pair: enabledInputMethodsList) {
                 if (pair.first.equals(id)) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index b08fc28..8297988e 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -3914,7 +3914,7 @@
         }
 
         boolean didSomething = killPackageProcessesLocked(name, appId, userId,
-                -100, callerWillRestart, false, doit, evenPersistent,
+                -100, callerWillRestart, true, doit, evenPersistent,
                 name == null ? ("force stop user " + userId) : ("force stop " + name));
         
         TaskRecord lastTask = null;
diff --git a/services/java/com/android/server/power/DisplayPowerController.java b/services/java/com/android/server/power/DisplayPowerController.java
index 724e126..b5010f2 100644
--- a/services/java/com/android/server/power/DisplayPowerController.java
+++ b/services/java/com/android/server/power/DisplayPowerController.java
@@ -344,7 +344,7 @@
      * Creates the display power controller.
      */
     public DisplayPowerController(Looper looper, Context context, Notifier notifier,
-            LightsService lights, TwilightService twilight,
+            LightsService lights, TwilightService twilight, SensorManager sensorManager,
             DisplayManagerService displayManager,
             DisplayBlanker displayBlanker,
             Callbacks callbacks, Handler callbackHandler) {
@@ -356,7 +356,7 @@
 
         mLights = lights;
         mTwilight = twilight;
-        mSensorManager = new SystemSensorManager(mHandler.getLooper());
+        mSensorManager = sensorManager;
         mDisplayManager = displayManager;
 
         final Resources resources = context.getResources();
diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java
index ec82290..2652739 100644
--- a/services/java/com/android/server/power/PowerManagerService.java
+++ b/services/java/com/android/server/power/PowerManagerService.java
@@ -35,6 +35,8 @@
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.database.ContentObserver;
+import android.hardware.SensorManager;
+import android.hardware.SystemSensorManager;
 import android.net.Uri;
 import android.os.BatteryManager;
 import android.os.Binder;
@@ -153,11 +155,6 @@
     // Otherwise the user won't get much screen on time before dimming occurs.
     private static final float MAXIMUM_SCREEN_DIM_RATIO = 0.2f;
 
-    // Upper bound on the battery charge percentage in order to consider turning
-    // the screen on when the device starts charging wirelessly.
-    // See point of use for more details.
-    private static final int WIRELESS_CHARGER_TURN_ON_BATTERY_LEVEL_LIMIT = 95;
-
     // The name of the boot animation service in init.rc.
     private static final String BOOT_ANIMATION_SERVICE = "bootanim";
 
@@ -179,6 +176,7 @@
     private WindowManagerPolicy mPolicy;
     private Notifier mNotifier;
     private DisplayPowerController mDisplayPowerController;
+    private WirelessChargerDetector mWirelessChargerDetector;
     private SettingsObserver mSettingsObserver;
     private DreamManagerService mDreamManager;
     private LightsService.Light mAttentionLight;
@@ -434,6 +432,8 @@
             mScreenBrightnessSettingMaximum = pm.getMaximumScreenBrightnessSetting();
             mScreenBrightnessSettingDefault = pm.getDefaultScreenBrightnessSetting();
 
+            SensorManager sensorManager = new SystemSensorManager(mHandler.getLooper());
+
             // The notifier runs on the system server's main looper so as not to interfere
             // with the animations and other critical functions of the power manager.
             mNotifier = new Notifier(Looper.getMainLooper(), mContext, mBatteryStats,
@@ -441,11 +441,14 @@
                     mScreenOnBlocker, mPolicy);
 
             // The display power controller runs on the power manager service's
-            // own handler thread.
+            // own handler thread to ensure timely operation.
             mDisplayPowerController = new DisplayPowerController(mHandler.getLooper(),
-                    mContext, mNotifier, mLightsService, twilight, mDisplayManagerService,
-                    mDisplayBlanker, mDisplayPowerControllerCallbacks, mHandler);
+                    mContext, mNotifier, mLightsService, twilight, sensorManager,
+                    mDisplayManagerService, mDisplayBlanker,
+                    mDisplayPowerControllerCallbacks, mHandler);
 
+            mWirelessChargerDetector = new WirelessChargerDetector(sensorManager,
+                    createSuspendBlockerLocked("PowerManagerService.WirelessChargerDetector"));
             mSettingsObserver = new SettingsObserver(mHandler);
             mAttentionLight = mLightsService.getLight(LightsService.LIGHT_ID_ATTENTION);
 
@@ -1164,65 +1167,51 @@
             if (wasPowered != mIsPowered || oldPlugType != mPlugType) {
                 mDirty |= DIRTY_IS_POWERED;
 
+                // Update wireless dock detection state.
+                final boolean dockedOnWirelessCharger = mWirelessChargerDetector.update(
+                        mIsPowered, mPlugType, mBatteryLevel);
+
                 // Treat plugging and unplugging the devices as a user activity.
                 // Users find it disconcerting when they plug or unplug the device
                 // and it shuts off right away.
                 // Some devices also wake the device when plugged or unplugged because
                 // they don't have a charging LED.
                 final long now = SystemClock.uptimeMillis();
-                if (shouldWakeUpWhenPluggedOrUnpluggedLocked(wasPowered, oldPlugType)) {
+                if (shouldWakeUpWhenPluggedOrUnpluggedLocked(wasPowered, oldPlugType,
+                        dockedOnWirelessCharger)) {
                     wakeUpNoUpdateLocked(now);
                 }
                 userActivityNoUpdateLocked(
                         now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
 
                 // Tell the notifier whether wireless charging has started so that
-                // it can provide feedback to the user.  Refer to
-                // shouldWakeUpWhenPluggedOrUnpluggedLocked for justification of the
-                // heuristics used here.
-                if (!wasPowered && mIsPowered
-                        && mPlugType == BatteryManager.BATTERY_PLUGGED_WIRELESS
-                        && mBatteryLevel < WIRELESS_CHARGER_TURN_ON_BATTERY_LEVEL_LIMIT) {
+                // it can provide feedback to the user.
+                if (dockedOnWirelessCharger) {
                     mNotifier.onWirelessChargingStarted();
                 }
             }
         }
     }
 
-    private boolean shouldWakeUpWhenPluggedOrUnpluggedLocked(boolean wasPowered, int oldPlugType) {
+    private boolean shouldWakeUpWhenPluggedOrUnpluggedLocked(
+            boolean wasPowered, int oldPlugType, boolean dockedOnWirelessCharger) {
         // Don't wake when powered unless configured to do so.
         if (!mWakeUpWhenPluggedOrUnpluggedConfig) {
             return false;
         }
 
-        // FIXME: Need more accurate detection of wireless chargers.
-        //
-        // We are unable to accurately detect whether the device is resting on the
-        // charger unless it is actually receiving power.  This causes us some grief
-        // because the device might not appear to be plugged into the wireless charger
-        // unless it actually charging.
-        //
-        // To avoid spuriously waking the screen, we apply a special policy to
-        // wireless chargers.
-        //
-        // 1. Don't wake the device when unplugged from wireless charger because
-        //    it might be that the device is still resting on the wireless charger
-        //    but is not receiving power anymore because the battery is full.
-        //
-        // 2. Don't wake the device when plugged into a wireless charger if the
-        //    battery already appears to be mostly full.  This situation may indicate
-        //    that the device was resting on the charger the whole time and simply
-        //    wasn't receiving power because the battery was full.  We can't tell
-        //    whether the device was just placed on the charger or whether it has
-        //    been there for half of the night slowly discharging until it hit
-        //    the point where it needed to start charging again.
+        // Don't wake when undocked from wireless charger.
+        // See WirelessChargerDetector for justification.
         if (wasPowered && !mIsPowered
                 && oldPlugType == BatteryManager.BATTERY_PLUGGED_WIRELESS) {
             return false;
         }
+
+        // Don't wake when docked on wireless charger unless we are certain of it.
+        // See WirelessChargerDetector for justification.
         if (!wasPowered && mIsPowered
                 && mPlugType == BatteryManager.BATTERY_PLUGGED_WIRELESS
-                && mBatteryLevel >= WIRELESS_CHARGER_TURN_ON_BATTERY_LEVEL_LIMIT) {
+                && !dockedOnWirelessCharger) {
             return false;
         }
 
@@ -2209,6 +2198,7 @@
         pw.println("POWER MANAGER (dumpsys power)\n");
 
         final DisplayPowerController dpc;
+        final WirelessChargerDetector wcd;
         synchronized (mLock) {
             pw.println("Power Manager State:");
             pw.println("  mDirty=0x" + Integer.toHexString(mDirty));
@@ -2291,11 +2281,16 @@
             pw.println("Display Blanker: " + mDisplayBlanker);
 
             dpc = mDisplayPowerController;
+            wcd = mWirelessChargerDetector;
         }
 
         if (dpc != null) {
             dpc.dump(pw);
         }
+
+        if (wcd != null) {
+            wcd.dump(pw);
+        }
     }
 
     private SuspendBlocker createSuspendBlockerLocked(String name) {
diff --git a/services/java/com/android/server/power/WirelessChargerDetector.java b/services/java/com/android/server/power/WirelessChargerDetector.java
new file mode 100644
index 0000000..ac6dc3e
--- /dev/null
+++ b/services/java/com/android/server/power/WirelessChargerDetector.java
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2013 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.power;
+
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.os.BatteryManager;
+import android.util.Slog;
+
+import java.io.PrintWriter;
+
+/**
+ * Implements heuristics to detect docking or undocking from a wireless charger.
+ * <p>
+ * Some devices have wireless charging circuits that are unable to detect when the
+ * device is resting on a wireless charger except when the device is actually
+ * receiving power from the charger.  The device may stop receiving power
+ * if the battery is already nearly full or if it is too hot.  As a result, we cannot
+ * always rely on the battery service wireless plug signal to accurately indicate
+ * whether the device has been docked or undocked from a wireless charger.
+ * </p><p>
+ * This is a problem because the power manager typically wakes up the screen and
+ * plays a tone when the device is docked in a wireless charger.  It is important
+ * for the system to suppress spurious docking and undocking signals because they
+ * can be intrusive for the user (especially if they cause a tone to be played
+ * late at night for no apparent reason).
+ * </p><p>
+ * To avoid spurious signals, we apply some special policies to wireless chargers.
+ * </p><p>
+ * 1. Don't wake the device when undocked from the wireless charger because
+ * it might be that the device is still resting on the wireless charger
+ * but is not receiving power anymore because the battery is full.
+ * Ideally we would wake the device if we could be certain that the user had
+ * picked it up from the wireless charger but due to hardware limitations we
+ * must be more conservative.
+ * </p><p>
+ * 2. Don't wake the device when docked on a wireless charger if the
+ * battery already appears to be mostly full.  This situation may indicate
+ * that the device was resting on the charger the whole time and simply
+ * wasn't receiving power because the battery was already full.  We can't tell
+ * whether the device was just placed on the charger or whether it has
+ * been there for half of the night slowly discharging until it reached
+ * the point where it needed to start charging again.  So we suppress docking
+ * signals that occur when the battery level is above a given threshold.
+ * </p><p>
+ * 3. Don't wake the device when docked on a wireless charger if it does
+ * not appear to have moved since it was last undocked because it may
+ * be that the prior undocking signal was spurious.  We use the gravity
+ * sensor to detect this case.
+ * </p>
+ */
+final class WirelessChargerDetector {
+    private static final String TAG = "WirelessChargerDetector";
+    private static final boolean DEBUG = false;
+
+    // Number of nanoseconds per millisecond.
+    private static final long NANOS_PER_MS = 1000000;
+
+    // The minimum amount of time to spend watching the sensor before making
+    // a determination of whether movement occurred.
+    private static final long SETTLE_TIME_NANOS = 500 * NANOS_PER_MS;
+
+    // The minimum number of samples that must be collected.
+    private static final int MIN_SAMPLES = 3;
+
+    // Upper bound on the battery charge percentage in order to consider turning
+    // the screen on when the device starts charging wirelessly.
+    private static final int WIRELESS_CHARGER_TURN_ON_BATTERY_LEVEL_LIMIT = 95;
+
+    // To detect movement, we compute the angle between the gravity vector
+    // at rest and the current gravity vector.  This field specifies the
+    // cosine of the maximum angle variance that we tolerate while at rest.
+    private static final double MOVEMENT_ANGLE_COS_THRESHOLD = Math.cos(5 * Math.PI / 180);
+
+    // Sanity thresholds for the gravity vector.
+    private static final double MIN_GRAVITY = SensorManager.GRAVITY_EARTH - 1.0f;
+    private static final double MAX_GRAVITY = SensorManager.GRAVITY_EARTH + 1.0f;
+
+    private final Object mLock = new Object();
+
+    private final SensorManager mSensorManager;
+    private final SuspendBlocker mSuspendBlocker;
+
+    // The gravity sensor, or null if none.
+    private Sensor mGravitySensor;
+
+    // Previously observed wireless power state.
+    private boolean mPoweredWirelessly;
+
+    // True if the device is thought to be at rest on a wireless charger.
+    private boolean mAtRest;
+
+    // The gravity vector most recently observed while at rest.
+    private float mRestX, mRestY, mRestZ;
+
+    /* These properties are only meaningful while detection is in progress. */
+
+    // True if detection is in progress.
+    // The suspend blocker is held while this is the case.
+    private boolean mDetectionInProgress;
+
+    // True if the rest position should be updated if at rest.
+    // Otherwise, the current rest position is simply checked and cleared if movement
+    // is detected but no new rest position is stored.
+    private boolean mMustUpdateRestPosition;
+
+    // The total number of samples collected.
+    private int mTotalSamples;
+
+    // The number of samples collected that showed evidence of not being at rest.
+    private int mMovingSamples;
+
+    // The time and value of the first sample that was collected.
+    private long mFirstSampleTime;
+    private float mFirstSampleX, mFirstSampleY, mFirstSampleZ;
+
+    public WirelessChargerDetector(SensorManager sensorManager,
+            SuspendBlocker suspendBlocker) {
+        mSensorManager = sensorManager;
+        mSuspendBlocker = suspendBlocker;
+
+        mGravitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY);
+    }
+
+    public void dump(PrintWriter pw) {
+        synchronized (mLock) {
+            pw.println();
+            pw.println("Wireless Charger Detector State:");
+            pw.println("  mGravitySensor=" + mGravitySensor);
+            pw.println("  mPoweredWirelessly=" + mPoweredWirelessly);
+            pw.println("  mAtRest=" + mAtRest);
+            pw.println("  mRestX=" + mRestX + ", mRestY=" + mRestY + ", mRestZ=" + mRestZ);
+            pw.println("  mDetectionInProgress=" + mDetectionInProgress);
+            pw.println("  mMustUpdateRestPosition=" + mMustUpdateRestPosition);
+            pw.println("  mTotalSamples=" + mTotalSamples);
+            pw.println("  mMovingSamples=" + mMovingSamples);
+            pw.println("  mFirstSampleTime=" + mFirstSampleTime);
+            pw.println("  mFirstSampleX=" + mFirstSampleX
+                    + ", mFirstSampleY=" + mFirstSampleY + ", mFirstSampleZ=" + mFirstSampleZ);
+        }
+    }
+
+    /**
+     * Updates the charging state and returns true if docking was detected.
+     *
+     * @param isPowered True if the device is powered.
+     * @param plugType The current plug type.
+     * @param batteryLevel The current battery level.
+     * @return True if the device is determined to have just been docked on a wireless
+     * charger, after suppressing spurious docking or undocking signals.
+     */
+    public boolean update(boolean isPowered, int plugType, int batteryLevel) {
+        synchronized (mLock) {
+            final boolean wasPoweredWirelessly = mPoweredWirelessly;
+
+            if (isPowered && plugType == BatteryManager.BATTERY_PLUGGED_WIRELESS) {
+                // The device is receiving power from the wireless charger.
+                // Update the rest position asynchronously.
+                mPoweredWirelessly = true;
+                mMustUpdateRestPosition = true;
+                startDetectionLocked();
+            } else {
+                // The device may or may not be on the wireless charger depending on whether
+                // the unplug signal that we received was spurious.
+                mPoweredWirelessly = false;
+                if (mAtRest) {
+                    if (plugType != 0 && plugType != BatteryManager.BATTERY_PLUGGED_WIRELESS) {
+                        // The device was plugged into a new non-wireless power source.
+                        // It's safe to assume that it is no longer on the wireless charger.
+                        mMustUpdateRestPosition = false;
+                        clearAtRestLocked();
+                    } else {
+                        // The device may still be on the wireless charger but we don't know.
+                        // Check whether the device has remained at rest on the charger
+                        // so that we will know to ignore the next wireless plug event
+                        // if needed.
+                        startDetectionLocked();
+                    }
+                }
+            }
+
+            // Report that the device has been docked only if the device just started
+            // receiving power wirelessly, has a high enough battery level that we
+            // can be assured that charging was not delayed due to the battery previously
+            // having been full, and the device is not known to already be at rest
+            // on the wireless charger from earlier.
+            return mPoweredWirelessly && !wasPoweredWirelessly
+                    && batteryLevel < WIRELESS_CHARGER_TURN_ON_BATTERY_LEVEL_LIMIT
+                    && !mAtRest;
+        }
+    }
+
+    private void startDetectionLocked() {
+        if (!mDetectionInProgress && mGravitySensor != null) {
+            if (mSensorManager.registerListener(mListener, mGravitySensor,
+                    SensorManager.SENSOR_DELAY_UI)) {
+                mSuspendBlocker.acquire();
+                mDetectionInProgress = true;
+                mTotalSamples = 0;
+                mMovingSamples = 0;
+            }
+        }
+    }
+
+    private void processSample(long timeNanos, float x, float y, float z) {
+        synchronized (mLock) {
+            if (!mDetectionInProgress) {
+                return;
+            }
+
+            mTotalSamples += 1;
+            if (mTotalSamples == 1) {
+                // Save information about the first sample collected.
+                mFirstSampleTime = timeNanos;
+                mFirstSampleX = x;
+                mFirstSampleY = y;
+                mFirstSampleZ = z;
+            } else {
+                // Determine whether movement has occurred relative to the first sample.
+                if (hasMoved(mFirstSampleX, mFirstSampleY, mFirstSampleZ, x, y, z)) {
+                    mMovingSamples += 1;
+                }
+            }
+
+            // Clear the at rest flag if movement has occurred relative to the rest sample.
+            if (mAtRest && hasMoved(mRestX, mRestY, mRestZ, x, y, z)) {
+                if (DEBUG) {
+                    Slog.d(TAG, "No longer at rest: "
+                            + "mRestX=" + mRestX + ", mRestY=" + mRestY + ", mRestZ=" + mRestZ
+                            + ", x=" + x + ", y=" + y + ", z=" + z);
+                }
+                clearAtRestLocked();
+            }
+
+            // Save the result when done.
+            if (timeNanos - mFirstSampleTime >= SETTLE_TIME_NANOS
+                    && mTotalSamples >= MIN_SAMPLES) {
+                mSensorManager.unregisterListener(mListener);
+                if (mMustUpdateRestPosition) {
+                    if (mMovingSamples == 0) {
+                        mAtRest = true;
+                        mRestX = x;
+                        mRestY = y;
+                        mRestZ = z;
+                    } else {
+                        clearAtRestLocked();
+                    }
+                    mMustUpdateRestPosition = false;
+                }
+                mDetectionInProgress = false;
+                mSuspendBlocker.release();
+
+                if (DEBUG) {
+                    Slog.d(TAG, "New state: mAtRest=" + mAtRest
+                            + ", mRestX=" + mRestX + ", mRestY=" + mRestY + ", mRestZ=" + mRestZ
+                            + ", mTotalSamples=" + mTotalSamples
+                            + ", mMovingSamples=" + mMovingSamples);
+                }
+            }
+        }
+    }
+
+    private void clearAtRestLocked() {
+        mAtRest = false;
+        mRestX = 0;
+        mRestY = 0;
+        mRestZ = 0;
+    }
+
+    private static boolean hasMoved(float x1, float y1, float z1,
+            float x2, float y2, float z2) {
+        final double dotProduct = (x1 * x2) + (y1 * y2) + (z1 * z2);
+        final double mag1 = Math.sqrt((x1 * x1) + (y1 * y1) + (z1 * z1));
+        final double mag2 = Math.sqrt((x2 * x2) + (y2 * y2) + (z2 * z2));
+        if (mag1 < MIN_GRAVITY || mag1 > MAX_GRAVITY
+                || mag2 < MIN_GRAVITY || mag2 > MAX_GRAVITY) {
+            if (DEBUG) {
+                Slog.d(TAG, "Weird gravity vector: mag1=" + mag1 + ", mag2=" + mag2);
+            }
+            return true;
+        }
+        final boolean moved = (dotProduct < mag1 * mag2 * MOVEMENT_ANGLE_COS_THRESHOLD);
+        if (DEBUG) {
+            Slog.d(TAG, "Check: moved=" + moved
+                    + ", x1=" + x1 + ", y1=" + y1 + ", z1=" + z1
+                    + ", x2=" + x2 + ", y2=" + y2 + ", z2=" + z2
+                    + ", angle=" + (Math.acos(dotProduct / mag1 / mag2) * 180 / Math.PI)
+                    + ", dotProduct=" + dotProduct
+                    + ", mag1=" + mag1 + ", mag2=" + mag2);
+        }
+        return moved;
+    }
+
+    private final SensorEventListener mListener = new SensorEventListener() {
+        @Override
+        public void onSensorChanged(SensorEvent event) {
+            processSample(event.timestamp, event.values[0], event.values[1], event.values[2]);
+        }
+
+        @Override
+        public void onAccuracyChanged(Sensor sensor, int accuracy) {
+        }
+    };
+}
diff --git a/services/java/com/android/server/wm/DimLayer.java b/services/java/com/android/server/wm/DimLayer.java
index 4c7add9..88efe2e 100644
--- a/services/java/com/android/server/wm/DimLayer.java
+++ b/services/java/com/android/server/wm/DimLayer.java
@@ -84,6 +84,17 @@
         return mTargetAlpha;
     }
 
+    void setLayer(int layer) {
+        if (mLayer != layer) {
+            mLayer = layer;
+            mDimSurface.setLayer(layer);
+        }
+    }
+
+    int getLayer() {
+        return mLayer;
+    }
+
     private void setAlpha(float alpha) {
         if (mAlpha != alpha) {
             if (DEBUG) Slog.v(TAG, "setAlpha alpha=" + alpha);
diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java
index d5144fb..d42221e 100644
--- a/services/java/com/android/server/wm/WindowAnimator.java
+++ b/services/java/com/android/server/wm/WindowAnimator.java
@@ -573,10 +573,13 @@
 
                 final DimLayer dimAnimator = displayAnimator.mDimAnimator;
                 final WindowStateAnimator winAnimator = displayAnimator.mDimWinAnimator;
+                final int dimLayer;
                 final float dimAmount;
                 if (winAnimator == null) {
+                    dimLayer = dimAnimator.getLayer();
                     dimAmount = 0;
                 } else {
+                    dimLayer = winAnimator.mAnimLayer - WindowManagerService.LAYER_OFFSET_DIM;
                     dimAmount = winAnimator.mWin.mAttrs.dimAmount;
                 }
                 final float targetAlpha = dimAnimator.getTargetAlpha();
@@ -590,9 +593,10 @@
                         if (targetAlpha > dimAmount) {
                             duration = getDimBehindFadeDuration(duration);
                         }
-                        dimAnimator.show(winAnimator.mAnimLayer -
-                                WindowManagerService.LAYER_OFFSET_DIM, dimAmount, duration);
+                        dimAnimator.show(dimLayer, dimAmount, duration);
                     }
+                } else if (dimAnimator.getLayer() != dimLayer) {
+                    dimAnimator.setLayer(dimLayer);
                 }
                 if (dimAnimator.isAnimating()) {
                     if (!mService.okToDisplay()) {