Merge "NativeDaemonConnector: Improve bad list IPC diagnostics"
diff --git a/core/java/android/server/BluetoothA2dpService.java b/core/java/android/server/BluetoothA2dpService.java
index 22bb43c..096ad39 100644
--- a/core/java/android/server/BluetoothA2dpService.java
+++ b/core/java/android/server/BluetoothA2dpService.java
@@ -121,10 +121,44 @@
                         handleSinkStateChange(device, state, BluetoothA2dp.STATE_DISCONNECTED);
                     }
                 }
+            } else if (action.equals(AudioManager.VOLUME_CHANGED_ACTION)) {
+                int streamType = intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, -1);
+                if (streamType == AudioManager.STREAM_MUSIC) {
+                    BluetoothDevice sinks[] = getConnectedSinks();
+                    if (sinks.length != 0 && isPhoneDocked(sinks[0])) {
+                        String address = sinks[0].getAddress();
+                        int newVolLevel =
+                          intent.getIntExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, 0);
+                        int oldVolLevel =
+                          intent.getIntExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, 0);
+                        String path = mBluetoothService.getObjectPathFromAddress(address);
+                        if (newVolLevel > oldVolLevel) {
+                            avrcpVolumeUpNative(path);
+                        } else if (newVolLevel < oldVolLevel) {
+                            avrcpVolumeDownNative(path);
+                        }
+                    }
+                }
             }
         }
     };
 
+
+    private boolean isPhoneDocked(BluetoothDevice device) {
+        // This works only because these broadcast intents are "sticky"
+        Intent i = mContext.registerReceiver(null, new IntentFilter(Intent.ACTION_DOCK_EVENT));
+        if (i != null) {
+            int state = i.getIntExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_UNDOCKED);
+            if (state != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
+                BluetoothDevice dockDevice = i.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+                if (dockDevice != null && device.equals(dockDevice)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     public BluetoothA2dpService(Context context, BluetoothService bluetoothService) {
         mContext = context;
 
@@ -145,6 +179,7 @@
         mIntentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
         mIntentFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
         mIntentFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
+        mIntentFilter.addAction(AudioManager.VOLUME_CHANGED_ACTION);
         mContext.registerReceiver(mReceiver, mIntentFilter);
 
         mAudioDevices = new HashMap<BluetoothDevice, Integer>();
@@ -551,4 +586,6 @@
     private synchronized native boolean suspendSinkNative(String path);
     private synchronized native boolean resumeSinkNative(String path);
     private synchronized native Object []getSinkPropertiesNative(String path);
+    private synchronized native boolean avrcpVolumeUpNative(String path);
+    private synchronized native boolean avrcpVolumeDownNative(String path);
 }
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index afc6864..1023036 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -39,6 +39,8 @@
  */
 public abstract class Layout {
     private static final boolean DEBUG = false;
+    private static final ParagraphStyle[] NO_PARA_SPANS =
+        ArrayUtils.emptyArray(ParagraphStyle.class);
 
     /* package */ static final EmojiFactory EMOJI_FACTORY =
         EmojiFactory.newAvailableInstance();
@@ -57,7 +59,7 @@
     private RectF mEmojiRect;
 
     /**
-     * Return how wide a layout would be necessary to display the
+     * Return how wide a layout must be in order to display the
      * specified text with one line per paragraph.
      */
     public static float getDesiredWidth(CharSequence source,
@@ -66,7 +68,7 @@
     }
     
     /**
-     * Return how wide a layout would be necessary to display the
+     * Return how wide a layout must be in order to display the
      * specified text slice with one line per paragraph.
      */
     public static float getDesiredWidth(CharSequence source,
@@ -82,6 +84,7 @@
             if (next < 0)
                 next = end;
 
+            // note, omits trailing paragraph char
             float w = measureText(paint, workPaint,
                                   source, i, next, null, true, null);
 
@@ -97,10 +100,19 @@
     /**
      * Subclasses of Layout use this constructor to set the display text,
      * width, and other standard properties.
+     * @param text the text to render
+     * @param paint the default paint for the layout.  Styles can override
+     * various attributes of the paint.
+     * @param width the wrapping width for the text.
+     * @param align whether to left, right, or center the text.  Styles can
+     * override the alignment.
+     * @param spacingMult factor by which to scale the font size to get the
+     * default line spacing
+     * @param spacingAdd amount to add to the default line spacing
      */
     protected Layout(CharSequence text, TextPaint paint,
                      int width, Alignment align,
-                     float spacingmult, float spacingadd) {
+                     float spacingMult, float spacingAdd) {
         if (width < 0)
             throw new IllegalArgumentException("Layout: " + width + " < 0");
 
@@ -109,8 +121,8 @@
         mWorkPaint = new TextPaint();
         mWidth = width;
         mAlignment = align;
-        mSpacingMult = spacingmult;
-        mSpacingAdd = spacingadd;
+        mSpacingMult = spacingMult;
+        mSpacingAdd = spacingAdd;
         mSpannedText = text instanceof Spanned;
     }
 
@@ -141,10 +153,16 @@
     }
 
     /**
-     * Draw the specified rectangle from this Layout on the specified Canvas,
-     * with the specified path drawn between the background and the text.
+     * Draw this Layout on the specified canvas, with the highlight path drawn
+     * between the background and the text.
+     *
+     * @param c the canvas
+     * @param highlight the path of the highlight or cursor; can be null
+     * @param highlightPaint the paint for the highlight
+     * @param cursorOffsetVertical the amount to temporarily translate the
+     *        canvas while rendering the highlight
      */
-    public void draw(Canvas c, Path highlight, Paint highlightpaint,
+    public void draw(Canvas c, Path highlight, Paint highlightPaint,
                      int cursorOffsetVertical) {
         int dtop, dbottom;
 
@@ -157,13 +175,10 @@
             dbottom = sTempRect.bottom;
         }
 
-        TextPaint paint = mPaint;
 
         int top = 0;
-        // getLineBottom(getLineCount() -1) just calls getLineTop(getLineCount) 
         int bottom = getLineTop(getLineCount());
 
-
         if (dtop > top) {
             top = dtop;
         }
@@ -177,16 +192,19 @@
         int previousLineBottom = getLineTop(first);
         int previousLineEnd = getLineStart(first);
         
+        TextPaint paint = mPaint;
         CharSequence buf = mText;
-
-        ParagraphStyle[] nospans = ArrayUtils.emptyArray(ParagraphStyle.class);
-        ParagraphStyle[] spans = nospans;
-        int spanend = 0;
-        int textLength = 0;
+        int width = mWidth;
         boolean spannedText = mSpannedText;
 
+        ParagraphStyle[] spans = NO_PARA_SPANS;
+        int spanend = 0;
+        int textLength = 0;
+
+        // First, draw LineBackgroundSpans.
+        // LineBackgroundSpans know nothing about the alignment or direction of
+        // the layout or line.  XXX: Should they?
         if (spannedText) {
-            spanend = 0;
             textLength = buf.length();
             for (int i = first; i <= last; i++) {
                 int start = previousLineEnd;
@@ -209,7 +227,7 @@
                 for (int n = 0; n < spans.length; n++) {
                     LineBackgroundSpan back = (LineBackgroundSpan) spans[n];
 
-                    back.drawBackground(c, paint, 0, mWidth,
+                    back.drawBackground(c, paint, 0, width,
                                        ltop, lbaseline, lbottom,
                                        buf, start, end,
                                        i);
@@ -219,7 +237,7 @@
             spanend = 0;
             previousLineBottom = getLineTop(first);
             previousLineEnd = getLineStart(first);
-            spans = nospans;
+            spans = NO_PARA_SPANS;
         } 
 
         // There can be a highlight even without spans if we are drawing
@@ -229,7 +247,7 @@
                 c.translate(0, cursorOffsetVertical);
             }
 
-            c.drawPath(highlight, highlightpaint);
+            c.drawPath(highlight, highlightPaint);
 
             if (cursorOffsetVertical != 0) {
                 c.translate(0, -cursorOffsetVertical);
@@ -238,6 +256,9 @@
 
         Alignment align = mAlignment;
         
+        // Next draw the lines, one at a time.
+        // the baseline is the top of the following line minus the current
+        // line's descent.
         for (int i = first; i <= last; i++) {
             int start = previousLineEnd;
 
@@ -249,21 +270,20 @@
             previousLineBottom = lbottom;
             int lbaseline = lbottom - getLineDescent(i);
 
-            boolean par = false;
+            boolean isFirstParaLine = false;
             if (spannedText) { 
                 if (start == 0 || buf.charAt(start - 1) == '\n') {
-                    par = true;
+                    isFirstParaLine = true;
                 }
+                // New batch of paragraph styles, compute the alignment.
+                // Last alignment style wins.
                 if (start >= spanend) {
-
                     Spanned sp = (Spanned) buf;
-
                     spanend = sp.nextSpanTransition(start, textLength,
                                                     ParagraphStyle.class);
                     spans = sp.getSpans(start, spanend, ParagraphStyle.class);
                     
                     align = mAlignment;
-                    
                     for (int n = spans.length-1; n >= 0; n--) {
                         if (spans[n] instanceof AlignmentSpan) {
                             align = ((AlignmentSpan) spans[n]).getAlignment();
@@ -277,6 +297,8 @@
             int left = 0;
             int right = mWidth;
 
+            // Draw all leading margin spans.  Adjust left or right according
+            // to the paragraph direction of the line.
             if (spannedText) {
                 final int length = spans.length;
                 for (int n = 0; n < length; n++) {
@@ -286,15 +308,15 @@
                         if (dir == DIR_RIGHT_TO_LEFT) {
                             margin.drawLeadingMargin(c, paint, right, dir, ltop,
                                                      lbaseline, lbottom, buf,
-                                                     start, end, par, this);
+                                                     start, end, isFirstParaLine, this);
                                 
-                            right -= margin.getLeadingMargin(par);
+                            right -= margin.getLeadingMargin(isFirstParaLine);
                         } else {
                             margin.drawLeadingMargin(c, paint, left, dir, ltop,
                                                      lbaseline, lbottom, buf,
-                                                     start, end, par, this);
+                                                     start, end, isFirstParaLine, this);
 
-                            boolean useMargin = par;
+                            boolean useMargin = isFirstParaLine;
                             if (margin instanceof LeadingMarginSpan.LeadingMarginSpan2) {
                                 int count = ((LeadingMarginSpan.LeadingMarginSpan2)margin).getLeadingMarginLineCount();
                                 useMargin = count > i;
@@ -305,6 +327,8 @@
                 }
             }
 
+            // Adjust the point at which to start rendering depending on the
+            // alignment of the paragraph.
             int x;
             if (align == Alignment.ALIGN_NORMAL) {
                 if (dir == DIR_LEFT_TO_RIGHT) {
@@ -340,6 +364,7 @@
                     Assert.assertTrue(dir == DIR_LEFT_TO_RIGHT);
                     Assert.assertNotNull(c);
                 }
+                // XXX: assumes there's nothing additional to be done
                 c.drawText(buf, start, end, x, lbaseline, paint);
             } else {
                 drawText(c, buf, start, end, dir, directions,
@@ -382,7 +407,7 @@
 
     /**
      * Increase the width of this layout to the specified width.
-     * Be careful to use this only when you know it is appropriate --
+     * Be careful to use this only when you know it is appropriate&mdash;
      * it does not cause the text to reflow to use the full new width.
      */
     public final void increaseWidthTo(int wid) {
@@ -397,7 +422,7 @@
      * Return the total height of this layout.
      */
     public int getHeight() {
-        return getLineTop(getLineCount());  // same as getLineBottom(getLineCount() - 1);
+        return getLineTop(getLineCount());
     }
 
     /**
@@ -439,33 +464,35 @@
             bounds.left = 0;     // ???
             bounds.top = getLineTop(line);
             bounds.right = mWidth;   // ???
-            bounds.bottom = getLineBottom(line);
+            bounds.bottom = getLineTop(line + 1);
         }
         return getLineBaseline(line);
     }
 
     /**
-     * Return the vertical position of the top of the specified line.
-     * If the specified line is one beyond the last line, returns the
+     * Return the vertical position of the top of the specified line
+     * (0&hellip;getLineCount()).
+     * If the specified line is equal to the line count, returns the
      * bottom of the last line.
      */
     public abstract int getLineTop(int line);
 
     /**
-     * Return the descent of the specified line.
+     * Return the descent of the specified line(0&hellip;getLineCount() - 1).
      */
     public abstract int getLineDescent(int line);
 
     /**
-     * Return the text offset of the beginning of the specified line.
-     * If the specified line is one beyond the last line, returns the
-     * end of the last line.
+     * Return the text offset of the beginning of the specified line (
+     * 0&hellip;getLineCount()). If the specified line is equal to the line
+     * count, returns the length of the text.
      */
     public abstract int getLineStart(int line);
 
     /**
-     * Returns the primary directionality of the paragraph containing
-     * the specified line.
+     * Returns the primary directionality of the paragraph containing the
+     * specified line, either 1 for left-to-right lines, or -1 for right-to-left
+     * lines (see {@link #DIR_LEFT_TO_RIGHT}, {@link #DIR_RIGHT_TO_LEFT}).
      */
     public abstract int getParagraphDirection(int line);
 
@@ -477,9 +504,11 @@
     public abstract boolean getLineContainsTab(int line);
 
     /**
-     * Returns an array of directionalities for the specified line.
+     * Returns the directional run information for the specified line.
      * The array alternates counts of characters in left-to-right
      * and right-to-left segments of the line.
+     *
+     * <p>NOTE: this is inadequate to support bidirectional text, and will change.
      */
     public abstract Directions getLineDirections(int line);
 
@@ -1565,6 +1594,21 @@
         return h;
     }
 
+    /**
+     * Measure width of a run of text on a single line that is known to all be
+     * in the same direction as the paragraph base direction. Returns the width,
+     * and the line metrics in fm if fm is not null.
+     *
+     * @param paint the paint for the text; will not be modified
+     * @param workPaint paint available for modification
+     * @param text text
+     * @param start start of the line
+     * @param end limit of the line
+     * @param fm object to return integer metrics in, can be null
+     * @param hasTabs true if it is known that the line has tabs
+     * @param tabs tab position information
+     * @return the width of the text from start to end
+     */
     /* package */ static float measureText(TextPaint paint,
                                            TextPaint workPaint,
                                            CharSequence text,
@@ -1580,37 +1624,36 @@
 
         int len = end - start;
 
-        int here = 0;
-        float h = 0;
-        int ab = 0, be = 0;
-        int top = 0, bot = 0;
+        int lastPos = 0;
+        float width = 0;
+        int ascent = 0, descent = 0, top = 0, bottom = 0;
 
         if (fm != null) {
             fm.ascent = 0;
             fm.descent = 0;
         }
 
-        for (int i = hasTabs ? 0 : len; i <= len; i++) {
+        for (int pos = hasTabs ? 0 : len; pos <= len; pos++) {
             int codept = 0;
             Bitmap bm = null;
 
-            if (hasTabs && i < len) {
-                codept = buf[i];
+            if (hasTabs && pos < len) {
+                codept = buf[pos];
             }
 
-            if (codept >= 0xD800 && codept <= 0xDFFF && i < len) {
-                codept = Character.codePointAt(buf, i);
+            if (codept >= 0xD800 && codept <= 0xDFFF && pos < len) {
+                codept = Character.codePointAt(buf, pos);
 
                 if (codept >= MIN_EMOJI && codept <= MAX_EMOJI) {
                     bm = EMOJI_FACTORY.getBitmapFromAndroidPua(codept);
                 }
             }
 
-            if (i == len || codept == '\t' || bm != null) {
+            if (pos == len || codept == '\t' || bm != null) {
                 workPaint.baselineShift = 0;
 
-                h += Styled.measureText(paint, workPaint, text,
-                                        start + here, start + i,
+                width += Styled.measureText(paint, workPaint, text,
+                                        start + lastPos, start + pos,
                                         fm);
 
                 if (fm != null) {
@@ -1623,60 +1666,80 @@
                     }
                 }
 
-                if (i != len) {
+                if (pos != len) {
                     if (bm == null) {
-                        h = nextTab(text, start, end, h, tabs);
+                        // no emoji, must have hit a tab
+                        width = nextTab(text, start, end, width, tabs);
                     } else {
+                        // This sets up workPaint with the font on the emoji
+                        // text, so that we can extract the ascent and scale.
+
+                        // We can't use the result of the previous call to
+                        // measureText because the emoji might have its own style.
+                        // We have to initialize workPaint here because if the
+                        // text is unstyled measureText might not use workPaint
+                        // at all.
                         workPaint.set(paint);
                         Styled.measureText(paint, workPaint, text,
-                                           start + i, start + i + 1, null);
+                                           start + pos, start + pos + 1, null);
 
-                        float wid = (float) bm.getWidth() *
+                        width += (float) bm.getWidth() *
                                     -workPaint.ascent() / bm.getHeight();
 
-                        h += wid;
-                        i++;
+                        // Since we had an emoji, we bump past the second half
+                        // of the surrogate pair.
+                        pos++;
                     }
                 }
 
                 if (fm != null) {
-                    if (fm.ascent < ab) {
-                        ab = fm.ascent;
+                    if (fm.ascent < ascent) {
+                        ascent = fm.ascent;
                     }
-                    if (fm.descent > be) {
-                        be = fm.descent;
+                    if (fm.descent > descent) {
+                        descent = fm.descent;
                     }
 
                     if (fm.top < top) {
                         top = fm.top;
                     }
-                    if (fm.bottom > bot) {
-                        bot = fm.bottom;
+                    if (fm.bottom > bottom) {
+                        bottom = fm.bottom;
                     }
 
-                    /*
-                     * No need to take bitmap height into account here,
-                     * since it is scaled to match the text height.
-                     */
+                    // No need to take bitmap height into account here,
+                    // since it is scaled to match the text height.
                 }
 
-                here = i + 1;
+                lastPos = pos + 1;
             }
         }
 
         if (fm != null) {
-            fm.ascent = ab;
-            fm.descent = be;
+            fm.ascent = ascent;
+            fm.descent = descent;
             fm.top = top;
-            fm.bottom = bot;
+            fm.bottom = bottom;
         }
 
         if (hasTabs)
             TextUtils.recycle(buf);
 
-        return h;
+        return width;
     }
 
+    /**
+     * Returns the position of the next tab stop after h on the line.
+     *
+     * @param text the text
+     * @param start start of the line
+     * @param end limit of the line
+     * @param h the current horizontal offset
+     * @param tabs the tabs, can be null.  If it is null, any tabs in effect
+     * on the line will be used.  If there are no tabs, a default offset
+     * will be used to compute the tab stop.
+     * @return the offset of the next tab stop.
+     */
     /* package */ static float nextTab(CharSequence text, int start, int end,
                                        float h, Object[] tabs) {
         float nh = Float.MAX_VALUE;
@@ -1747,6 +1810,16 @@
     public static class Directions {
         private short[] mDirections;
 
+        // The values in mDirections are the offsets from the first character
+        // in the line to the next flip in direction.  Runs at even indices
+        // are left-to-right, the others are right-to-left.  So, for example,
+        // a line that starts with a right-to-left run has 0 at mDirections[0],
+        // since the 'first' (ltr) run is zero length.
+        //
+        // The code currently assumes that each run is adjacent to the previous
+        // one, progressing in the base line direction.  This isn't sufficient
+        // to handle nested runs, for example numeric text in an rtl context
+        // in an ltr paragraph.
         /* package */ Directions(short[] dirs) {
             mDirections = dirs;
         }
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index fbf1261..6c89f92 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -1012,6 +1012,10 @@
         int extra;
 
         if (needMultiply) {
+            // XXX: this looks like it is using the +0.5 and the cast to int
+            // to do rounding, but this I expect this isn't doing the intended
+            // thing when spacingmult < 1.  An intended extra of, say, -1.2
+            // will get 'rounded' to -.7 and then truncated to 0.
             extra = (int) ((below - above) * (spacingmult - 1)
                            + spacingadd + 0.5);
         } else {
diff --git a/core/java/android/text/Styled.java b/core/java/android/text/Styled.java
index 0aa2004..513b2cd 100644
--- a/core/java/android/text/Styled.java
+++ b/core/java/android/text/Styled.java
@@ -13,7 +13,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package android.text;
 
 import android.graphics.Canvas;
@@ -23,27 +22,49 @@
 import android.text.style.ReplacementSpan;
 
 /**
- * This class provides static methods for drawing and measuring styled texts, like
- * {@link android.text.Spanned} object with {@link android.text.style.ReplacementSpan}.
+ * This class provides static methods for drawing and measuring styled text,
+ * like {@link android.text.Spanned} object with
+ * {@link android.text.style.ReplacementSpan}.
+ *
  * @hide
  */
 public class Styled
 {
-    private static float each(Canvas canvas,
+    /**
+     * Draws and/or measures a uniform run of text on a single line. No span of
+     * interest should start or end in the middle of this run (if not
+     * drawing, character spans that don't affect metrics can be ignored).
+     * Neither should the run direction change in the middle of the run.
+     *
+     * <p>The x position is the leading edge of the text. In a right-to-left
+     * paragraph, this will be to the right of the text to be drawn. Paint
+     * should not have an Align value other than LEFT or positioning will get
+     * confused.
+     *
+     * <p>On return, workPaint will reflect the original paint plus any
+     * modifications made by character styles on the run.
+     *
+     * <p>The returned width is signed and will be < 0 if the paragraph
+     * direction is right-to-left.
+     */
+    private static float drawUniformRun(Canvas canvas,
                               Spanned text, int start, int end,
-                              int dir, boolean reverse,
+                              int dir, boolean runIsRtl,
                               float x, int top, int y, int bottom,
                               Paint.FontMetricsInt fmi,
                               TextPaint paint,
                               TextPaint workPaint,
-                              boolean needwid) {
+                              boolean needWidth) {
 
-        boolean havewid = false;
+        boolean haveWidth = false;
         float ret = 0;
         CharacterStyle[] spans = text.getSpans(start, end, CharacterStyle.class);
 
         ReplacementSpan replacement = null;
 
+        // XXX: This shouldn't be modifying paint, only workPaint.
+        // However, the members belonging to TextPaint should have default
+        // values anyway.  Better to ensure this in the Layout constructor.
         paint.bgColor = 0;
         paint.baselineShift = 0;
         workPaint.set(paint);
@@ -65,9 +86,10 @@
             CharSequence tmp;
             int tmpstart, tmpend;
 
-            if (reverse) {
+            if (runIsRtl) {
                 tmp = TextUtils.getReverse(text, start, end);
                 tmpstart = 0;
+                // XXX: assumes getReverse doesn't change the length of the text
                 tmpend = end - start;
             } else {
                 tmp = text;
@@ -86,9 +108,9 @@
                     workPaint.setColor(workPaint.bgColor);
                     workPaint.setStyle(Paint.Style.FILL);
 
-                    if (!havewid) {
+                    if (!haveWidth) {
                         ret = workPaint.measureText(tmp, tmpstart, tmpend);
-                        havewid = true;
+                        haveWidth = true;
                     }
 
                     if (dir == Layout.DIR_RIGHT_TO_LEFT)
@@ -101,18 +123,18 @@
                 }
 
                 if (dir == Layout.DIR_RIGHT_TO_LEFT) {
-                    if (!havewid) {
+                    if (!haveWidth) {
                         ret = workPaint.measureText(tmp, tmpstart, tmpend);
-                        havewid = true;
+                        haveWidth = true;
                     }
 
                     canvas.drawText(tmp, tmpstart, tmpend,
                                     x - ret, y + workPaint.baselineShift, workPaint);
                 } else {
-                    if (needwid) {
-                        if (!havewid) {
+                    if (needWidth) {
+                        if (!haveWidth) {
                             ret = workPaint.measureText(tmp, tmpstart, tmpend);
-                            havewid = true;
+                            haveWidth = true;
                         }
                     }
 
@@ -120,9 +142,9 @@
                                     x, y + workPaint.baselineShift, workPaint);
                 }
             } else {
-                if (needwid && !havewid) {
+                if (needWidth && !haveWidth) {
                     ret = workPaint.measureText(tmp, tmpstart, tmpend);
-                    havewid = true;
+                    haveWidth = true;
                 }
             }
         } else {
@@ -145,25 +167,28 @@
     }
 
     /**
-     * Return the advance widths for the characters in the string.
-     * See also {@link android.graphics.Paint#getTextWidths(CharSequence, int, int, float[])}.
+     * Returns the advance widths for a uniform left-to-right run of text with
+     * no style changes in the middle of the run. If any style is replacement
+     * text, the first character will get the width of the replacement and the
+     * remaining characters will get a width of 0.
      * 
-     * @param paint The main {@link TextPaint} object.
-     * @param workPaint The {@link TextPaint} object used for temporal workspace.
-     * @param text The text to measure
-     * @param start The index of the first char to to measure
-     * @param end The end of the text slice to measure
-     * @param widths Array to receive the advance widths of the characters.
-     * Must be at least a large as (end - start).
-     * @param fmi FontMetrics information. Can be null.
-     * @return The actual number of widths returned. 
+     * @param paint the paint, will not be modified
+     * @param workPaint a paint to modify; on return will reflect the original
+     *        paint plus the effect of all spans on the run
+     * @param text the text
+     * @param start the start of the run
+     * @param end the limit of the run
+     * @param widths array to receive the advance widths of the characters. Must
+     *        be at least a large as (end - start).
+     * @param fmi FontMetrics information; can be null
+     * @return the actual number of widths returned
      */
     public static int getTextWidths(TextPaint paint,
                                     TextPaint workPaint,
                                     Spanned text, int start, int end,
                                     float[] widths, Paint.FontMetricsInt fmi) {
-        //  Keep workPaint as is so that developers reuse the workspace.
-        MetricAffectingSpan[] spans = text.getSpans(start, end, MetricAffectingSpan.class);
+        MetricAffectingSpan[] spans =
+            text.getSpans(start, end, MetricAffectingSpan.class);
 
 		ReplacementSpan replacement = null;
         workPaint.set(paint);
@@ -186,7 +211,6 @@
 
             if (end > start) {
                 widths[0] = wid;
-
                 for (int i = start + 1; i < end; i++)
                     widths[i - start] = 0;
             }
@@ -194,19 +218,42 @@
         return end - start;
     }
 
-    private static float foreach(Canvas canvas,
+    /**
+     * Renders and/or measures a directional run of text on a single line.
+     * Unlike {@link #drawUniformRun}, this can render runs that cross style
+     * boundaries.  Returns the signed advance width, if requested.
+     *
+     * <p>The x position is the leading edge of the text. In a right-to-left
+     * paragraph, this will be to the right of the text to be drawn. Paint
+     * should not have an Align value other than LEFT or positioning will get
+     * confused.
+     *
+     * <p>This optimizes for unstyled text and so workPaint might not be
+     * modified by this call.
+     *
+     * <p>The returned advance width will be < 0 if the paragraph
+     * direction is right-to-left.
+     */
+    private static float drawDirectionalRun(Canvas canvas,
                                  CharSequence text, int start, int end,
-                                 int dir, boolean reverse,
+                                 int dir, boolean runIsRtl,
                                  float x, int top, int y, int bottom,
                                  Paint.FontMetricsInt fmi,
                                  TextPaint paint,
                                  TextPaint workPaint,
                                  boolean needWidth) {
-        if (! (text instanceof Spanned)) {
+
+        // XXX: It looks like all calls to this API match dir and runIsRtl, so
+        // having both parameters is redundant and confusing.
+
+        // fast path for unstyled text
+        if (!(text instanceof Spanned)) {
             float ret = 0;
 
-            if (reverse) {
+            if (runIsRtl) {
                 CharSequence tmp = TextUtils.getReverse(text, start, end);
+                // XXX: this assumes getReverse doesn't tweak the length of
+                // the text
                 int tmpend = end - start;
 
                 if (canvas != null || needWidth)
@@ -227,15 +274,14 @@
                 paint.getFontMetricsInt(fmi);
             }
 
-            return ret * dir;   //Layout.DIR_RIGHT_TO_LEFT == -1
+            return ret * dir;   // Layout.DIR_RIGHT_TO_LEFT == -1
         }
         
         float ox = x;
-        int asc = 0, desc = 0;
-        int ftop = 0, fbot = 0;
+        int minAscent = 0, maxDescent = 0, minTop = 0, maxBottom = 0;
 
         Spanned sp = (Spanned) text;
-        Class division;
+        Class<?> division;
 
         if (canvas == null)
             division = MetricAffectingSpan.class;
@@ -246,20 +292,23 @@
         for (int i = start; i < end; i = next) {
             next = sp.nextSpanTransition(i, end, division);
 
-            x += each(canvas, sp, i, next, dir, reverse,
+            // XXX: if dir and runIsRtl were not the same, this would draw
+            // spans in the wrong order, but no one appears to call it this
+            // way.
+            x += drawUniformRun(canvas, sp, i, next, dir, runIsRtl,
                   x, top, y, bottom, fmi, paint, workPaint,
                   needWidth || next != end);
 
             if (fmi != null) {
-                if (fmi.ascent < asc)
-                    asc = fmi.ascent;
-                if (fmi.descent > desc)
-                    desc = fmi.descent;
+                if (fmi.ascent < minAscent)
+                    minAscent = fmi.ascent;
+                if (fmi.descent > maxDescent)
+                    maxDescent = fmi.descent;
 
-                if (fmi.top < ftop)
-                    ftop = fmi.top;
-                if (fmi.bottom > fbot)
-                    fbot = fmi.bottom;
+                if (fmi.top < minTop)
+                    minTop = fmi.top;
+                if (fmi.bottom > maxBottom)
+                    maxBottom = fmi.bottom;
             }
         }
 
@@ -267,71 +316,78 @@
             if (start == end) {
                 paint.getFontMetricsInt(fmi);
             } else {
-                fmi.ascent = asc;
-                fmi.descent = desc;
-                fmi.top = ftop;
-                fmi.bottom = fbot;
+                fmi.ascent = minAscent;
+                fmi.descent = maxDescent;
+                fmi.top = minTop;
+                fmi.bottom = maxBottom;
             }
         }
 
         return x - ox;
     }
 
-
+    /**
+     * Draws a unidirectional run of text on a single line, and optionally
+     * returns the signed advance.  Unlike drawDirectionalRun, the paragraph
+     * direction and run direction can be different.
+     */
     /* package */ static float drawText(Canvas canvas,
                                        CharSequence text, int start, int end,
-                                       int direction, boolean reverse,
+                                       int dir, boolean runIsRtl,
                                        float x, int top, int y, int bottom,
                                        TextPaint paint,
                                        TextPaint workPaint,
                                        boolean needWidth) {
-        if ((direction == Layout.DIR_RIGHT_TO_LEFT && !reverse) ||
-            (reverse && direction == Layout.DIR_LEFT_TO_RIGHT)) {
-            float ch = foreach(null, text, start, end, Layout.DIR_LEFT_TO_RIGHT,
-                         false, 0, 0, 0, 0, null, paint, workPaint,
-                         true);
+        // XXX this logic is (dir == DIR_LEFT_TO_RIGHT) == runIsRtl
+        if ((dir == Layout.DIR_RIGHT_TO_LEFT && !runIsRtl) ||
+            (runIsRtl && dir == Layout.DIR_LEFT_TO_RIGHT)) {
+            // TODO: this needs the real direction
+            float ch = drawDirectionalRun(null, text, start, end,
+                    Layout.DIR_LEFT_TO_RIGHT, false, 0, 0, 0, 0, null, paint,
+                    workPaint, true);
 
-            ch *= direction;  // DIR_RIGHT_TO_LEFT == -1
-            foreach(canvas, text, start, end, -direction,
-                    reverse, x + ch, top, y, bottom, null, paint,
+            ch *= dir;  // DIR_RIGHT_TO_LEFT == -1
+            drawDirectionalRun(canvas, text, start, end, -dir,
+                    runIsRtl, x + ch, top, y, bottom, null, paint,
                     workPaint, true);
 
             return ch;
         }
 
-        return foreach(canvas, text, start, end, direction, reverse,
+        return drawDirectionalRun(canvas, text, start, end, dir, runIsRtl,
                        x, top, y, bottom, null, paint, workPaint,
                        needWidth);
     }
     
     /**
-     * Draw the specified range of text, specified by start/end, with its origin at (x,y),
-     * in the specified Paint. The origin is interpreted based on the Align setting in the
-     * Paint.
-     *  
-     * This method considers style information in the text
-     * (e.g. Even when text is an instance of {@link android.text.Spanned}, this method
-     * correctly draws the text).
-     * See also
-     * {@link android.graphics.Canvas#drawText(CharSequence, int, int, float, float, Paint)}
-     * and
-     * {@link android.graphics.Canvas#drawRect(float, float, float, float, Paint)}.
+     * Draws a run of text on a single line, with its
+     * origin at (x,y), in the specified Paint. The origin is interpreted based
+     * on the Align setting in the Paint.
+     *
+     * This method considers style information in the text (e.g. even when text
+     * is an instance of {@link android.text.Spanned}, this method correctly
+     * draws the text). See also
+     * {@link android.graphics.Canvas#drawText(CharSequence, int, int, float,
+     * float, Paint)} and
+     * {@link android.graphics.Canvas#drawRect(float, float, float, float,
+     * Paint)}.
      * 
-     * @param canvas The target canvas.
+     * @param canvas The target canvas
      * @param text The text to be drawn
      * @param start The index of the first character in text to draw
      * @param end (end - 1) is the index of the last character in text to draw
      * @param direction The direction of the text. This must be
-     * {@link android.text.Layout#DIR_LEFT_TO_RIGHT} or
-     * {@link android.text.Layout#DIR_RIGHT_TO_LEFT}.
+     *        {@link android.text.Layout#DIR_LEFT_TO_RIGHT} or
+     *        {@link android.text.Layout#DIR_RIGHT_TO_LEFT}.
      * @param x The x-coordinate of origin for where to draw the text
      * @param top The top side of the rectangle to be drawn
      * @param y The y-coordinate of origin for where to draw the text
      * @param bottom The bottom side of the rectangle to be drawn
      * @param paint The main {@link TextPaint} object.
-     * @param workPaint The {@link TextPaint} object used for temporal workspace.
-     * @param needWidth If true, this method returns the width of drawn text.
-     * @return Width of the drawn text if needWidth is true.
+     * @param workPaint The {@link TextPaint} object used for temporal
+     *        workspace.
+     * @param needWidth If true, this method returns the width of drawn text
+     * @return Width of the drawn text if needWidth is true
      */
     public static float drawText(Canvas canvas,
                                  CharSequence text, int start, int end,
@@ -341,34 +397,37 @@
                                  TextPaint workPaint,
                                  boolean needWidth) {
         // For safety.
-        direction = direction >= 0 ? Layout.DIR_LEFT_TO_RIGHT : Layout.DIR_RIGHT_TO_LEFT;
-        /*
-         * Hided "reverse" parameter since it is meaningless for external developers.
-         * Kept workPaint as is so that developers reuse the workspace.
-         */
+        direction = direction >= 0 ? Layout.DIR_LEFT_TO_RIGHT
+                : Layout.DIR_RIGHT_TO_LEFT;
+
+        // Hide runIsRtl parameter since it is meaningless for external
+        // developers.
+        // XXX: the runIsRtl probably ought to be the same as direction, then
+        // this could draw rtl text.
         return drawText(canvas, text, start, end, direction, false,
                         x, top, y, bottom, paint, workPaint, needWidth);
     }
     
     /**
-     * Return the width of the text, considering style information in the text
-     * (e.g. Even when text is an instance of {@link android.text.Spanned}, this method
-     * correctly mesures the width of the text).
+     * Returns the width of a run of left-to-right text on a single line,
+     * considering style information in the text (e.g. even when text is an
+     * instance of {@link android.text.Spanned}, this method correctly measures
+     * the width of the text).
      * 
-     * @param paint The main {@link TextPaint} object.
-     * @param workPaint The {@link TextPaint} object used for temporal workspace.
-     * @param text The text to measure
-     * @param start The index of the first character to start measuring
+     * @param paint the main {@link TextPaint} object; will not be modified
+     * @param workPaint the {@link TextPaint} object available for modification;
+     *        will not necessarily be used
+     * @param text the text to measure
+     * @param start the index of the first character to start measuring
      * @param end 1 beyond the index of the last character to measure
-     * @param fmi FontMetrics information. Can be null
-     * @return The width of the text 
+     * @param fmi FontMetrics information; can be null
+     * @return The width of the text
      */
     public static float measureText(TextPaint paint,
                                     TextPaint workPaint,
                                     CharSequence text, int start, int end,
                                     Paint.FontMetricsInt fmi) {
-        // Keep workPaint as is so that developers reuse the workspace.
-        return foreach(null, text, start, end,
+        return drawDirectionalRun(null, text, start, end,
                        Layout.DIR_LEFT_TO_RIGHT, false,
                        0, 0, 0, 0, fmi, paint, workPaint, true);
     }
diff --git a/core/java/android/text/style/LeadingMarginSpan.java b/core/java/android/text/style/LeadingMarginSpan.java
index cb55329..6635ddb8 100644
--- a/core/java/android/text/style/LeadingMarginSpan.java
+++ b/core/java/android/text/style/LeadingMarginSpan.java
@@ -23,10 +23,44 @@
 import android.text.ParcelableSpan;
 import android.text.TextUtils;
 
+/**
+ * A paragraph style affecting the leading margin. There can be multiple leading
+ * margin spans on a single paragraph; they will be rendered in order, each
+ * adding its margin to the ones before it. The leading margin is on the right
+ * for lines in a right-to-left paragraph.
+ */
 public interface LeadingMarginSpan
 extends ParagraphStyle
 {
+    /**
+     * Returns the amount by which to adjust the leading margin. Positive values
+     * move away from the leading edge of the paragraph, negative values move
+     * towards it.
+     * 
+     * @param first true if the request is for the first line of a paragraph,
+     * false for subsequent lines
+     * @return the offset for the margin.
+     */
     public int getLeadingMargin(boolean first);
+
+    /**
+     * Renders the leading margin.  This is called before the margin has been
+     * adjusted by the value returned by {@link getLeadingMargin(boolean)}.
+     * 
+     * @param c the canvas
+     * @param p the paint. The this should be left unchanged on exit.
+     * @param x the current position of the margin
+     * @param dir the base direction of the paragraph; if negative, the margin
+     * is to the right of the text, otherwise it is to the left.
+     * @param top the top of the line
+     * @param baseline the baseline of the line
+     * @param bottom the bottom of the line
+     * @param text the text
+     * @param start the start of the line
+     * @param end the end of the line
+     * @param first true if this is the first line of its paragraph
+     * @param layout the layout containing this line
+     */
     public void drawLeadingMargin(Canvas c, Paint p,
                                   int x, int dir,
                                   int top, int baseline, int bottom,
@@ -38,14 +72,29 @@
         public int getLeadingMarginLineCount();
     };
 
+    /**
+     * The standard implementation of LeadingMarginSpan, which adjusts the
+     * margin but does not do any rendering.
+     */
     public static class Standard implements LeadingMarginSpan, ParcelableSpan {
         private final int mFirst, mRest;
         
+        /**
+         * Constructor taking separate indents for the first and subsequent
+         * lines.
+         * 
+         * @param first the indent for the first line of the paragraph
+         * @param rest the indent for the remaining lines of the paragraph
+         */
         public Standard(int first, int rest) {
             mFirst = first;
             mRest = rest;
         }
 
+        /**
+         * Constructor taking an indent for all lines.
+         * @param every the indent of each line
+         */
         public Standard(int every) {
             this(every, every);
         }
diff --git a/core/java/android/text/style/TabStopSpan.java b/core/java/android/text/style/TabStopSpan.java
index e5b7644..0566428 100644
--- a/core/java/android/text/style/TabStopSpan.java
+++ b/core/java/android/text/style/TabStopSpan.java
@@ -16,14 +16,31 @@
 
 package android.text.style;
 
+/**
+ * Represents a single tab stop on a line.
+ */
 public interface TabStopSpan
 extends ParagraphStyle
 {
+    /**
+     * Returns the offset of the tab stop from the leading margin of the
+     * line.
+     * @return the offset
+     */
     public int getTabStop();
 
+    /**
+     * The default implementation of TabStopSpan.
+     */
     public static class Standard
     implements TabStopSpan
     {
+        /**
+         * Constructor.
+         *
+         * @param where the offset of the tab stop from the leading margin of
+         *        the line
+         */
         public Standard(int where) {
             mTab = where;
         }
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index ae6c666..acb64aa 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -3105,11 +3105,26 @@
         }
     }
 
+    private static class Metrics {
+        int mScrollX;
+        int mScrollY;
+        int mWidth;
+        int mHeight;
+        float mScale;
+    }
+
+    private Metrics getViewMetrics() {
+        Metrics metrics = new Metrics();
+        metrics.mScrollX = mScrollX;
+        metrics.mScrollY = computeVerticalScrollOffset();
+        metrics.mWidth = getWidth();
+        metrics.mHeight = getHeight() - getVisibleTitleHeight();
+        metrics.mScale = mActualScale;
+        return metrics;
+    }
+
     private void drawLayers(Canvas canvas) {
         if (mRootLayer != 0) {
-            int scrollY = computeVerticalScrollOffset();
-            int viewHeight = getHeight() - getVisibleTitleHeight();
-
             // Currently for each draw we compute the animation values;
             // We may in the future decide to do that independently.
             if (nativeEvaluateLayersAnimations(mRootLayer)) {
@@ -3119,9 +3134,7 @@
             }
 
             // We can now draw the layers.
-            nativeDrawLayers(mRootLayer, mScrollX, scrollY,
-                             getWidth(), viewHeight,
-                             mActualScale, canvas);
+            nativeDrawLayers(mRootLayer, canvas);
         }
     }
 
@@ -3209,7 +3222,15 @@
 
         mWebViewCore.drawContentPicture(canvas, color,
                 (animateZoom || mPreviewZoomOnly), animateScroll);
-
+        boolean cursorIsInLayer = nativeCursorIsInLayer();
+        if (drawCursorRing && !cursorIsInLayer) {
+            nativeDrawCursorRing(canvas);
+        }
+        // When the FindDialog is up, only draw the matches if we are not in
+        // the process of scrolling them into view.
+        if (mFindIsUp && !animateScroll) {
+            nativeDrawMatches(canvas);
+        }
         drawLayers(canvas);
 
         if (mNativeClass == 0) return;
@@ -3232,12 +3253,7 @@
                             LONG_PRESS_TIMEOUT);
                 }
             }
-            nativeDrawCursorRing(canvas);
-        }
-        // When the FindDialog is up, only draw the matches if we are not in
-        // the process of scrolling them into view.
-        if (mFindIsUp && !animateScroll) {
-            nativeDrawMatches(canvas);
+            if (cursorIsInLayer) nativeDrawCursorRing(canvas);
         }
         if (mFocusSizeChanged) {
             mFocusSizeChanged = false;
@@ -5952,6 +5968,7 @@
                 case SET_ROOT_LAYER_MSG_ID: {
                     int oldLayer = mRootLayer;
                     mRootLayer = msg.arg1;
+                    nativeSetRootLayer(mRootLayer);
                     if (oldLayer > 0) {
                         nativeDestroyLayer(oldLayer);
                     }
@@ -6715,6 +6732,7 @@
     /* package */ native boolean nativeCursorMatchesFocus();
     private native boolean  nativeCursorIntersects(Rect visibleRect);
     private native boolean  nativeCursorIsAnchor();
+    private native boolean  nativeCursorIsInLayer();
     private native boolean  nativeCursorIsTextInput();
     private native Point    nativeCursorPosition();
     private native String   nativeCursorText();
@@ -6728,10 +6746,7 @@
     private native void     nativeDrawCursorRing(Canvas content);
     private native void     nativeDestroyLayer(int layer);
     private native boolean  nativeEvaluateLayersAnimations(int layer);
-    private native void     nativeDrawLayers(int layer,
-                                             int scrollX, int scrollY,
-                                             int width, int height,
-                                             float scale, Canvas canvas);
+    private native void     nativeDrawLayers(int layer, Canvas canvas);
     private native void     nativeDrawMatches(Canvas canvas);
     private native void     nativeDrawSelectionPointer(Canvas content,
             float scale, int x, int y, boolean extendSelection);
@@ -6781,6 +6796,7 @@
     private native void     nativeSetFindIsUp();
     private native void     nativeSetFollowedLink(boolean followed);
     private native void     nativeSetHeightCanMeasure(boolean measure);
+    private native void     nativeSetRootLayer(int layer);
     private native int      nativeTextGeneration();
     // Never call this version except by updateCachedTextfield(String) -
     // we always want to pass in our generation number.
diff --git a/core/jni/android_server_BluetoothA2dpService.cpp b/core/jni/android_server_BluetoothA2dpService.cpp
index 4eab4b3..cf53a06 100644
--- a/core/jni/android_server_BluetoothA2dpService.cpp
+++ b/core/jni/android_server_BluetoothA2dpService.cpp
@@ -200,6 +200,38 @@
     return JNI_FALSE;
 }
 
+static jboolean avrcpVolumeUpNative(JNIEnv *env, jobject object,
+                                     jstring path) {
+#ifdef HAVE_BLUETOOTH
+    LOGV(__FUNCTION__);
+    if (nat) {
+        const char *c_path = env->GetStringUTFChars(path, NULL);
+        bool ret = dbus_func_args_async(env, nat->conn, -1, NULL, NULL, nat,
+                           c_path, "org.bluez.Control", "VolumeUp",
+                           DBUS_TYPE_INVALID);
+        env->ReleaseStringUTFChars(path, c_path);
+        return ret ? JNI_TRUE : JNI_FALSE;
+    }
+#endif
+    return JNI_FALSE;
+}
+
+static jboolean avrcpVolumeDownNative(JNIEnv *env, jobject object,
+                                     jstring path) {
+#ifdef HAVE_BLUETOOTH
+    LOGV(__FUNCTION__);
+    if (nat) {
+        const char *c_path = env->GetStringUTFChars(path, NULL);
+        bool ret = dbus_func_args_async(env, nat->conn, -1, NULL, NULL, nat,
+                           c_path, "org.bluez.Control", "VolumeDown",
+                           DBUS_TYPE_INVALID);
+        env->ReleaseStringUTFChars(path, c_path);
+        return ret ? JNI_TRUE : JNI_FALSE;
+    }
+#endif
+    return JNI_FALSE;
+}
+
 #ifdef HAVE_BLUETOOTH
 DBusHandlerResult a2dp_event_filter(DBusMessage *msg, JNIEnv *env) {
     DBusError err;
@@ -267,6 +299,7 @@
     free(user);
 }
 
+
 #endif
 
 
@@ -281,6 +314,8 @@
     {"resumeSinkNative", "(Ljava/lang/String;)Z", (void*)resumeSinkNative},
     {"getSinkPropertiesNative", "(Ljava/lang/String;)[Ljava/lang/Object;",
                                     (void *)getSinkPropertiesNative},
+    {"avrcpVolumeUpNative", "(Ljava/lang/String;)Z", (void*)avrcpVolumeUpNative},
+    {"avrcpVolumeDownNative", "(Ljava/lang/String;)Z", (void*)avrcpVolumeDownNative},
 };
 
 int register_android_server_BluetoothA2dpService(JNIEnv *env) {
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 70c27c2..32c5c23 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -87,10 +87,11 @@
 
     /**
      * @hide Broadcast intent when the volume for a particular stream type changes.
-     * Includes the stream and the new volume
+     * Includes the stream, the new volume and previous volumes
      *
      * @see #EXTRA_VOLUME_STREAM_TYPE
      * @see #EXTRA_VOLUME_STREAM_VALUE
+     * @see #EXTRA_PREV_VOLUME_STREAM_VALUE
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String VOLUME_CHANGED_ACTION = "android.media.VOLUME_CHANGED_ACTION";
@@ -126,6 +127,12 @@
     public static final String EXTRA_VOLUME_STREAM_VALUE =
         "android.media.EXTRA_VOLUME_STREAM_VALUE";
 
+    /**
+     * @hide The previous volume associated with the stream for the volume changed intent.
+     */
+    public static final String EXTRA_PREV_VOLUME_STREAM_VALUE =
+        "android.media.EXTRA_PREV_VOLUME_STREAM_VALUE";
+
     /** The audio stream for phone calls */
     public static final int STREAM_VOICE_CALL = AudioSystem.STREAM_VOICE_CALL;
     /** The audio stream for system sounds */
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index bde8a47..668917e 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -403,30 +403,34 @@
         // UI
         mVolumePanel.postVolumeChanged(streamType, flags);
         // Broadcast Intent
-        sendVolumeUpdate(streamType);
+        sendVolumeUpdate(streamType, oldIndex, streamState.mIndex);
     }
 
     /** @see AudioManager#setStreamVolume(int, int, int) */
     public void setStreamVolume(int streamType, int index, int flags) {
         ensureValidStreamType(streamType);
+
+        final int oldIndex = mStreamStates[STREAM_VOLUME_ALIAS[streamType]].mIndex;
+
         index = rescaleIndex(index * 10, streamType, STREAM_VOLUME_ALIAS[streamType]);
         setStreamVolumeInt(STREAM_VOLUME_ALIAS[streamType], index, false, true);
 
         // UI, etc.
         mVolumePanel.postVolumeChanged(streamType, flags);
         // Broadcast Intent
-        sendVolumeUpdate(streamType);
+        sendVolumeUpdate(streamType, oldIndex, index);
     }
 
-    private void sendVolumeUpdate(int streamType) {
+    private void sendVolumeUpdate(int streamType, int oldIndex, int index) {
+        oldIndex = (oldIndex + 5) / 10;
+        index = (index + 5) / 10;
+
         Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
         intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType);
-        intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, getStreamVolume(streamType));
+        intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
+        intent.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
 
-        // Currently, sending the intent only when the stream is BLUETOOTH_SCO
-        if (streamType == AudioSystem.STREAM_BLUETOOTH_SCO) {
-            mContext.sendBroadcast(intent);
-        }
+        mContext.sendBroadcast(intent);
     }
 
     /**
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index 2a65b0d..2012b3d 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -296,7 +296,7 @@
 
 void SoundPool::autoPause()
 {
-    LOGV("pauseAll()");
+    LOGV("autoPause()");
     Mutex::Autolock lock(&mLock);
     for (int i = 0; i < mMaxChannels; ++i) {
         SoundChannel* channel = &mChannelPool[i];
@@ -316,7 +316,7 @@
 
 void SoundPool::autoResume()
 {
-    LOGV("pauseAll()");
+    LOGV("autoResume()");
     Mutex::Autolock lock(&mLock);
     for (int i = 0; i < mMaxChannels; ++i) {
         SoundChannel* channel = &mChannelPool[i];
diff --git a/telephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java b/telephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java
index 9caae3d..41e527c 100644
--- a/telephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java
+++ b/telephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java
@@ -409,7 +409,7 @@
                     case USIM_EFIAP_TAG:
                     case USIM_EFSNE_TAG:
                         data = tlv.getData();
-                        int efid = data[0] << 8 | data[1];
+                        int efid = ((data[0] & 0xFF) << 8) | (data[1] & 0xFF);
                         val.put(tag, efid);
                         break;
                 }