Merge "Add a little input event consistency verifier."
diff --git a/Android.mk b/Android.mk
index aae10dc..3902971 100644
--- a/Android.mk
+++ b/Android.mk
@@ -370,6 +370,7 @@
     -since ./frameworks/base/api/9.xml 9 \
     -since ./frameworks/base/api/10.xml 10 \
     -since ./frameworks/base/api/11.xml 11 \
+    -since ./frameworks/base/api/12.xml 12 \
 		-werror -hide 113 \
 		-overview $(LOCAL_PATH)/core/java/overview.html
 
diff --git a/api/current.xml b/api/current.xml
index ded1d1b..58aa1fd 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -15703,6 +15703,17 @@
  visibility="public"
 >
 </field>
+<field name="Theme_Holo_Light_NoActionBar"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16974064"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="Theme_Holo_Light_Panel"
  type="int"
  transient="false"
@@ -259887,7 +259898,7 @@
  synchronized="false"
  static="false"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 <parameter name="appWidgetId" type="int">
@@ -259897,6 +259908,21 @@
 <parameter name="intent" type="android.content.Intent">
 </parameter>
 </method>
+<method name="setRemoteAdapter"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="viewId" type="int">
+</parameter>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+</method>
 <method name="setScrollPosition"
  return="void"
  abstract="false"
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 31119d7..72fa07c 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -57,11 +57,30 @@
      */
     public boolean userSetLocale;
 
+    /** Constant for {@link #screenLayout}: bits that encode the size. */
     public static final int SCREENLAYOUT_SIZE_MASK = 0x0f;
+    /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK}
+     * value indicating that no size has been set. */
     public static final int SCREENLAYOUT_SIZE_UNDEFINED = 0x00;
+    /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK}
+     * value indicating the screen is at least approximately 320x426 dp units.
+     * See <a href="{@docRoot}guide/practices/screens_support.html">Supporting
+     * Multiple Screens</a> for more information. */
     public static final int SCREENLAYOUT_SIZE_SMALL = 0x01;
+    /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK}
+     * value indicating the screen is at least approximately 320x470 dp units.
+     * See <a href="{@docRoot}guide/practices/screens_support.html">Supporting
+     * Multiple Screens</a> for more information. */
     public static final int SCREENLAYOUT_SIZE_NORMAL = 0x02;
+    /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK}
+     * value indicating the screen is at least approximately 480x640 dp units.
+     * See <a href="{@docRoot}guide/practices/screens_support.html">Supporting
+     * Multiple Screens</a> for more information. */
     public static final int SCREENLAYOUT_SIZE_LARGE = 0x03;
+    /** Constant for {@link #screenLayout}: a {@link #SCREENLAYOUT_SIZE_MASK}
+     * value indicating the screen is at least approximately 720x960 dp units.
+     * See <a href="{@docRoot}guide/practices/screens_support.html">Supporting
+     * Multiple Screens</a> for more information.*/
     public static final int SCREENLAYOUT_SIZE_XLARGE = 0x04;
     
     public static final int SCREENLAYOUT_LONG_MASK = 0x30;
@@ -88,6 +107,9 @@
      * <p>The {@link #SCREENLAYOUT_LONG_MASK} defines whether the screen
      * is wider/taller than normal.  They may be one of
      * {@link #SCREENLAYOUT_LONG_NO} or {@link #SCREENLAYOUT_LONG_YES}.
+     * 
+     * <p>See <a href="{@docRoot}guide/practices/screens_support.html">Supporting
+     * Multiple Screens</a> for more information.
      */
     public int screenLayout;
     
diff --git a/core/java/android/hardware/usb/UsbAccessory.java b/core/java/android/hardware/usb/UsbAccessory.java
index 5e9ead0..c8ea825 100644
--- a/core/java/android/hardware/usb/UsbAccessory.java
+++ b/core/java/android/hardware/usb/UsbAccessory.java
@@ -22,7 +22,21 @@
 import android.util.Log;
 
 /**
- * A class representing a USB accessory.
+ * A class representing a USB accessory, which is an external hardware component
+ * that communicates with an android application over USB.
+ * The accessory is the USB host and android the device side of the USB connection.
+ *
+ * <p>When the accessory connects, it reports its manufacturer and model names,
+ * the version of the accessory, and a user visible description of the accessory to the device.
+ * The manufacturer, model and version strings are used by the USB Manager to choose
+ * an appropriate application for the accessory.
+ * The accessory may optionally provide a unique serial number
+ * and a URL to for the accessory's website to the device as well.
+ *
+ * <p>An instance of this class is sent to the application via the
+ * {@link UsbManager#ACTION_USB_ACCESSORY_ATTACHED} Intent.
+ * The application can then call {@link UsbManager#openAccessory} to open a file descriptor
+ * for reading and writing data to and from the accessory.
  */
 public class UsbAccessory implements Parcelable {
 
@@ -63,7 +77,7 @@
     }
 
     /**
-     * Returns the manufacturer of the accessory.
+     * Returns the manufacturer name of the accessory.
      *
      * @return the accessory manufacturer
      */
diff --git a/core/java/android/hardware/usb/UsbConstants.java b/core/java/android/hardware/usb/UsbConstants.java
index 6626c9f..0e8d47c 100644
--- a/core/java/android/hardware/usb/UsbConstants.java
+++ b/core/java/android/hardware/usb/UsbConstants.java
@@ -22,45 +22,162 @@
  */
 public final class UsbConstants {
 
+    /**
+     * Bitmask used for extracting the {@link UsbEndpoint} direction from its address field.
+     * @see UsbEndpoint#getAddress
+     * @see UsbEndpoint#getDirection
+     * @see #USB_DIR_OUT
+     * @see #USB_DIR_IN
+     *
+     */
     public static final int USB_ENDPOINT_DIR_MASK = 0x80;
+    /**
+     * Used to signify direction of data for a {@link UsbEndpoint} is OUT (host to device)
+     * @see UsbEndpoint#getDirection
+     */
     public static final int USB_DIR_OUT = 0;
+    /**
+     * Used to signify direction of data for a {@link UsbEndpoint} is IN (device to host)
+     * @see UsbEndpoint#getDirection
+     */
     public static final int USB_DIR_IN = 0x80;
 
-    public static final int USB_TYPE_MASK = (0x03 << 5);
-    public static final int USB_TYPE_STANDARD = (0x00 << 5);
-    public static final int USB_TYPE_CLASS = (0x01 << 5);
-    public static final int USB_TYPE_VENDOR = (0x02 << 5);
-    public static final int USB_TYPE_RESERVED = (0x03 << 5);
-
+    /**
+     * Bitmask used for extracting the {@link UsbEndpoint} number its address field.
+     * @see UsbEndpoint#getAddress
+     * @see UsbEndpoint#getEndpointNumber
+     */
     public static final int USB_ENDPOINT_NUMBER_MASK = 0x0f;
 
-    // flags for endpoint attributes
+    /**
+     * Bitmask used for extracting the {@link UsbEndpoint} type from its address field.
+     * @see UsbEndpoint#getAddress
+     * @see UsbEndpoint#getType
+     * @see #USB_ENDPOINT_XFER_CONTROL
+     * @see #USB_ENDPOINT_XFER_ISOC
+     * @see #USB_ENDPOINT_XFER_BULK
+     * @see #USB_ENDPOINT_XFER_INT
+     */
     public static final int USB_ENDPOINT_XFERTYPE_MASK = 0x03;
+    /**
+     * Control endpoint type (endpoint zero)
+     * @see UsbEndpoint#getType
+     */
     public static final int USB_ENDPOINT_XFER_CONTROL = 0;
+    /**
+     * Isochronous endpoint type (currently not supported)
+     * @see UsbEndpoint#getType
+     */
     public static final int USB_ENDPOINT_XFER_ISOC = 1;
+    /**
+     * Bulk endpoint type
+     * @see UsbEndpoint#getType
+     */
     public static final int USB_ENDPOINT_XFER_BULK = 2;
+    /**
+     * Interrupt endpoint type
+     * @see UsbEndpoint#getType
+     */
     public static final int USB_ENDPOINT_XFER_INT = 3;
 
-    // USB classes
+
+    /**
+     * Bitmask used for encoding the request type for a control request on endpoint zero.
+     */
+    public static final int USB_TYPE_MASK = (0x03 << 5);
+    /**
+     * Used to specify that an endpoint zero control request is a standard request.
+     */
+    public static final int USB_TYPE_STANDARD = (0x00 << 5);
+    /**
+     * Used to specify that an endpoint zero control request is a class specific request.
+     */
+    public static final int USB_TYPE_CLASS = (0x01 << 5);
+    /**
+     * Used to specify that an endpoint zero control request is a vendor specific request.
+     */
+    public static final int USB_TYPE_VENDOR = (0x02 << 5);
+    /**
+     * Reserved endpoint zero control request type (currently unused).
+     */
+    public static final int USB_TYPE_RESERVED = (0x03 << 5);
+
+
+    /**
+     * USB class indicating that the class is determined on a per-interface basis.
+     */
     public static final int USB_CLASS_PER_INTERFACE = 0;
+    /**
+     * USB class for audio devices.
+     */
     public static final int USB_CLASS_AUDIO = 1;
+    /**
+     * USB class for communication devices.
+     */
     public static final int USB_CLASS_COMM = 2;
+    /**
+     * USB class for human interface devices (for example, mice and keyboards).
+     */
     public static final int USB_CLASS_HID = 3;
+    /**
+     * USB class for physical devices.
+     */
     public static final int USB_CLASS_PHYSICA = 5;
+    /**
+     * USB class for still image devices (digital cameras).
+     */
     public static final int USB_CLASS_STILL_IMAGE = 6;
+    /**
+     * USB class for printers.
+     */
     public static final int USB_CLASS_PRINTER = 7;
+    /**
+     * USB class for mass storage devices.
+     */
     public static final int USB_CLASS_MASS_STORAGE = 8;
+    /**
+     * USB class for USB hubs.
+     */
     public static final int USB_CLASS_HUB = 9;
+    /**
+     * USB class for CDC devices (communications device class).
+     */
     public static final int USB_CLASS_CDC_DATA = 0x0a;
+    /**
+     * USB class for content smart card devices.
+     */
     public static final int USB_CLASS_CSCID = 0x0b;
+    /**
+     * USB class for content security devices.
+     */
     public static final int USB_CLASS_CONTENT_SEC = 0x0d;
+    /**
+     * USB class for video devices.
+     */
     public static final int USB_CLASS_VIDEO = 0x0e;
+    /**
+     * USB class for wireless controller devices.
+     */
     public static final int USB_CLASS_WIRELESS_CONTROLLER = 0xe0;
+    /**
+     * USB class for wireless miscellaneous devices.
+     */
     public static final int USB_CLASS_MISC = 0xef;
+    /**
+     * Application specific USB class.
+     */
     public static final int USB_CLASS_APP_SPEC = 0xfe;
+    /**
+     * Vendor specific USB class.
+     */
     public static final int USB_CLASS_VENDOR_SPEC = 0xff;
 
-    // USB subclasses
-    public static final int USB_INTERFACE_SUBCLASS_BOOT = 1;    // for HID class
+    /**
+     * Boot subclass for HID devices.
+     */
+    public static final int USB_INTERFACE_SUBCLASS_BOOT = 1;
+    /**
+     * Vendor specific USB subclass.
+     */
     public static final int USB_SUBCLASS_VENDOR_SPEC = 0xff;
-}
\ No newline at end of file
+}
diff --git a/core/java/android/hardware/usb/UsbDevice.java b/core/java/android/hardware/usb/UsbDevice.java
index 9e536a7..af3f7f0 100644
--- a/core/java/android/hardware/usb/UsbDevice.java
+++ b/core/java/android/hardware/usb/UsbDevice.java
@@ -24,7 +24,16 @@
 import java.io.FileDescriptor;
 
 /**
- * A class representing a USB device.
+ * This class represents a USB device attached to the android device with the android device
+ * acting as the USB host.
+ * Each device contains one or more {@link UsbInterface}s, each of which contains a number of
+ * {@link UsbEndpoint}s (the channels via which data is transmitted over USB).
+ *
+ * <p> This class contains information (along with {@link UsbInterface} and {@link UsbEndpoint})
+ * that describes the capabilities of the USB device.
+ * To communicate with the device, you open a {@link UsbDeviceConnection} for the device
+ * and use {@link UsbRequest} to send and receive data on an endpoint.
+ * {@link UsbDeviceConnection#controlTransfer} is used for control requests on endpoint zero.
  */
 public class UsbDevice implements Parcelable {
 
@@ -96,8 +105,7 @@
 
     /**
      * Returns the devices's class field.
-     * Some useful constants for USB device classes can be found in
-     * {@link android.hardware.usb.UsbConstants}
+     * Some useful constants for USB device classes can be found in {@link UsbConstants}.
      *
      * @return the devices's class
      */
@@ -115,7 +123,7 @@
     }
 
     /**
-     * Returns the device's subclass field.
+     * Returns the device's protocol field.
      *
      * @return the device's protocol
      */
@@ -124,7 +132,7 @@
     }
 
     /**
-     * Returns the number of {@link android.hardware.usb.UsbInterface}s this device contains.
+     * Returns the number of {@link UsbInterface}s this device contains.
      *
      * @return the number of interfaces
      */
@@ -133,7 +141,7 @@
     }
 
     /**
-     * Returns the {@link android.hardware.usb.UsbInterface} at the given index.
+     * Returns the {@link UsbInterface} at the given index.
      *
      * @return the interface
      */
diff --git a/core/java/android/hardware/usb/UsbDeviceConnection.java b/core/java/android/hardware/usb/UsbDeviceConnection.java
index 876287c..a153c0b 100644
--- a/core/java/android/hardware/usb/UsbDeviceConnection.java
+++ b/core/java/android/hardware/usb/UsbDeviceConnection.java
@@ -23,7 +23,8 @@
 
 
 /**
- * A class representing a USB device.
+ * This class is used for sending and receiving data and control messages to a USB device.
+ * Instances of this class are created by {@link UsbManager#openDevice}.
  */
 public class UsbDeviceConnection {
 
@@ -48,15 +49,20 @@
 
     /**
      * Releases all system resources related to the device.
+     * Once the object is closed it cannot be used again.
+     * The client must call {@link UsbManager#openDevice} again
+     * to retrieve a new instance to reestablish communication with the device.
      */
     public void close() {
         native_close();
     }
 
     /**
-     * Returns an integer file descriptor for the device, or
+     * Returns the native file descriptor for the device, or
      * -1 if the device is not opened.
-     * This is intended for passing to native code to access the device
+     * This is intended for passing to native code to access the device.
+     *
+     * @return the native file descriptor
      */
     public int getFileDescriptor() {
         return native_get_fd();
@@ -65,7 +71,8 @@
     /**
      * Claims exclusive access to a {@link android.hardware.usb.UsbInterface}.
      * This must be done before sending or receiving data on any
-     * {@link android.hardware.usb.UsbEndpoint}s belonging to the interface
+     * {@link android.hardware.usb.UsbEndpoint}s belonging to the interface.
+     *
      * @param intf the interface to claim
      * @param force true to disconnect kernel driver if necessary
      * @return true if the interface was successfully claimed
diff --git a/core/java/android/hardware/usb/UsbEndpoint.java b/core/java/android/hardware/usb/UsbEndpoint.java
index bc2c2c1..753a447 100644
--- a/core/java/android/hardware/usb/UsbEndpoint.java
+++ b/core/java/android/hardware/usb/UsbEndpoint.java
@@ -21,7 +21,14 @@
 import android.os.Parcelable;
 
 /**
- * A class representing an endpoint on a {@link android.hardware.usb.UsbInterface}.
+ * A class representing an endpoint on a {@link UsbInterface}.
+ * Endpoints are the channels for sending and receiving data over USB.
+ * Typically bulk endpoints are used for sending non-trivial amounts of data.
+ * Interrupt endpoints are used for sending small amounts of data, typically events,
+ * separately from the main data streams.
+ * The endpoint zero is a special endpoint for control messages sent from the host
+ * to device.
+ * Isochronous endpoints are currently unsupported.
  */
 public class UsbEndpoint implements Parcelable {
 
@@ -43,6 +50,10 @@
 
     /**
      * Returns the endpoint's address field.
+     * The address is a bitfield containing both the endpoint number
+     * as well as the data direction of the endpoint.
+     * the endpoint number and direction can also be accessed via
+     * {@link #getEndpointNumber} and {@link #getDirection}.
      *
      * @return the endpoint's address
      */
@@ -61,10 +72,12 @@
 
     /**
      * Returns the endpoint's direction.
-     * Returns {@link android.hardware.usb.UsbConstants#USB_DIR_OUT}
+     * Returns {@link UsbConstants#USB_DIR_OUT}
      * if the direction is host to device, and
-     * {@link android.hardware.usb.UsbConstants#USB_DIR_IN} if the
+     * {@link UsbConstants#USB_DIR_IN} if the
      * direction is device to host.
+     * @see {@link UsbConstants#USB_DIR_IN}
+     * @see {@link UsbConstants#USB_DIR_OUT}
      *
      * @return the endpoint's direction
      */
@@ -85,10 +98,10 @@
      * Returns the endpoint's type.
      * Possible results are:
      * <ul>
-     * <li>{@link android.hardware.usb.UsbConstants#USB_ENDPOINT_XFER_CONTROL} (endpoint zero)
-     * <li>{@link android.hardware.usb.UsbConstants#USB_ENDPOINT_XFER_ISOC} (isochronous endpoint)
-     * <li>{@link android.hardware.usb.UsbConstants#USB_ENDPOINT_XFER_BULK} (bulk endpoint)
-     * <li>{@link android.hardware.usb.UsbConstants#USB_ENDPOINT_XFER_INT} (interrupt endpoint)
+     * <li>{@link UsbConstants#USB_ENDPOINT_XFER_CONTROL} (endpoint zero)
+     * <li>{@link UsbConstants#USB_ENDPOINT_XFER_ISOC} (isochronous endpoint)
+     * <li>{@link UsbConstants#USB_ENDPOINT_XFER_BULK} (bulk endpoint)
+     * <li>{@link UsbConstants#USB_ENDPOINT_XFER_INT} (interrupt endpoint)
      * </ul>
      *
      * @return the endpoint's type
diff --git a/core/java/android/hardware/usb/UsbInterface.java b/core/java/android/hardware/usb/UsbInterface.java
index 2b4c7c0..3b51063 100644
--- a/core/java/android/hardware/usb/UsbInterface.java
+++ b/core/java/android/hardware/usb/UsbInterface.java
@@ -21,7 +21,11 @@
 import android.os.Parcelable;
 
 /**
- * A class representing an interface on a {@link android.hardware.usb.UsbDevice}.
+ * A class representing an interface on a {@link UsbDevice}.
+ * USB devices can have one or more interfaces, each one providing a different
+ * piece of functionality, separate from the other interfaces.
+ * An interface will have one or more {@link UsbEndpoint}s, which are the
+ * channels by which the host transfers data with the device.
  */
 public class UsbInterface implements Parcelable {
 
@@ -46,6 +50,7 @@
 
     /**
      * Returns the interface's ID field.
+     * This is an integer that uniquely identifies the interface on the device.
      *
      * @return the interface's ID
      */
@@ -55,8 +60,7 @@
 
     /**
      * Returns the interface's class field.
-     * Some useful constants for USB classes can be found in
-     * {@link android.hardware.usb.UsbConstants}
+     * Some useful constants for USB classes can be found in {@link UsbConstants}
      *
      * @return the interface's class
      */
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 7bf278a..60b37a1 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -31,7 +31,8 @@
 import java.util.HashMap;
 
 /**
- * This class allows you to access the state of USB, both in host and device mode.
+ * This class allows you to access the state of USB and communicate with USB devices.
+ * Currently only host mode is supported in the public API.
  *
  * <p>You can obtain an instance of this class by calling
  * {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}.
diff --git a/core/java/android/hardware/usb/UsbRequest.java b/core/java/android/hardware/usb/UsbRequest.java
index 5fe6c8c..2252248 100644
--- a/core/java/android/hardware/usb/UsbRequest.java
+++ b/core/java/android/hardware/usb/UsbRequest.java
@@ -24,8 +24,13 @@
  * A class representing USB request packet.
  * This can be used for both reading and writing data to or from a
  * {@link android.hardware.usb.UsbDeviceConnection}.
- * UsbRequests are sent asynchronously via {@link #queue} and the results
- * are read by {@link android.hardware.usb.UsbDeviceConnection#requestWait}.
+ * UsbRequests can be used to transfer data on bulk and interrupt endpoints.
+ * Requests on bulk endpoints can be sent synchronously via {@link UsbDeviceConnection#bulkTransfer}
+ * or asynchronously via {@link #queue} and {@link UsbDeviceConnection#requestWait}.
+ * Requests on interrupt endpoints are only send and received asynchronously.
+ *
+ * <p>Requests on endpoint zero are not supported by this class;
+ * use {@link UsbDeviceConnection#controlTransfer} for endpoint zero requests instead.
  */
 public class UsbRequest {
 
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 0c6ab9e..c8cb1de 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -95,7 +95,7 @@
      * Defines the UID/GID for the NFC service process.
      * @hide
      */
-    public static final int NFC_UID = 1022;
+    public static final int NFC_UID = 1023;
 
     /**
      * Defines the GID for the group that allows write access to the internal media storage.
diff --git a/core/java/android/text/GraphicsOperations.java b/core/java/android/text/GraphicsOperations.java
index d426d124..6e2168b 100644
--- a/core/java/android/text/GraphicsOperations.java
+++ b/core/java/android/text/GraphicsOperations.java
@@ -58,6 +58,13 @@
             int flags, float[] advances, int advancesIndex, Paint paint);
 
     /**
+     * Just like {@link Paint#getTextRunAdvances}.
+     * @hide
+     */
+    float getTextRunAdvancesICU(int start, int end, int contextStart, int contextEnd,
+            int flags, float[] advances, int advancesIndex, Paint paint);
+
+    /**
      * Just like {@link Paint#getTextRunCursor}.
      * @hide
      */
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index ea5cdfe..ff6a4cd 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -1170,6 +1170,35 @@
     }
 
     /**
+     * Don't call this yourself -- exists for Paint to use internally.
+     * {@hide}
+     */
+    public float getTextRunAdvancesICU(int start, int end, int contextStart, int contextEnd, int flags,
+            float[] advances, int advancesPos, Paint p) {
+
+        float ret;
+
+        int contextLen = contextEnd - contextStart;
+        int len = end - start;
+
+        if (end <= mGapStart) {
+            ret = p.getTextRunAdvancesICU(mText, start, len, contextStart, contextLen,
+                    flags, advances, advancesPos);
+        } else if (start >= mGapStart) {
+            ret = p.getTextRunAdvancesICU(mText, start + mGapLength, len,
+                    contextStart + mGapLength, contextLen, flags, advances, advancesPos);
+        } else {
+            char[] buf = TextUtils.obtain(contextLen);
+            getChars(contextStart, contextEnd, buf, 0);
+            ret = p.getTextRunAdvancesICU(buf, start - contextStart, len,
+                    0, contextLen, flags, advances, advancesPos);
+            TextUtils.recycle(buf);
+        }
+
+        return ret;
+    }
+
+    /**
      * Returns the next cursor position in the run.  This avoids placing the cursor between
      * surrogates, between characters that form conjuncts, between base characters and combining
      * marks, or within a reordering cluster.
diff --git a/core/java/android/webkit/CacheManager.java b/core/java/android/webkit/CacheManager.java
index 3ce0730..e21a02e 100644
--- a/core/java/android/webkit/CacheManager.java
+++ b/core/java/android/webkit/CacheManager.java
@@ -857,6 +857,7 @@
         String cacheControl = headers.getCacheControl();
         if (cacheControl != null) {
             String[] controls = cacheControl.toLowerCase().split("[ ,;]");
+            boolean noCache = false;
             for (int i = 0; i < controls.length; i++) {
                 if (NO_STORE.equals(controls[i])) {
                     return null;
@@ -867,7 +868,12 @@
                 // can only be used in CACHE_MODE_CACHE_ONLY case
                 if (NO_CACHE.equals(controls[i])) {
                     ret.expires = 0;
-                } else if (controls[i].startsWith(MAX_AGE)) {
+                    noCache = true;
+                // if cache control = no-cache has been received, ignore max-age
+                // header, according to http spec:
+                // If a request includes the no-cache directive, it SHOULD NOT
+                // include min-fresh, max-stale, or max-age.
+                } else if (controls[i].startsWith(MAX_AGE) && !noCache) {
                     int separator = controls[i].indexOf('=');
                     if (separator < 0) {
                         separator = controls[i].indexOf(':');
diff --git a/core/java/android/webkit/HTML5VideoFullScreen.java b/core/java/android/webkit/HTML5VideoFullScreen.java
index 9636513..3d15968 100644
--- a/core/java/android/webkit/HTML5VideoFullScreen.java
+++ b/core/java/android/webkit/HTML5VideoFullScreen.java
@@ -198,8 +198,6 @@
 
         if (mProgressView != null) {
             mProgressView.setVisibility(View.GONE);
-            mLayout.removeView(mProgressView);
-            mProgressView = null;
         }
 
         mVideoWidth = mp.getVideoWidth();
@@ -321,4 +319,13 @@
         return false;
     }
 
+    @Override
+    protected void switchProgressView(boolean playerBuffering) {
+        if (playerBuffering) {
+            mProgressView.setVisibility(View.VISIBLE);
+        } else {
+            mProgressView.setVisibility(View.GONE);
+        }
+        return;
+    }
 }
diff --git a/core/java/android/webkit/HTML5VideoView.java b/core/java/android/webkit/HTML5VideoView.java
index ad6e5d3..fd3f358 100644
--- a/core/java/android/webkit/HTML5VideoView.java
+++ b/core/java/android/webkit/HTML5VideoView.java
@@ -78,6 +78,7 @@
                         TIMEUPDATE_PERIOD);
             }
             mPlayer.start();
+            setPlayerBuffering(false);
         }
     }
 
@@ -296,4 +297,21 @@
         return 0;
     }
 
+    // This is true only when the player is buffering and paused
+    public boolean mPlayerBuffering = false;
+
+    public boolean getPlayerBuffering() {
+        return mPlayerBuffering;
+    }
+
+    public void setPlayerBuffering(boolean playerBuffering) {
+        mPlayerBuffering = playerBuffering;
+        switchProgressView(playerBuffering);
+    }
+
+
+    protected void switchProgressView(boolean playerBuffering) {
+        // Only used in HTML5VideoFullScreen
+    }
+
 }
diff --git a/core/java/android/webkit/HTML5VideoViewProxy.java b/core/java/android/webkit/HTML5VideoViewProxy.java
index 0ee1566..14157c2 100644
--- a/core/java/android/webkit/HTML5VideoViewProxy.java
+++ b/core/java/android/webkit/HTML5VideoViewProxy.java
@@ -95,8 +95,10 @@
         // identify the exact layer on the UI thread to use the SurfaceTexture.
         private static int mBaseLayer = 0;
 
-        // This is true only when the player is buffering and paused
-        private static boolean mPlayerBuffering = false;
+        private static void setPlayerBuffering(boolean playerBuffering) {
+            mHTML5VideoView.setPlayerBuffering(playerBuffering);
+        }
+
         // Every time webView setBaseLayer, this will be called.
         // When we found the Video layer, then we set the Surface Texture to it.
         // Otherwise, we may want to delete the Surface Texture to save memory.
@@ -111,7 +113,7 @@
                 int currentVideoLayerId = mHTML5VideoView.getVideoLayerId();
                 if (layer != 0 && surfTexture != null && currentVideoLayerId != -1) {
                     int playerState = mHTML5VideoView.getCurrentState();
-                    if (mPlayerBuffering)
+                    if (mHTML5VideoView.getPlayerBuffering())
                         playerState = HTML5VideoView.STATE_NOTPREPARED;
                     boolean foundInTree = nativeSendSurfaceTexture(surfTexture,
                             layer, currentVideoLayerId, textureName,
@@ -166,7 +168,6 @@
                 WebChromeClient client, int videoLayerId) {
             int currentVideoLayerId = -1;
             boolean backFromFullScreenMode = false;
-            mPlayerBuffering = false;
             if (mHTML5VideoView != null) {
                 currentVideoLayerId = mHTML5VideoView.getVideoLayerId();
                 if (mHTML5VideoView instanceof HTML5VideoFullScreen) {
@@ -231,7 +232,6 @@
         }
 
         public static void onPrepared() {
-            mPlayerBuffering = false;
             // The VideoView will decide whether to really kick off to play.
             mHTML5VideoView.start();
             if (mBaseLayer != 0) {
@@ -350,11 +350,11 @@
                 break;
             }
             case BUFFERING_START: {
-                VideoPlayer.mPlayerBuffering = true;
+                VideoPlayer.setPlayerBuffering(true);
                 break;
             }
             case BUFFERING_END: {
-                VideoPlayer.mPlayerBuffering = false;
+                VideoPlayer.setPlayerBuffering(false);
                 break;
             }
         }
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index c854fac..9cf2718 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -125,7 +125,7 @@
      *  SUBCLASSES MUST BE IMMUTABLE SO CLONE WORKS!!!!!
      */
     private abstract static class Action implements Parcelable {
-        public abstract void apply(View root) throws ActionException;
+        public abstract void apply(View root, ViewGroup rootParent) throws ActionException;
 
         public int describeContents() {
             return 0;
@@ -183,7 +183,7 @@
         }
 
         @Override
-        public void apply(View root) {
+        public void apply(View root, ViewGroup rootParent) {
             final View view = root.findViewById(viewId);
             if (!(view instanceof AdapterView<?>)) return;
 
@@ -214,7 +214,7 @@
         }
 
         @Override
-        public void apply(View root) {
+        public void apply(View root, ViewGroup rootParent) {
             final View target = root.findViewById(viewId);
             if (target == null) return;
 
@@ -295,7 +295,7 @@
         }
 
         @Override
-        public void apply(View root) {
+        public void apply(View root, ViewGroup rootParent) {
             final View target = root.findViewById(viewId);
             if (target == null) return;
 
@@ -360,6 +360,60 @@
         public final static int TAG = 8;
     }
 
+    private class SetRemoteViewsAdapterIntent extends Action {
+        public SetRemoteViewsAdapterIntent(int id, Intent intent) {
+            this.viewId = id;
+            this.intent = intent;
+        }
+
+        public SetRemoteViewsAdapterIntent(Parcel parcel) {
+            viewId = parcel.readInt();
+            intent = Intent.CREATOR.createFromParcel(parcel);
+        }
+
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(TAG);
+            dest.writeInt(viewId);
+            intent.writeToParcel(dest, flags);
+        }
+
+        @Override
+        public void apply(View root, ViewGroup rootParent) {
+            final View target = root.findViewById(viewId);
+            if (target == null) return;
+
+            // Ensure that we are applying to an AppWidget root
+            if (!(rootParent instanceof AppWidgetHostView)) {
+                Log.e("RemoteViews", "SetRemoteViewsAdapterIntent action can only be used for " +
+                        "AppWidgets (root id: " + viewId + ")");
+                return;
+            }
+            // Ensure that we are calling setRemoteAdapter on an AdapterView that supports it
+            if (!(target instanceof AbsListView) && !(target instanceof AdapterViewAnimator)) {
+                Log.e("RemoteViews", "Cannot setRemoteViewsAdapter on a view which is not " +
+                        "an AbsListView or AdapterViewAnimator (id: " + viewId + ")");
+                return;
+            }
+
+            // Embed the AppWidget Id for use in RemoteViewsAdapter when connecting to the intent
+            // RemoteViewsService
+            AppWidgetHostView host = (AppWidgetHostView) rootParent;
+            intent.putExtra(EXTRA_REMOTEADAPTER_APPWIDGET_ID, host.getAppWidgetId());
+            if (target instanceof AbsListView) {
+                AbsListView v = (AbsListView) target;
+                v.setRemoteViewsAdapter(intent);
+            } else if (target instanceof AdapterViewAnimator) {
+                AdapterViewAnimator v = (AdapterViewAnimator) target;
+                v.setRemoteViewsAdapter(intent);
+            }
+        }
+
+        int viewId;
+        Intent intent;
+
+        public final static int TAG = 10;
+    }
+
     /**
      * Equivalent to calling
      * {@link android.view.View#setOnClickListener(android.view.View.OnClickListener)}
@@ -383,7 +437,7 @@
         }
 
         @Override
-        public void apply(View root) {
+        public void apply(View root, ViewGroup rootParent) {
             final View target = root.findViewById(viewId);
             if (target == null) return;
 
@@ -479,7 +533,7 @@
         }
         
         @Override
-        public void apply(View root) {
+        public void apply(View root, ViewGroup rootParent) {
             final View target = root.findViewById(viewId);
             if (target == null) return;
             
@@ -539,7 +593,7 @@
         }
 
         @Override
-        public void apply(View root) {
+        public void apply(View root, ViewGroup rootParent) {
             final View view = root.findViewById(viewId);
             if (view == null) return;
 
@@ -755,7 +809,7 @@
         }
 
         @Override
-        public void apply(View root) {
+        public void apply(View root, ViewGroup rootParent) {
             final View view = root.findViewById(viewId);
             if (view == null) return;
 
@@ -850,7 +904,7 @@
         }
 
         @Override
-        public void apply(View root) {
+        public void apply(View root, ViewGroup rootParent) {
             final Context context = root.getContext();
             final ViewGroup target = (ViewGroup) root.findViewById(viewId);
             if (target == null) return;
@@ -952,6 +1006,9 @@
                 case SetOnClickFillInIntent.TAG:
                     mActions.add(new SetOnClickFillInIntent(parcel));
                     break;
+                case SetRemoteViewsAdapterIntent.TAG:
+                    mActions.add(new SetRemoteViewsAdapterIntent(parcel));
+                    break;
                 default:
                     throw new ActionException("Tag " + tag + " not found");
                 }
@@ -1287,16 +1344,29 @@
     /**
      * Equivalent to calling {@link android.widget.AbsListView#setRemoteViewsAdapter(Intent)}.
      *
-     * @param appWidgetId The id of the app widget which contains the specified view
+     * @param appWidgetId The id of the app widget which contains the specified view. (This
+     *      parameter is ignored in this deprecated method)
+     * @param viewId The id of the view whose text should change
+     * @param intent The intent of the service which will be
+     *            providing data to the RemoteViewsAdapter
+     * @deprecated This method has been deprecated. See
+     *      {@link android.widget.RemoteViews#setRemoteAdapter(int, Intent)}
+     */
+    @Deprecated
+    public void setRemoteAdapter(int appWidgetId, int viewId, Intent intent) {
+        setRemoteAdapter(viewId, intent);
+    }
+
+    /**
+     * Equivalent to calling {@link android.widget.AbsListView#setRemoteViewsAdapter(Intent)}.
+     * Can only be used for App Widgets.
+     *
      * @param viewId The id of the view whose text should change
      * @param intent The intent of the service which will be
      *            providing data to the RemoteViewsAdapter
      */
-    public void setRemoteAdapter(int appWidgetId, int viewId, Intent intent) {
-        // Embed the AppWidget Id for use in RemoteViewsAdapter when connecting to the intent
-        // RemoteViewsService
-        intent.putExtra(EXTRA_REMOTEADAPTER_APPWIDGET_ID, appWidgetId);
-        setIntent(viewId, "setRemoteViewsAdapter", intent);
+    public void setRemoteAdapter(int viewId, Intent intent) {
+        addAction(new SetRemoteViewsAdapterIntent(viewId, intent));
     }
 
     /**
@@ -1499,7 +1569,7 @@
 
         result = inflater.inflate(mLayoutId, parent, false);
 
-        performApply(result);
+        performApply(result, parent);
 
         return result;
     }
@@ -1514,15 +1584,15 @@
      */
     public void reapply(Context context, View v) {
         prepareContext(context);
-        performApply(v);
+        performApply(v, (ViewGroup) v.getParent());
     }
 
-    private void performApply(View v) {
+    private void performApply(View v, ViewGroup parent) {
         if (mActions != null) {
             final int count = mActions.size();
             for (int i = 0; i < count; i++) {
                 Action a = mActions.get(i);
-                a.apply(v);
+                a.apply(v, parent);
             }
         }
     }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index baf20a1..9e482b4 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -2951,6 +2951,16 @@
                     advancesIndex);
         }
 
+        public float getTextRunAdvancesICU(int start, int end, int contextStart,
+                int contextEnd, int flags, float[] advances, int advancesIndex,
+                Paint p) {
+            int count = end - start;
+            int contextCount = contextEnd - contextStart;
+            return p.getTextRunAdvancesICU(mChars, start + mStart, count,
+                    contextStart + mStart, contextCount, flags, advances,
+                    advancesIndex);
+        }
+
         public int getTextRunCursor(int contextStart, int contextEnd, int flags,
                 int offset, int cursorOpt, Paint p) {
             int contextCount = contextEnd - contextStart;
diff --git a/core/jni/android/graphics/HarfbuzzSkia.cpp b/core/jni/android/graphics/HarfbuzzSkia.cpp
index 58fb32b..92c743f 100644
--- a/core/jni/android/graphics/HarfbuzzSkia.cpp
+++ b/core/jni/android/graphics/HarfbuzzSkia.cpp
@@ -34,6 +34,8 @@
 #include "SkRect.h"
 #include "SkTypeface.h"
 
+#include <utils/Log.h>
+
 extern "C" {
 #include "harfbuzz-shaper.h"
 }
@@ -43,20 +45,13 @@
 
 namespace android {
 
-static HB_Fixed SkiaScalarToHarfbuzzFixed(SkScalar value)
-{
-    // HB_Fixed is a 26.6 fixed point format.
-    return value * 64;
-}
-
 static void setupPaintWithFontData(SkPaint* paint, FontData* data) {
-    paint->setAntiAlias(true);
-    paint->setSubpixelText(true);
-    paint->setHinting(SkPaint::kSlight_Hinting);
-    paint->setTextSize(SkFloatToScalar(data->textSize));
     paint->setTypeface(data->typeFace);
-    paint->setFakeBoldText(data->fakeBold);
-    paint->setTextSkewX(data->fakeItalic ? -SK_Scalar1/4 : 0);
+    paint->setTextSize(data->textSize);
+    paint->setTextSkewX(data->textSkewX);
+    paint->setTextScaleX(data->textScaleX);
+    paint->setFlags(data->flags);
+    paint->setHinting(data->hinting);
 }
 
 static HB_Bool stringToGlyphs(HB_Font hbFont, const HB_UChar16* characters, hb_uint32 length,
@@ -67,16 +62,13 @@
     setupPaintWithFontData(&paint, data);
 
     paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
-    int numGlyphs = paint.textToGlyphs(characters, length * sizeof(uint16_t),
-            reinterpret_cast<uint16_t*>(glyphs));
+    uint16_t* skiaGlyphs = reinterpret_cast<uint16_t*>(glyphs);
+    int numGlyphs = paint.textToGlyphs(characters, length * sizeof(uint16_t), skiaGlyphs);
 
     // HB_Glyph is 32-bit, but Skia outputs only 16-bit numbers. So our
     // |glyphs| array needs to be converted.
     for (int i = numGlyphs - 1; i >= 0; --i) {
-        uint16_t value;
-        // We use a memcpy to avoid breaking strict aliasing rules.
-        memcpy(&value, reinterpret_cast<char*>(glyphs) + sizeof(uint16_t) * i, sizeof(value));
-        glyphs[i] = value;
+        glyphs[i] = skiaGlyphs[i];
     }
 
     *glyphsSize = numGlyphs;
@@ -97,16 +89,17 @@
         return;
     for (unsigned i = 0; i < numGlyphs; ++i)
         glyphs16[i] = glyphs[i];
-    paint.getTextWidths(glyphs16, numGlyphs * sizeof(uint16_t), reinterpret_cast<SkScalar*>(advances));
+    SkScalar* scalarAdvances = reinterpret_cast<SkScalar*>(advances);
+    paint.getTextWidths(glyphs16, numGlyphs * sizeof(uint16_t), scalarAdvances);
 
     // The |advances| values which Skia outputs are SkScalars, which are floats
     // in Chromium. However, Harfbuzz wants them in 26.6 fixed point format.
     // These two formats are both 32-bits long.
     for (unsigned i = 0; i < numGlyphs; ++i) {
-        float value;
-        // We use a memcpy to avoid breaking strict aliasing rules.
-        memcpy(&value, reinterpret_cast<char*>(advances) + sizeof(float) * i, sizeof(value));
-        advances[i] = SkiaScalarToHarfbuzzFixed(value);
+        advances[i] = SkScalarToHBFixed(scalarAdvances[i]);
+#if DEBUG_ADVANCES
+        LOGD("glyphsToAdvances -- advances[%d]=%d", i, advances[i]);
+#endif
     }
     delete glyphs16;
 }
@@ -156,8 +149,8 @@
         return HB_Err_Invalid_SubTable;
     // Skia does let us get a single point from the path.
     path.getPoints(points, point + 1);
-    *xPos = SkiaScalarToHarfbuzzFixed(points[point].fX);
-    *yPos = SkiaScalarToHarfbuzzFixed(points[point].fY);
+    *xPos = SkScalarToHBFixed(points[point].fX);
+    *yPos = SkScalarToHBFixed(points[point].fY);
     *resultingNumPoints = numPoints;
     delete points;
 
@@ -176,12 +169,12 @@
     SkRect bounds;
     paint.getTextWidths(&glyph16, sizeof(glyph16), &width, &bounds);
 
-    metrics->x = SkiaScalarToHarfbuzzFixed(bounds.fLeft);
-    metrics->y = SkiaScalarToHarfbuzzFixed(bounds.fTop);
-    metrics->width = SkiaScalarToHarfbuzzFixed(bounds.width());
-    metrics->height = SkiaScalarToHarfbuzzFixed(bounds.height());
+    metrics->x = SkScalarToHBFixed(bounds.fLeft);
+    metrics->y = SkScalarToHBFixed(bounds.fTop);
+    metrics->width = SkScalarToHBFixed(bounds.width());
+    metrics->height = SkScalarToHBFixed(bounds.height());
 
-    metrics->xOffset = SkiaScalarToHarfbuzzFixed(width);
+    metrics->xOffset = SkScalarToHBFixed(width);
     // We can't actually get the |y| correct because Skia doesn't export
     // the vertical advance. However, nor we do ever render vertical text at
     // the moment so it's unimportant.
@@ -199,7 +192,7 @@
 
     switch (metric) {
     case HB_FontAscent:
-        return SkiaScalarToHarfbuzzFixed(-skiaMetrics.fAscent);
+        return SkScalarToHBFixed(-skiaMetrics.fAscent);
     // We don't support getting the rest of the metrics and Harfbuzz doesn't seem to need them.
     default:
         return 0;
diff --git a/core/jni/android/graphics/HarfbuzzSkia.h b/core/jni/android/graphics/HarfbuzzSkia.h
index d057d76..99b389a 100644
--- a/core/jni/android/graphics/HarfbuzzSkia.h
+++ b/core/jni/android/graphics/HarfbuzzSkia.h
@@ -27,22 +27,38 @@
 #ifndef HarfbuzzSkia_h
 #define HarfbuzzSkia_h
 
+#include "SkScalar.h"
 #include "SkTypeface.h"
+#include "SkPaint.h"
 
 extern "C" {
 #include "harfbuzz-shaper.h"
 }
 
 namespace android {
-    typedef struct {
-        SkTypeface* typeFace;
-        float textSize;
-        bool fakeBold;
-        bool fakeItalic;
-    } FontData;
 
-    HB_Error harfbuzzSkiaGetTable(void* voidface, const HB_Tag, HB_Byte* buffer, HB_UInt* len);
-    extern const HB_FontClass harfbuzzSkiaClass;
+static inline float HBFixedToFloat(HB_Fixed v) {
+    // Harfbuzz uses 26.6 fixed point values for pixel offsets
+    return v * (1.0f / 64);
+}
+
+static inline HB_Fixed SkScalarToHBFixed(SkScalar value) {
+    // HB_Fixed is a 26.6 fixed point format.
+    return SkScalarToFloat(value) * 64.0f;
+}
+
+typedef struct {
+    SkTypeface* typeFace;
+    SkScalar textSize;
+    SkScalar textSkewX;
+    SkScalar textScaleX;
+    uint32_t flags;
+    SkPaint::Hinting hinting;
+} FontData;
+
+HB_Error harfbuzzSkiaGetTable(void* voidface, const HB_Tag, HB_Byte* buffer, HB_UInt* len);
+extern const HB_FontClass harfbuzzSkiaClass;
+
 }  // namespace android
 
 #endif
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 5c3497f..27be871 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -414,6 +414,7 @@
         for (int i = 0; i < glyphCount; i++) {
             glyphsArray[i] = (jchar) shaperItem.glyphs[i];
         }
+        env->ReleaseCharArrayElements(glyphs, glyphsArray, JNI_ABORT);
         return glyphCount;
     }
 
@@ -442,6 +443,21 @@
         return totalAdvance;
     }
 
+    static jfloat doTextRunAdvancesICU(JNIEnv *env, SkPaint *paint, const jchar *text,
+                                    jint start, jint count, jint contextCount, jint flags,
+                                    jfloatArray advances, jint advancesIndex) {
+        jfloat advancesArray[count];
+        jfloat totalAdvance;
+
+        TextLayout::getTextRunAdvancesICU(paint, text, start, count, contextCount, flags,
+                                       advancesArray, totalAdvance);
+
+        if (advances != NULL) {
+            env->SetFloatArrayRegion(advances, advancesIndex, count, advancesArray);
+        }
+        return totalAdvance;
+    }
+
     static float getTextRunAdvances___CIIIII_FI(JNIEnv* env, jobject clazz, SkPaint* paint,
             jcharArray text, jint index, jint count, jint contextIndex, jint contextCount,
             jint flags, jfloatArray advances, jint advancesIndex) {
@@ -463,6 +479,27 @@
         return result;
     }
 
+    static float getTextRunAdvancesICU___CIIIII_FI(JNIEnv* env, jobject clazz, SkPaint* paint,
+            jcharArray text, jint index, jint count, jint contextIndex, jint contextCount,
+            jint flags, jfloatArray advances, jint advancesIndex) {
+        jchar* textArray = env->GetCharArrayElements(text, NULL);
+        jfloat result = doTextRunAdvancesICU(env, paint, textArray + contextIndex,
+            index - contextIndex, count, contextCount, flags, advances, advancesIndex);
+        env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
+        return result;
+    }
+
+    static float getTextRunAdvancesICU__StringIIIII_FI(JNIEnv* env, jobject clazz, SkPaint* paint,
+            jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint flags,
+            jfloatArray advances, jint advancesIndex) {
+        const jchar* textArray = env->GetStringChars(text, NULL);
+        jfloat result = doTextRunAdvancesICU(env, paint, textArray + contextStart,
+            start - contextStart, end - start, contextEnd - contextStart, flags, advances,
+            advancesIndex);
+        env->ReleaseStringChars(text, textArray);
+        return result;
+    }
+
     static jint doTextRunCursor(JNIEnv *env, SkPaint* paint, const jchar *text, jint start,
             jint count, jint flags, jint offset, jint opt) {
         SkScalar scalarArray[count];
@@ -748,10 +785,14 @@
     {"native_breakText","(Ljava/lang/String;ZF[F)I", (void*) SkPaintGlue::breakTextS},
     {"native_getTextWidths","(I[CII[F)I", (void*) SkPaintGlue::getTextWidths___CII_F},
     {"native_getTextWidths","(ILjava/lang/String;II[F)I", (void*) SkPaintGlue::getTextWidths__StringII_F},
-    {"native_getTextRunAdvances","(I[CIIIII[FI)F", (void*)
-        SkPaintGlue::getTextRunAdvances___CIIIII_FI},
+    {"native_getTextRunAdvances","(I[CIIIII[FI)F",
+        (void*) SkPaintGlue::getTextRunAdvances___CIIIII_FI},
     {"native_getTextRunAdvances","(ILjava/lang/String;IIIII[FI)F",
         (void*) SkPaintGlue::getTextRunAdvances__StringIIIII_FI},
+    {"native_getTextRunAdvancesICU","(I[CIIIII[FI)F",
+        (void*) SkPaintGlue::getTextRunAdvancesICU___CIIIII_FI},
+    {"native_getTextRunAdvancesICU","(ILjava/lang/String;IIIII[FI)F",
+        (void*) SkPaintGlue::getTextRunAdvancesICU__StringIIIII_FI},
     {"native_getTextGlyphs","(ILjava/lang/String;IIIII[C)I",
         (void*) SkPaintGlue::getTextGlyphs__StringIIIII_C},
     {"native_getTextRunCursor", "(I[CIIIII)I", (void*) SkPaintGlue::getTextRunCursor___C},
diff --git a/core/jni/android/graphics/RtlProperties.h b/core/jni/android/graphics/RtlProperties.h
index 2c68fa3..f41f4a1 100644
--- a/core/jni/android/graphics/RtlProperties.h
+++ b/core/jni/android/graphics/RtlProperties.h
@@ -45,7 +45,12 @@
     return kRtlDebugDisabled;
 }
 
+// Define if we want to use Harfbuzz (1) or not (0)
 #define RTL_USE_HARFBUZZ 1
 
+// Define if we want (1) to have Advances debug values or not (0)
+#define DEBUG_ADVANCES 0
+
+
 } // namespace android
 #endif // ANDROID_RTL_PROPERTIES_H
diff --git a/core/jni/android/graphics/TextLayout.cpp b/core/jni/android/graphics/TextLayout.cpp
index f1bb696..434f63b 100644
--- a/core/jni/android/graphics/TextLayout.cpp
+++ b/core/jni/android/graphics/TextLayout.cpp
@@ -269,6 +269,21 @@
 #endif
 }
 
+void TextLayout::getTextRunAdvancesHB(SkPaint* paint, const jchar* chars, jint start,
+                                    jint count, jint contextCount, jint dirFlags,
+                                    jfloat* resultAdvances, jfloat& resultTotalAdvance) {
+    // Compute advances and return them
+    RunAdvanceDescription::computeAdvancesWithHarfbuzz(paint, chars, start, count, contextCount, dirFlags,
+            resultAdvances, &resultTotalAdvance);
+}
+
+void TextLayout::getTextRunAdvancesICU(SkPaint* paint, const jchar* chars, jint start,
+                                    jint count, jint contextCount, jint dirFlags,
+                                    jfloat* resultAdvances, jfloat& resultTotalAdvance) {
+    // Compute advances and return them
+    RunAdvanceDescription::computeAdvancesWithICU(paint, chars, start, count, contextCount, dirFlags,
+            resultAdvances, &resultTotalAdvance);
+}
 
 // Draws a paragraph of text on a single line, running bidi and shaping
 void TextLayout::drawText(SkPaint* paint, const jchar* text, jsize len,
diff --git a/core/jni/android/graphics/TextLayout.h b/core/jni/android/graphics/TextLayout.h
index a950d13..138983c 100644
--- a/core/jni/android/graphics/TextLayout.h
+++ b/core/jni/android/graphics/TextLayout.h
@@ -73,6 +73,14 @@
                                    jint count, jint contextCount, jint dirFlags,
                                    jfloat* resultAdvances, jfloat& resultTotalAdvance);
 
+    static void getTextRunAdvancesICU(SkPaint* paint, const jchar* chars, jint start,
+                                   jint count, jint contextCount, jint dirFlags,
+                                   jfloat* resultAdvances, jfloat& resultTotalAdvance);
+
+    static void getTextRunAdvancesHB(SkPaint* paint, const jchar* chars, jint start,
+                                   jint count, jint contextCount, jint dirFlags,
+                                   jfloat* resultAdvances, jfloat& resultTotalAdvance);
+
     static void drawText(SkPaint* paint, const jchar* text, jsize len,
                          jint bidiFlags, jfloat x, jfloat y, SkCanvas* canvas);
 
diff --git a/core/jni/android/graphics/TextLayoutCache.h b/core/jni/android/graphics/TextLayoutCache.h
index 925bb7c..bced40c 100644
--- a/core/jni/android/graphics/TextLayoutCache.h
+++ b/core/jni/android/graphics/TextLayoutCache.h
@@ -19,17 +19,20 @@
 
 #include "RtlProperties.h"
 
-#include "stddef.h"
+#include <stddef.h>
 #include <utils/threads.h>
 #include <utils/String16.h>
-#include "utils/GenerationCache.h"
-#include "utils/Compare.h"
+#include <utils/GenerationCache.h>
+#include <utils/Compare.h>
 
-#include "SkPaint.h"
-#include "SkTemplates.h"
+#include <SkPaint.h>
+#include <SkTemplates.h>
+#include <SkUtils.h>
+#include <SkScalerContext.h>
+#include <SkAutoKern.h>
 
-#include "unicode/ubidi.h"
-#include "unicode/ushape.h"
+#include <unicode/ubidi.h>
+#include <unicode/ushape.h>
 #include "HarfbuzzSkia.h"
 #include "harfbuzz-shaper.h"
 
@@ -54,21 +57,16 @@
 // Define the interval in number of cache hits between two statistics dump
 #define DEFAULT_DUMP_STATS_CACHE_HIT_INTERVAL 100
 
-// Define if we want to have Advances debug values
-#define DEBUG_ADVANCES 0
-
 namespace android {
 
-// Harfbuzz uses 26.6 fixed point values for pixel offsets
-#define HB_FIXED_TO_FLOAT(v) (((float) v) * (1.0 / 64))
-
 /**
  * TextLayoutCacheKey is the Cache key
  */
 class TextLayoutCacheKey {
 public:
     TextLayoutCacheKey() : text(NULL), start(0), count(0), contextCount(0),
-            dirFlags(0), textSize(0), typeface(NULL), textSkewX(0), fakeBoldText(false)  {
+            dirFlags(0), typeface(NULL), textSize(0), textSkewX(0), textScaleX(0), flags(0),
+            hinting(SkPaint::kNo_Hinting)  {
     }
 
     TextLayoutCacheKey(const SkPaint* paint,
@@ -76,22 +74,28 @@
             size_t contextCount, int dirFlags) :
                 text(text), start(start), count(count), contextCount(contextCount),
                 dirFlags(dirFlags) {
-        textSize = paint->getTextSize();
         typeface = paint->getTypeface();
+        textSize = paint->getTextSize();
         textSkewX = paint->getTextSkewX();
-        fakeBoldText = paint->isFakeBoldText();
+        textScaleX = paint->getTextScaleX();
+        flags = paint->getFlags();
+        hinting = paint->getHinting();
     }
 
     bool operator<(const TextLayoutCacheKey& rhs) const {
         LTE_INT(count) {
             LTE_INT(contextCount) {
                 LTE_INT(start) {
-                    LTE_FLOAT(textSize) {
-                        LTE_INT(typeface) {
-                            LTE_INT(textSkewX) {
-                                LTE_INT(fakeBoldText) {
-                                    LTE_INT(dirFlags) {
-                                        return strncmp16(text, rhs.text, contextCount) < 0;
+                    LTE_INT(typeface) {
+                        LTE_FLOAT(textSize) {
+                            LTE_FLOAT(textSkewX) {
+                                LTE_FLOAT(textScaleX) {
+                                    LTE_INT(flags) {
+                                        LTE_INT(hinting) {
+                                            LTE_INT(dirFlags) {
+                                                return strncmp16(text, rhs.text, contextCount) < 0;
+                                            }
+                                        }
                                     }
                                 }
                             }
@@ -124,10 +128,12 @@
     size_t count;
     size_t contextCount;
     int dirFlags;
-    float textSize;
     SkTypeface* typeface;
-    float textSkewX;
-    bool fakeBoldText;
+    SkScalar textSize;
+    SkScalar textSkewX;
+    SkScalar textScaleX;
+    uint32_t flags;
+    SkPaint::Hinting hinting;
 }; // TextLayoutCacheKey
 
 /*
@@ -202,6 +208,8 @@
         shaperItem->font = font;
         shaperItem->face = HB_NewFace(shaperItem->font, harfbuzzSkiaGetTable);
 
+        shaperItem->kerning_applied = false;
+
         // We cannot know, ahead of time, how many glyphs a given script run
         // will produce. We take a guess that script runs will not produce more
         // than twice as many glyphs as there are code points plus a bit of
@@ -222,10 +230,12 @@
         shaperItem->string = chars;
         shaperItem->stringLength = contextCount;
 
-        fontData->textSize = paint->getTextSize();
-        fontData->fakeBold = paint->isFakeBoldText();
-        fontData->fakeItalic = (paint->getTextSkewX() > 0);
         fontData->typeFace = paint->getTypeface();
+        fontData->textSize = paint->getTextSize();
+        fontData->textSkewX = paint->getTextSkewX();
+        fontData->textScaleX = paint->getTextScaleX();
+        fontData->flags = paint->getFlags();
+        fontData->hinting = paint->getHinting();
 
         shaperItem->font->userData = fontData;
     }
@@ -261,13 +271,15 @@
                 contextCount, dirFlags);
 
 #if DEBUG_ADVANCES
-        LOGD("HARFBUZZ -- num_glypth=%d", shaperItem.num_glyphs);
+        LOGD("HARFBUZZ -- num_glypth=%d - kerning_applied=%d", shaperItem.num_glyphs, shaperItem.kerning_applied);
+        LOGD("         -- string= '%s'", String8(chars, contextCount).string());
+        LOGD("         -- isDevKernText=%d", paint->isDevKernText());
 #endif
 
         jfloat totalAdvance = 0;
+
         for (size_t i = 0; i < count; i++) {
-            // Be careful: we need to use ceilf() for doing the same way as what Skia is doing
-            totalAdvance += outAdvances[i] = ceilf(HB_FIXED_TO_FLOAT(shaperItem.advances[i]));
+            totalAdvance += outAdvances[i] = HBFixedToFloat(shaperItem.advances[i]);
 
 #if DEBUG_ADVANCES
             LOGD("hb-adv = %d - rebased = %f - total = %f", shaperItem.advances[i], outAdvances[i],
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 0c9a2ef..348ded7 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1031,7 +1031,7 @@
     <permission android:name="android.permission.STOP_APP_SWITCHES"
         android:label="@string/permlab_stopAppSwitches"
         android:description="@string/permdesc_stopAppSwitches"
-        android:protectionLevel="signature" />
+        android:protectionLevel="signatureOrSystem" />
 
     <!-- Allows an application to retrieve the current state of keys and
          switches.  This is only for use by the system.-->
diff --git a/core/res/res/drawable-hdpi/ic_media_video_poster.png b/core/res/res/drawable-hdpi/ic_media_video_poster.png
index 6c1fd6b..77b6b0e 100644
--- a/core/res/res/drawable-hdpi/ic_media_video_poster.png
+++ b/core/res/res/drawable-hdpi/ic_media_video_poster.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/password_keyboard_background_holo.9.png b/core/res/res/drawable-hdpi/password_keyboard_background_holo.9.png
new file mode 100644
index 0000000..c56c704
--- /dev/null
+++ b/core/res/res/drawable-hdpi/password_keyboard_background_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_bg_activated_holo_dark.9.png b/core/res/res/drawable-hdpi/textfield_bg_activated_holo_dark.9.png
new file mode 100644
index 0000000..a233b0d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/textfield_bg_activated_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_bg_default_holo_dark.9.png b/core/res/res/drawable-hdpi/textfield_bg_default_holo_dark.9.png
new file mode 100644
index 0000000..403f502
--- /dev/null
+++ b/core/res/res/drawable-hdpi/textfield_bg_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_bg_disabled_focused_holo_dark.9.png b/core/res/res/drawable-hdpi/textfield_bg_disabled_focused_holo_dark.9.png
new file mode 100644
index 0000000..0ded801
--- /dev/null
+++ b/core/res/res/drawable-hdpi/textfield_bg_disabled_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_bg_disabled_holo_dark.9.png b/core/res/res/drawable-hdpi/textfield_bg_disabled_holo_dark.9.png
new file mode 100644
index 0000000..27237b8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/textfield_bg_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_bg_focused_holo_dark.9.png b/core/res/res/drawable-hdpi/textfield_bg_focused_holo_dark.9.png
new file mode 100644
index 0000000..0e451f1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/textfield_bg_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-ldpi/ic_media_video_poster.png b/core/res/res/drawable-ldpi/ic_media_video_poster.png
index 786d0e6..7b34913 100644
--- a/core/res/res/drawable-ldpi/ic_media_video_poster.png
+++ b/core/res/res/drawable-ldpi/ic_media_video_poster.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_media_video_poster.png b/core/res/res/drawable-mdpi/ic_media_video_poster.png
old mode 100644
new mode 100755
index 10bbd74..f457f23
--- a/core/res/res/drawable-mdpi/ic_media_video_poster.png
+++ b/core/res/res/drawable-mdpi/ic_media_video_poster.png
Binary files differ
diff --git a/core/res/res/layout/keyguard_screen_password_landscape.xml b/core/res/res/layout/keyguard_screen_password_landscape.xml
index 4d8c688..aac0853 100644
--- a/core/res/res/layout/keyguard_screen_password_landscape.xml
+++ b/core/res/res/layout/keyguard_screen_password_landscape.xml
@@ -16,59 +16,81 @@
 ** limitations under the License.
 */
 -->
+
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:orientation="vertical"
-    android:gravity="center_horizontal">
+    android:orientation="vertical">
 
-    <LinearLayout
+    <View
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="horizontal">
-        <!-- "Enter PIN(Password) to unlock" -->
-        <TextView android:id="@+id/status1"
-            android:layout_width="0dip"
-            android:layout_height="wrap_content"
-            android:layout_weight="1"
-            android:orientation="horizontal"
-            android:layout_marginRight="6dip"
-            android:layout_marginLeft="6dip"
-            android:layout_marginTop="10dip"
-            android:layout_marginBottom="10dip"
-            android:gravity="left"
-            android:ellipsize="marquee"
-            android:text="@android:string/keyguard_password_enter_password_code"
-            android:textAppearance="?android:attr/textAppearanceLarge"
-        />
-
-        <!-- Password entry field -->
-        <EditText android:id="@+id/passwordEntry"
-            android:layout_width="0dip"
-            android:layout_height="wrap_content"
-            android:layout_weight="1"
-            android:singleLine="true"
-            android:textStyle="bold"
-            android:inputType="textPassword"
-            android:gravity="center"
-            android:layout_gravity="center"
-            android:textSize="24sp"
-            android:textAppearance="?android:attr/textAppearanceLarge"
-            android:background="@drawable/password_field_default"
-            android:textColor="#ffffffff"
-        />
-    </LinearLayout>
-
-    <!-- Alphanumeric keyboard -->
-    <com.android.internal.widget.PasswordEntryKeyboardView android:id="@+id/keyboard"
-        android:layout_alignParentBottom="true"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:background="#00000000"
-        android:keyBackground="@drawable/btn_keyboard_key_fulltrans"
+        android:layout_height="0dip"
+        android:layout_weight="1"
     />
 
-    <!-- emergency call button -->
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+
+        <!-- left side: status -->
+        <include layout="@layout/keyguard_screen_status_land"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_centerVertical="true"
+            android:layout_alignParentLeft="true"/>
+
+        <!-- right side: password -->
+        <LinearLayout
+            android:layout_width="300dip"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:layout_alignParentRight="true"
+            android:layout_centerVertical="true">
+
+            <!-- Password entry field -->
+            <EditText android:id="@+id/passwordEntry"
+                android:layout_height="wrap_content"
+                android:layout_width="match_parent"
+                android:singleLine="true"
+                android:textStyle="normal"
+                android:inputType="textPassword"
+                android:gravity="center"
+                android:textSize="24sp"
+                android:textAppearance="?android:attr/textAppearanceMedium"
+                android:background="@drawable/lockscreen_password_field_dark"
+                android:textColor="#ffffffff"
+                />
+
+            <!-- Numeric keyboard -->
+            <com.android.internal.widget.PasswordEntryKeyboardView android:id="@+id/keyboard"
+                android:layout_width="300dip"
+                android:layout_height="400dip"
+                android:background="#40000000"
+                android:layout_marginTop="5dip"
+                android:keyBackground="@drawable/btn_keyboard_key_fulltrans"
+                android:visibility="gone"
+            />
+        </LinearLayout>
+
+    </RelativeLayout>
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="0dip"
+        android:layout_weight="1"
+    />
+
+    <!-- Alphanumeric keyboard -->
+    <com.android.internal.widget.PasswordEntryKeyboardView android:id="@+id/keyboardAlpha"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="@drawable/password_keyboard_background_holo"
+        android:keyBackground="@drawable/btn_keyboard_key_fulltrans"
+        android:keyTextSize="18dip"
+        android:visibility="gone"
+    />
+
+    <!-- emergency call button NOT CURRENTLY USED -->
     <Button
         android:id="@+id/emergencyCall"
         android:layout_width="wrap_content"
@@ -76,6 +98,7 @@
         android:drawableLeft="@drawable/ic_emergency"
         android:drawablePadding="8dip"
         android:text="@string/lockscreen_emergency_call"
+        android:visibility="gone"
         style="@style/Widget.Button.Transparent"
     />
 
diff --git a/core/res/res/layout/keyguard_screen_password_portrait.xml b/core/res/res/layout/keyguard_screen_password_portrait.xml
index 93966de..7805672b 100644
--- a/core/res/res/layout/keyguard_screen_password_portrait.xml
+++ b/core/res/res/layout/keyguard_screen_password_portrait.xml
@@ -19,63 +19,18 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:orientation="vertical"
-    android:gravity="center_horizontal">
+    android:orientation="vertical">
 
-    <!-- "Enter PIN(Password) to unlock" -->
-    <TextView android:id="@+id/status1"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="horizontal"
-        android:layout_marginRight="6dip"
-        android:layout_marginLeft="6dip"
-        android:layout_marginTop="10dip"
-        android:layout_marginBottom="10dip"
-        android:gravity="center"
-        android:text="@android:string/keyguard_password_enter_password_code"
-        android:textAppearance="?android:attr/textAppearanceLarge"
-    />
-
-    <!-- spacer above text entry field -->
-    <View
-        android:id="@+id/spacerBottom"
-        android:layout_width="fill_parent"
-        android:layout_height="1dip"
-        android:layout_marginTop="6dip"
-        android:background="@android:drawable/divider_horizontal_dark"
-    />
-
-    <!-- Password entry field -->
-    <EditText android:id="@+id/passwordEntry"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:singleLine="true"
-        android:textStyle="bold"
-        android:inputType="textPassword"
-        android:gravity="center"
-        android:layout_gravity="center"
-        android:textSize="32sp"
-        android:layout_marginTop="15dip"
-        android:layout_marginLeft="30dip"
-        android:layout_marginRight="30dip"
-        android:textAppearance="?android:attr/textAppearanceLarge"
-        android:background="@drawable/password_field_default"
-        android:textColor="#ffffffff"
-    />
-
-    <View
-        android:layout_width="match_parent"
-        android:layout_height="0dip"
-        android:layout_weight="1" />
-
-    <!-- Alphanumeric keyboard -->
-    <com.android.internal.widget.PasswordEntryKeyboardView android:id="@+id/keyboard"
-        android:layout_alignParentBottom="true"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:background="#00000000"
-        android:keyBackground="@drawable/btn_keyboard_key_fulltrans"
-    />
+    <!-- top: status -->
+    <RelativeLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content">
+        <include layout="@layout/keyguard_screen_status_port"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentTop="true"
+            android:layout_alignParentLeft="true"/>
+    </RelativeLayout>
 
     <!-- emergency call button -->
     <Button
@@ -84,9 +39,48 @@
         android:layout_height="wrap_content"
         android:drawableLeft="@drawable/ic_emergency"
         android:drawablePadding="8dip"
-        android:layout_marginTop="20dip"
-        android:layout_marginBottom="20dip"
         android:text="@string/lockscreen_emergency_call"
+        android:visibility="gone"
         style="@style/Widget.Button.Transparent"
     />
-</LinearLayout>
+
+    <!-- bottom: password -->
+
+    <!-- Password entry field -->
+    <EditText android:id="@+id/passwordEntry"
+        android:layout_height="wrap_content"
+        android:layout_width="match_parent"
+        android:singleLine="true"
+        android:textStyle="normal"
+        android:inputType="textPassword"
+        android:gravity="center"
+        android:textSize="22sp"
+        android:background="@drawable/lockscreen_password_field_dark"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:textColor="#ffffffff"/>
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="0dip"
+        android:layout_weight="1"
+    />
+
+    <!-- Numeric keyboard -->
+    <com.android.internal.widget.PasswordEntryKeyboardView android:id="@+id/keyboard"
+        android:layout_width="match_parent"
+        android:layout_height="260dip"
+        android:background="#40000000"
+        android:keyBackground="@drawable/btn_keyboard_key_fulltrans"
+    />
+
+    <!-- Alphanumeric keyboard -->
+    <com.android.internal.widget.PasswordEntryKeyboardView android:id="@+id/keyboardAlpha"
+        android:layout_width="match_parent"
+        android:layout_height="400dip"
+        android:background="@drawable/password_keyboard_background_holo"
+        android:keyBackground="@drawable/btn_keyboard_key_fulltrans"
+        android:keyTextSize="22dip"
+        android:visibility="gone"
+    />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/core/res/res/layout/keyguard_screen_status_land.xml b/core/res/res/layout/keyguard_screen_status_land.xml
new file mode 100644
index 0000000..259a3af
--- /dev/null
+++ b/core/res/res/layout/keyguard_screen_status_land.xml
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2010, 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.
+*/
+-->
+
+<!-- Status to show on the left side of lock screen -->
+<LinearLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:orientation="vertical"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:gravity="left"
+        >
+
+    <TextView
+        android:id="@+id/carrier"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:textSize="17sp"
+        android:drawablePadding="4dip"
+        android:singleLine="true"
+        android:ellipsize="marquee"
+        />
+
+    <com.android.internal.widget.DigitalClock android:id="@+id/time"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentTop="true"
+        android:layout_alignParentLeft="true"
+        android:layout_marginTop="8dip"
+        android:layout_marginBottom="8dip">
+
+        <!-- Because we can't have multi-tone fonts, we render two TextViews, one on
+        top of the other. Hence the redundant layout... -->
+        <TextView android:id="@+id/timeDisplayBackground"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:singleLine="true"
+            android:ellipsize="none"
+            android:textSize="40sp"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="@color/lockscreen_clock_background"
+            android:layout_marginBottom="6dip"
+            />
+
+        <TextView android:id="@+id/timeDisplayForeground"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:singleLine="true"
+            android:ellipsize="none"
+            android:textSize="40sp"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="@color/lockscreen_clock_foreground"
+            android:layout_alignLeft="@id/timeDisplayBackground"
+            android:layout_alignTop="@id/timeDisplayBackground"
+            android:layout_marginBottom="6dip"
+            />
+
+        <TextView android:id="@+id/am_pm"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_toRightOf="@id/timeDisplayBackground"
+            android:layout_alignBaseline="@id/timeDisplayBackground"
+            android:singleLine="true"
+            android:ellipsize="none"
+            android:textSize="18sp"
+            android:layout_marginLeft="8dip"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="@color/lockscreen_clock_am_pm"
+            />
+
+    </com.android.internal.widget.DigitalClock>
+
+    <LinearLayout
+        android:orientation="horizontal"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/time"
+        android:layout_marginTop="10dip">
+
+        <TextView
+            android:id="@+id/date"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textSize="17sp"/>
+
+        <TextView
+            android:id="@+id/alarm_status"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="30dip"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textSize="17sp"/>
+
+    </LinearLayout>
+
+    <!-- Status2 is generally charge status  -->
+    <TextView
+        android:id="@+id/status2"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentTop="true"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:textSize="17sp"
+        android:layout_marginTop="10dip"
+        android:drawablePadding="4dip"
+        android:visibility="gone"
+        />
+
+    <!-- Status1 is generally battery status and informational messages -->
+    <TextView
+        android:id="@+id/status1"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="10dip"
+        android:textSize="17sp"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        />
+
+    <TextView
+        android:id="@+id/propertyOf"
+        android:lineSpacingExtra="8dip"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:textSize="17sp"
+        android:layout_marginTop="20dip"
+        android:singleLine="false"
+        android:textColor="@color/lockscreen_owner_info"
+        android:visibility="gone"
+        />
+</LinearLayout>
diff --git a/core/res/res/layout/keyguard_screen_status_port.xml b/core/res/res/layout/keyguard_screen_status_port.xml
new file mode 100644
index 0000000..680c073
--- /dev/null
+++ b/core/res/res/layout/keyguard_screen_status_port.xml
@@ -0,0 +1,145 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2010, 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.
+*/
+-->
+
+<!-- Status to show on the left side of lock screen -->
+<LinearLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:orientation="vertical"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:gravity="left">
+
+    <TextView
+        android:id="@+id/carrier"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:textSize="17sp"
+        android:drawablePadding="4dip"
+        android:layout_marginTop="10dip"
+        android:singleLine="true"
+        android:ellipsize="marquee"
+        />
+
+    <com.android.internal.widget.DigitalClock android:id="@+id/time"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="8dip"
+        android:layout_marginBottom="8dip">
+
+        <!-- Because we can't have multi-tone fonts, we render two TextViews, one on
+        top of the other. Hence the redundant layout... -->
+        <TextView android:id="@+id/timeDisplayBackground"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:singleLine="true"
+            android:ellipsize="none"
+            android:textSize="60sp"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="@color/lockscreen_clock_background"
+            android:layout_marginBottom="6dip"
+            />
+
+        <TextView android:id="@+id/timeDisplayForeground"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:singleLine="true"
+            android:ellipsize="none"
+            android:textSize="60sp"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="@color/lockscreen_clock_foreground"
+            android:layout_marginBottom="6dip"
+            android:layout_alignLeft="@id/timeDisplayBackground"
+            android:layout_alignTop="@id/timeDisplayBackground"
+            />
+
+        <TextView android:id="@+id/am_pm"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_toRightOf="@id/timeDisplayBackground"
+            android:layout_alignBaseline="@id/timeDisplayBackground"
+            android:singleLine="true"
+            android:ellipsize="none"
+            android:textSize="22sp"
+            android:layout_marginLeft="8dip"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="@color/lockscreen_clock_am_pm"
+            />
+
+    </com.android.internal.widget.DigitalClock>
+
+    <LinearLayout
+        android:orientation="horizontal"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/time"
+        android:layout_marginTop="10dip">
+
+        <TextView
+            android:id="@+id/date"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textSize="17sp"/>
+
+        <TextView
+            android:id="@+id/alarm_status"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="30dip"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textSize="17sp"/>
+
+    </LinearLayout>
+
+    <!-- used for status such as the next alarm, and charging status.  -->
+    <TextView
+        android:id="@+id/status2"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentTop="true"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:textSize="17sp"
+        android:layout_marginTop="10dip"
+        android:drawablePadding="4dip"
+        android:visibility="gone"
+        />
+
+    <TextView
+        android:id="@+id/status1"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="10dip"
+        android:textSize="17sp"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        />
+
+    <TextView
+        android:id="@+id/propertyOf"
+        android:lineSpacingExtra="8dip"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="20dip"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:textSize="17sp"
+        android:singleLine="false"
+        android:visibility="gone"
+        android:textColor="@color/lockscreen_owner_info"
+        />
+</LinearLayout>
diff --git a/core/res/res/values-land/dimens.xml b/core/res/res/values-land/dimens.xml
index fbfc3bf..058daa8 100644
--- a/core/res/res/values-land/dimens.xml
+++ b/core/res/res/values-land/dimens.xml
@@ -1,25 +1,29 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* 
+/*
 **
 ** Copyright 2010, 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 
+** 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 
+**     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 
+** 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.
 */
 -->
 
 <resources>
-    <dimen name="password_keyboard_key_height">47dip</dimen>
+    <!-- Default height of a key in the password keyboard for alpha -->
+    <dimen name="password_keyboard_key_height_alpha">47dip</dimen>
+    <!-- Default height of a key in the password keyboard for numeric -->
+    <dimen name="password_keyboard_key_height_numeric">60dip</dimen>
+    <!-- Default correction for the space key in the password keyboard -->
     <dimen name="password_keyboard_spacebar_vertical_correction">2dip</dimen>
     <dimen name="preference_screen_side_margin">96dp</dimen>
     <dimen name="preference_screen_side_margin_negative">-100dp</dimen>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index cca7d8b..968d99c 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -34,6 +34,8 @@
     <dimen name="status_bar_height">25dip</dimen>
     <!-- Height of the status bar -->
     <dimen name="status_bar_icon_size">25dip</dimen>
+    <!-- Size of the giant number (unread count) in the notifications -->
+    <dimen name="status_bar_content_number_size">48sp</dimen>
     <!-- Margin at the edge of the screen to ignore touch events for in the windowshade. -->
     <dimen name="status_bar_edge_ignore">5dp</dimen>
     <!-- Margin for permanent screen decorations at the bottom. -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 0fefbf2..4109ae1 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1657,4 +1657,6 @@
   <public type="attr" name="state_drag_can_accept" />
   <public type="attr" name="state_drag_hovered" />
 
+  <public type="style" name="Theme.Holo.Light.NoActionBar" />
+
 </resources>
diff --git a/docs/html/guide/market/billing/billing_integrate.jd b/docs/html/guide/market/billing/billing_integrate.jd
index 26bda66..7532337 100755
--- a/docs/html/guide/market/billing/billing_integrate.jd
+++ b/docs/html/guide/market/billing/billing_integrate.jd
@@ -121,7 +121,6 @@
 
 <p>The in-app billing sample application is available as a downloadable component of the Android SDK. To download the sample application component, launch the Android SDK and AVD Manager and then select the "Google Market Billing package" component (see figure 1), and click <strong>Install Selected</strong> to begin the download.</p>
 
-<div style="margin-bottom:2em;">
 
 <img src="{@docRoot}images/billing_package.png" height="325" id="figure1" />
 <p class="img-caption">
@@ -296,7 +295,7 @@
 <pre>
 try {
   boolean bindResult = mContext.bindService(
-    new Intent(IMarketBillingService.class.getName()), this, Context.BIND_AUTO_CREATE);
+    new Intent("com.android.vending.billing.MarketBillingService.BIND"), this, Context.BIND_AUTO_CREATE);
   if (bindResult) {
     Log.i(TAG, "Service bind successful.");
   } else {
@@ -664,8 +663,6 @@
 
 <p class="caution"><strong>Important</strong>: To keep your public key safe from malicious users and hackers, do not embed your public key as an entire literal string. Instead, construct the string at runtime from pieces or use bit manipulation (for example, XOR with some other string) to hide the actual key. The key itself is not secret information, but you do not want to make it easy for a hacker or malicious user to replace the public key with another key.</p>
 
-<div style="margin-bottom:2em;">
-
 <img src="{@docRoot}images/billing_public_key.png" height="510" id="figure2" />
 <p class="img-caption">
   <strong>Figure 2.</strong> The Licensing and In-app Billing panel of your account's Edit Profile page lets you see your public key.
diff --git a/docs/html/guide/practices/screens_support.jd b/docs/html/guide/practices/screens_support.jd
index 520bd28..9875a6e 100644
--- a/docs/html/guide/practices/screens_support.jd
+++ b/docs/html/guide/practices/screens_support.jd
@@ -189,12 +189,32 @@
 handle the actual rendering of the UI on the current device screen according to
 its characteristics. </p>
 
-
 <img src="{@docRoot}images/screens_support/screens-ranges.png" />
 <p class="img-caption"><strong>Figure 1.</strong>
 Illustration of how the Android platform maps actual screen densities and sizes
 to generalized density and size configurations. </p>
 
+<p>Layout designs often need to be done against a minimum amount of
+available space, so each screen size bucket has an associated minimum size.
+These sizes are in "dp" units -- the same units you should use in defining
+your layouts, which allow us to avoid worrying about changes in screen density.</p>
+
+<ul>
+<li> <em>xlarge</em> screens are at least 960dp x 720dp.
+<li> <em>large</em> screens are at least 640dp x 480dp.
+<li> <em>normal</em> screens are at least 470dp x 320dp.
+<li> <em>small</em> screens are at least 426dp x 320dp.
+</ul>
+
+<p>Note that these minimum screen sizes were not
+as well defined prior to Android 3.0, so you may encounter some devices
+that are mis-classified between normal and large.  These are also based
+on the physical resolution of the screen, so may vary across devices --
+for example a 1024x720 tablet with a system bar would actually have a bit
+less space available to the application due to it being used by the system
+bar.  Android does not currently support screens smaller than the "small"
+426dp x 320dp size.</p>
+
 <p>Although the platform lets your application provide customized resources for
 the various size and density configurations, you do not need to do write
 custom code or provide custom resources for every combination of screen size and density.
@@ -212,7 +232,8 @@
 screen.</p>
 
 <p class="table-caption" id="screens-table"><strong>Table 1.</strong> Screen
-sizes and densities of emulator skins included in the Android SDK.</p>
+sizes and densities of emulator skins included in the Android SDK and other
+representative resolutions.</p>
 
   <table>
     <tbody>
@@ -235,27 +256,33 @@
       <td  style="background-color:#f3f3f3">
         <em>Small</em> screen
       </td>
-      <td style="font-size:.9em;">QVGA (240x320)</td>
+      <td style="font-size:.9em;"><strong>QVGA (240x320)</strong></td>
       </td>
       <td></td>
-      <td></td>
+      <td style="font-size:.9em;">480x640</td>
       <td></td>
     </tr>
     <tr>
       <td style="background-color:#f3f3f3">
         <em>Normal</em> screen
       </td>
-      <td style="font-size:.9em;">WQVGA400 (240x400)<br>WQVGA432 (240x432)</td>
-      <td style="font-size:.9em;">HVGA (320x480)</td>
-      <td style="font-size:.9em;">WVGA800 (480x800)<br>WVGA854 (480x854)</td>
-      <td style="font-size:.9em;"></td>
+      <td style="font-size:.9em;"><strong>WQVGA400 (240x400)</strong>
+        <br><strong>WQVGA432 (240x432)</strong></td>
+      <td style="font-size:.9em;"><strong>HVGA (320x480)</strong></td>
+      <td style="font-size:.9em;"><strong>WVGA800 (480x800)</strong>
+        <br><strong>WVGA854 (480x854)</strong>
+        <br>600x1024</td>
+      <td style="font-size:.9em;">640x960</td>
     </tr>
     <tr>
       <td style="background-color:#f3f3f3">
         <em>Large</em> screen
       </td>
-      <td></td>
-      <td style="font-size:.9em;">WVGA800* (480x800)<br>WVGA854* (480x854)</td>
+      <td style="font-size:.9em;"><strong>WVGA800** (480x800)</strong>
+        <br><strong>WVGA854** (480x854)</strong></td>
+      <td style="font-size:.9em;"><strong>WVGA800* (480x800)</strong>
+        <br><strong>WVGA854* (480x854)</strong>
+        <br>600x1024</td>
       <td></td>
       <td></td>
     </tr>
@@ -263,10 +290,13 @@
       <td style="background-color:#f3f3f3">
         <em>Extra Large</em> screen
       </td>
-      <td></td>
-      <td></td>
-      <td></td>
-      <td></td>
+      <td style="font-size:.9em;">600x1024</td>
+      <td style="font-size:.9em;">768x1024<br><strong>WXGA (768x1280)</strong>
+        <br>800x1280</td>
+      <td style="font-size:.9em;">1152x1536<br>1152x1920
+        <br>1200x1920</td>
+      <td style="font-size:.9em;">1536x2048<br>1536x2560
+        <br>1600x2560</td>
     </tr>
     <tr>
       <td colspan="4" style="border:none;font-size:90%;">* To emulate this
@@ -274,6 +304,12 @@
         creating an AVD that uses a WVGA800 or WVGA854 skin.
       </td>
     </tr>
+    <tr>
+      <td colspan="4" style="border:none;font-size:90%;">** To emulate this
+        configuration, specify a custom density of 120 when
+        creating an AVD that uses a WVGA800 or WVGA854 skin.
+      </td>
+    </tr>
 </table>
 
 <p>For an overview of the relative numbers of high (hdpi), medium (mdpi), and
diff --git a/docs/html/guide/topics/resources/providing-resources.jd b/docs/html/guide/topics/resources/providing-resources.jd
index 1583dee..1da2622 100644
--- a/docs/html/guide/topics/resources/providing-resources.jd
+++ b/docs/html/guide/topics/resources/providing-resources.jd
@@ -337,21 +337,25 @@
         <li>{@code small}: Screens based on the space available on a
         low-density QVGA screen.  Considering a portrait HVGA display, this has
         the same available width but less height&mdash;it is 3:4 vs. HVGA's
-        2:3 aspect ratio.  Examples are QVGA low density and VGA high
+        2:3 aspect ratio.  The minimum layout size for this screen configuration
+        is approximately 320x426 dp units.  Examples are QVGA low density and VGA high
         density.</li>
         <li>{@code normal}: Screens based on the traditional
         medium-density HVGA screen.  A screen is considered to be normal if it is
-        at least this size (independent of density) and not larger.  Examples
+        at least this size (independent of density) and not larger.  The minimum
+        layout size for this screen configuration is approximately 320x470 dp units.  Examples
         of such screens a WQVGA low density, HVGA medium density, WVGA
         high density.</li>
         <li>{@code large}: Screens based on the space available on a
         medium-density VGA screen.  Such a screen has significantly more
         available space in both width and height than an HVGA display.
+        The minimum layout size for this screen configuration is approximately 480x640 dp units.
         Examples are VGA and WVGA medium density screens.</li>
         <li>{@code xlarge}: Screens that are considerably larger than the traditional
-        medium-density HVGA screen. In most cases, devices with extra large screens would be too
-large to carry in a pocket and would most likely be tablet-style devices. <em>Added in API Level
-9.</em></li>
+        medium-density HVGA screen. The minimum layout size for this screen configuration
+        is approximately 720x960 dp units.  In most cases, devices with extra large
+        screens would be too large to carry in a pocket and would most likely
+        be tablet-style devices. <em>Added in API Level 9.</em></li>
         </ul>
         <p><em>Added in API Level 4.</em></p>
         <p>See <a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 96eb936..0949beb 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -1534,6 +1534,48 @@
     }
 
     /**
+     * Convenience overload that takes a char array instead of a
+     * String.
+     *
+     * @see #getTextRunAdvances(String, int, int, int, int, int, float[], int)
+     * @hide
+     */
+    public float getTextRunAdvancesICU(char[] chars, int index, int count,
+            int contextIndex, int contextCount, int flags, float[] advances,
+            int advancesIndex) {
+
+        if ((index | count | contextIndex | contextCount | advancesIndex
+                | (index - contextIndex)
+                | ((contextIndex + contextCount) - (index + count))
+                | (chars.length - (contextIndex + contextCount))
+                | (advances == null ? 0 :
+                    (advances.length - (advancesIndex + count)))) < 0) {
+            throw new IndexOutOfBoundsException();
+        }
+        if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) {
+            throw new IllegalArgumentException("unknown flags value: " + flags);
+        }
+
+        if (!mHasCompatScaling) {
+            return native_getTextRunAdvancesICU(mNativePaint, chars, index, count,
+                    contextIndex, contextCount, flags, advances, advancesIndex);
+        }
+
+        final float oldSize = getTextSize();
+        setTextSize(oldSize * mCompatScaling);
+        float res = native_getTextRunAdvancesICU(mNativePaint, chars, index, count,
+                contextIndex, contextCount, flags, advances, advancesIndex);
+        setTextSize(oldSize);
+
+        if (advances != null) {
+            for (int i = advancesIndex, e = i + count; i < e; i++) {
+                advances[i] *= mInvCompatScaling;
+            }
+        }
+        return res * mInvCompatScaling; // assume errors are not significant
+    }
+
+    /**
      * Convenience overload that takes a CharSequence instead of a
      * String.
      *
@@ -1569,6 +1611,41 @@
     }
 
     /**
+     * Convenience overload that takes a CharSequence instead of a
+     * String.
+     *
+     * @see #getTextRunAdvances(String, int, int, int, int, int, float[], int)
+     * @hide
+     */
+    public float getTextRunAdvancesICU(CharSequence text, int start, int end,
+            int contextStart, int contextEnd, int flags, float[] advances,
+            int advancesIndex) {
+
+        if (text instanceof String) {
+            return getTextRunAdvancesICU((String) text, start, end,
+                    contextStart, contextEnd, flags, advances, advancesIndex);
+        }
+        if (text instanceof SpannedString ||
+            text instanceof SpannableString) {
+            return getTextRunAdvancesICU(text.toString(), start, end,
+                    contextStart, contextEnd, flags, advances, advancesIndex);
+        }
+        if (text instanceof GraphicsOperations) {
+            return ((GraphicsOperations) text).getTextRunAdvancesICU(start, end,
+                    contextStart, contextEnd, flags, advances, advancesIndex, this);
+        }
+
+        int contextLen = contextEnd - contextStart;
+        int len = end - start;
+        char[] buf = TemporaryBuffer.obtain(contextLen);
+        TextUtils.getChars(text, start, end, buf, 0);
+        float result = getTextRunAdvancesICU(buf, start - contextStart, len,
+                0, contextLen, flags, advances, advancesIndex);
+        TemporaryBuffer.recycle(buf);
+        return result;
+    }
+
+    /**
      * Returns the total advance width for the characters in the run
      * between start and end, and if advances is not null, the advance
      * assigned to each of these characters (java chars).
@@ -1644,6 +1721,44 @@
     }
 
     /**
+     * Temporary - DO NOT USE
+     *
+     * @hide
+     */
+    public float getTextRunAdvancesICU(String text, int start, int end, int contextStart,
+            int contextEnd, int flags, float[] advances, int advancesIndex) {
+
+        if ((start | end | contextStart | contextEnd | advancesIndex | (end - start)
+                | (start - contextStart) | (contextEnd - end)
+                | (text.length() - contextEnd)
+                | (advances == null ? 0 :
+                    (advances.length - advancesIndex - (end - start)))) < 0) {
+            throw new IndexOutOfBoundsException();
+        }
+        if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) {
+            throw new IllegalArgumentException("unknown flags value: " + flags);
+        }
+
+        if (!mHasCompatScaling) {
+            return native_getTextRunAdvancesICU(mNativePaint, text, start, end,
+                    contextStart, contextEnd, flags, advances, advancesIndex);
+        }
+
+        final float oldSize = getTextSize();
+        setTextSize(oldSize * mCompatScaling);
+        float totalAdvance = native_getTextRunAdvances(mNativePaint, text, start, end,
+                contextStart, contextEnd, flags, advances, advancesIndex);
+        setTextSize(oldSize);
+
+        if (advances != null) {
+            for (int i = advancesIndex, e = i + (end - start); i < e; i++) {
+                advances[i] *= mInvCompatScaling;
+            }
+        }
+        return totalAdvance * mInvCompatScaling; // assume errors are insignificant
+    }
+
+    /**
      * Returns the next cursor position in the run.  This avoids placing the
      * cursor between surrogates, between characters that form conjuncts,
      * between base characters and combining marks, or within a reordering
@@ -1907,6 +2022,13 @@
             String text, int start, int end, int contextStart, int contextEnd,
             int flags, float[] advances, int advancesIndex);
 
+    private static native float native_getTextRunAdvancesICU(int native_object,
+            char[] text, int index, int count, int contextIndex, int contextCount,
+            int flags, float[] advances, int advancesIndex);
+    private static native float native_getTextRunAdvancesICU(int native_object,
+            String text, int start, int end, int contextStart, int contextEnd,
+            int flags, float[] advances, int advancesIndex);
+
     private native int native_getTextRunCursor(int native_object, char[] text,
             int contextStart, int contextLength, int flags, int offset, int cursorOpt);
     private native int native_getTextRunCursor(int native_object, String text,
diff --git a/include/media/stagefright/DataSource.h b/include/media/stagefright/DataSource.h
index d30e908..6b6fcdf 100644
--- a/include/media/stagefright/DataSource.h
+++ b/include/media/stagefright/DataSource.h
@@ -84,6 +84,8 @@
         return String8();
     }
 
+    virtual String8 getMIMEType() const;
+
 protected:
     virtual ~DataSource() {}
 
diff --git a/include/media/stagefright/MediaDefs.h b/include/media/stagefright/MediaDefs.h
index 66dfff6..6a21627 100644
--- a/include/media/stagefright/MediaDefs.h
+++ b/include/media/stagefright/MediaDefs.h
@@ -45,6 +45,7 @@
 extern const char *MEDIA_MIMETYPE_CONTAINER_OGG;
 extern const char *MEDIA_MIMETYPE_CONTAINER_MATROSKA;
 extern const char *MEDIA_MIMETYPE_CONTAINER_MPEG2TS;
+extern const char *MEDIA_MIMETYPE_CONTAINER_AVI;
 
 extern const char *MEDIA_MIMETYPE_CONTAINER_WVM;
 
diff --git a/include/ui/egl/android_natives.h b/include/ui/egl/android_natives.h
index 972e799..0a6e4fb 100644
--- a/include/ui/egl/android_natives.h
+++ b/include/ui/egl/android_natives.h
@@ -291,6 +291,9 @@
     void* reserved_proc[2];
 };
 
+// Backwards compatibility...  please switch to ANativeWindow.
+typedef struct ANativeWindow android_native_window_t;
+
 /*
  *  native_window_set_usage(..., usage)
  *  Sets the intended usage flags for the next buffers
diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java
index c41e0ad..352579a 100644
--- a/media/java/android/media/MediaFile.java
+++ b/media/java/android/media/MediaFile.java
@@ -66,8 +66,9 @@
     public static final int FILE_TYPE_ASF     = 26;
     public static final int FILE_TYPE_MKV     = 27;
     public static final int FILE_TYPE_MP2TS   = 28;
+    public static final int FILE_TYPE_AVI     = 29;
     private static final int FIRST_VIDEO_FILE_TYPE = FILE_TYPE_MP4;
-    private static final int LAST_VIDEO_FILE_TYPE = FILE_TYPE_MP2TS;
+    private static final int LAST_VIDEO_FILE_TYPE = FILE_TYPE_AVI;
     
     // Image file types
     public static final int FILE_TYPE_JPEG    = 31;
@@ -198,6 +199,7 @@
         addFileType("MKV", FILE_TYPE_MKV, "video/x-matroska");
         addFileType("WEBM", FILE_TYPE_MKV, "video/x-matroska");
         addFileType("TS", FILE_TYPE_MP2TS, "video/mp2ts");
+        addFileType("AVI", FILE_TYPE_AVI, "video/avi");
 
         if (isWMVEnabled()) {
             addFileType("WMV", FILE_TYPE_WMV, "video/x-ms-wmv", MtpConstants.FORMAT_WMV);
diff --git a/media/java/android/media/ThumbnailUtils.java b/media/java/android/media/ThumbnailUtils.java
index 7fdf448..7c181ee 100644
--- a/media/java/android/media/ThumbnailUtils.java
+++ b/media/java/android/media/ThumbnailUtils.java
@@ -83,7 +83,7 @@
      *
      * @param filePath the path of image file
      * @param kind could be MINI_KIND or MICRO_KIND
-     * @return Bitmap
+     * @return Bitmap, or null on failures
      *
      * @hide This method is only used by media framework and media provider internally.
      */
@@ -123,6 +123,8 @@
                 bitmap = BitmapFactory.decodeFileDescriptor(fd, null, options);
             } catch (IOException ex) {
                 Log.e(TAG, "", ex);
+            } catch (OutOfMemoryError oom) {
+                Log.e(TAG, "Unable to decode file " + filePath + ". OutOfMemoryError.", oom);
             }
         }
 
diff --git a/media/java/android/mtp/MtpDevice.java b/media/java/android/mtp/MtpDevice.java
index af37c9e..47bb8c9 100644
--- a/media/java/android/mtp/MtpDevice.java
+++ b/media/java/android/mtp/MtpDevice.java
@@ -61,7 +61,9 @@
     }
 
     /**
-     * Closes all resources related to the MtpDevice object
+     * Closes all resources related to the MtpDevice object.
+     * After this is called, the object can not be used until {@link #open} is called again
+     * with a new {@link android.hardware.usb.UsbDeviceConnection}.
      */
     public void close() {
         native_close();
@@ -78,6 +80,8 @@
 
     /**
      * Returns the name of the USB device
+     * This returns the same value as {@link android.hardware.usb.UsbDevice#getDeviceName}
+     * for the device's {@link android.hardware.usb.UsbDevice}
      *
      * @return the device name
      */
@@ -86,7 +90,9 @@
     }
 
     /**
-     * Returns the ID of the USB device
+     * Returns the USB ID of the USB device.
+     * This returns the same value as {@link android.hardware.usb.UsbDevice#getDeviceId}
+     * for the device's {@link android.hardware.usb.UsbDevice}
      *
      * @return the device ID
      */
@@ -100,7 +106,7 @@
     }
 
     /**
-     * Returns the {@link android.mtp.MtpDeviceInfo} for this device
+     * Returns the {@link MtpDeviceInfo} for this device
      *
      * @return the device info
      */
@@ -110,8 +116,9 @@
 
     /**
      * Returns the list of IDs for all storage units on this device
+     * Information about each storage unit can be accessed via {@link #getStorageInfo}.
      *
-     * @return the storage IDs
+     * @return the list of storage IDs
      */
     public int[] getStorageIds() {
         return native_get_storage_ids();
@@ -120,6 +127,7 @@
     /**
      * Returns the list of object handles for all objects on the given storage unit,
      * with the given format and parent.
+     * Information about each object can be accessed via {@link #getObjectInfo}.
      *
      * @param storageId the storage unit to query
      * @param format the format of the object to return, or zero for all formats
@@ -132,10 +140,12 @@
 
     /**
      * Returns the data for an object as a byte array.
+     * This call may block for an arbitrary amount of time depending on the size
+     * of the data and speed of the devices.
      *
      * @param objectHandle handle of the object to read
      * @param objectSize the size of the object (this should match
-     *      {@link android.mtp.MtpObjectInfo#getCompressedSize}
+     *      {@link MtpObjectInfo#getCompressedSize}
      * @return the object's data, or null if reading fails
      */
     public byte[] getObject(int objectHandle, int objectSize) {
@@ -144,6 +154,10 @@
 
     /**
      * Returns the thumbnail data for an object as a byte array.
+     * The size and format of the thumbnail data can be determined via
+     * {@link MtpObjectInfo#getThumbCompressedSize} and
+     * {@link MtpObjectInfo#getThumbFormat}.
+     * For typical devices the format is JPEG.
      *
      * @param objectHandle handle of the object to read
      * @return the object's thumbnail, or null if reading fails
@@ -153,7 +167,7 @@
     }
 
     /**
-     * Retrieves the {@link android.mtp.MtpStorageInfo} for a storage unit.
+     * Retrieves the {@link MtpStorageInfo} for a storage unit.
      *
      * @param storageId the ID of the storage unit
      * @return the MtpStorageInfo
@@ -163,7 +177,7 @@
     }
 
     /**
-     * Retrieves the {@link android.mtp.MtpObjectInfo} for an object.
+     * Retrieves the {@link MtpObjectInfo} for an object.
      *
      * @param objectHandle the handle of the object
      * @return the MtpObjectInfo
@@ -173,7 +187,9 @@
     }
 
     /**
-     * Deletes an object on the device.
+     * Deletes an object on the device.  This call may block, since
+     * deleting a directory containing many files may take a long time
+     * on some devices.
      *
      * @param objectHandle handle of the object to delete
      * @return true if the deletion succeeds
@@ -204,6 +220,8 @@
 
     /**
      * Copies the data for an object to a file in external storage.
+     * This call may block for an arbitrary amount of time depending on the size
+     * of the data and speed of the devices.
      *
      * @param objectHandle handle of the object to read
      * @param destPath path to destination for the file transfer.
diff --git a/media/java/android/mtp/MtpStorageInfo.java b/media/java/android/mtp/MtpStorageInfo.java
index 09736a8..d1b86fc 100644
--- a/media/java/android/mtp/MtpStorageInfo.java
+++ b/media/java/android/mtp/MtpStorageInfo.java
@@ -34,7 +34,8 @@
     }
 
     /**
-     * Returns the storage ID for the storage unit
+     * Returns the storage ID for the storage unit.
+     * The storage ID uniquely identifies the storage unit on the MTP device.
      *
      * @return the storage ID
      */
@@ -61,7 +62,9 @@
     }
 
    /**
-     * Returns the description string for the storage unit
+     * Returns the description string for the storage unit.
+     * This is typically displayed to the user in the user interface on the
+     * MTP host.
      *
      * @return the storage unit description
      */
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 346d0bb..9928f44 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -1081,8 +1081,8 @@
                 android_native_rect_t crop;
                 crop.left = rect.nLeft;
                 crop.top = rect.nTop;
-                crop.right = rect.nLeft + rect.nWidth - 1;
-                crop.bottom = rect.nTop + rect.nHeight - 1;
+                crop.right = rect.nLeft + rect.nWidth;
+                crop.bottom = rect.nTop + rect.nHeight;
 
                 CHECK_EQ(0, native_window_set_crop(
                             mNativeWindow.get(), &crop));
diff --git a/media/libstagefright/AVIExtractor.cpp b/media/libstagefright/AVIExtractor.cpp
new file mode 100644
index 0000000..6313ca3
--- /dev/null
+++ b/media/libstagefright/AVIExtractor.cpp
@@ -0,0 +1,922 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "AVIExtractor"
+#include <utils/Log.h>
+
+#include "include/AVIExtractor.h"
+
+#include <binder/ProcessState.h>
+#include <media/stagefright/foundation/hexdump.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
+
+namespace android {
+
+struct AVIExtractor::AVISource : public MediaSource {
+    AVISource(const sp<AVIExtractor> &extractor, size_t trackIndex);
+
+    virtual status_t start(MetaData *params);
+    virtual status_t stop();
+
+    virtual sp<MetaData> getFormat();
+
+    virtual status_t read(
+            MediaBuffer **buffer, const ReadOptions *options);
+
+protected:
+    virtual ~AVISource();
+
+private:
+    sp<AVIExtractor> mExtractor;
+    size_t mTrackIndex;
+    const AVIExtractor::Track &mTrack;
+    MediaBufferGroup *mBufferGroup;
+    size_t mSampleIndex;
+
+    DISALLOW_EVIL_CONSTRUCTORS(AVISource);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+AVIExtractor::AVISource::AVISource(
+        const sp<AVIExtractor> &extractor, size_t trackIndex)
+    : mExtractor(extractor),
+      mTrackIndex(trackIndex),
+      mTrack(mExtractor->mTracks.itemAt(trackIndex)),
+      mBufferGroup(NULL) {
+}
+
+AVIExtractor::AVISource::~AVISource() {
+    if (mBufferGroup) {
+        stop();
+    }
+}
+
+status_t AVIExtractor::AVISource::start(MetaData *params) {
+    CHECK(!mBufferGroup);
+
+    mBufferGroup = new MediaBufferGroup;
+
+    mBufferGroup->add_buffer(new MediaBuffer(mTrack.mMaxSampleSize));
+    mBufferGroup->add_buffer(new MediaBuffer(mTrack.mMaxSampleSize));
+    mSampleIndex = 0;
+
+    return OK;
+}
+
+status_t AVIExtractor::AVISource::stop() {
+    CHECK(mBufferGroup);
+
+    delete mBufferGroup;
+    mBufferGroup = NULL;
+
+    return OK;
+}
+
+sp<MetaData> AVIExtractor::AVISource::getFormat() {
+    return mTrack.mMeta;
+}
+
+status_t AVIExtractor::AVISource::read(
+        MediaBuffer **buffer, const ReadOptions *options) {
+    CHECK(mBufferGroup);
+
+    *buffer = NULL;
+
+    int64_t seekTimeUs;
+    ReadOptions::SeekMode seekMode;
+    if (options && options->getSeekTo(&seekTimeUs, &seekMode)) {
+        status_t err =
+            mExtractor->getSampleIndexAtTime(
+                    mTrackIndex, seekTimeUs, seekMode, &mSampleIndex);
+
+        if (err != OK) {
+            return ERROR_END_OF_STREAM;
+        }
+    }
+
+    int64_t timeUs =
+        (mSampleIndex * 1000000ll * mTrack.mRate) / mTrack.mScale;
+
+    off64_t offset;
+    size_t size;
+    bool isKey;
+    status_t err = mExtractor->getSampleInfo(
+            mTrackIndex, mSampleIndex, &offset, &size, &isKey);
+
+    ++mSampleIndex;
+
+    if (err != OK) {
+        return ERROR_END_OF_STREAM;
+    }
+
+    MediaBuffer *out;
+    CHECK_EQ(mBufferGroup->acquire_buffer(&out), (status_t)OK);
+
+    ssize_t n = mExtractor->mDataSource->readAt(offset, out->data(), size);
+
+    if (n < (ssize_t)size) {
+        return n < 0 ? (status_t)n : (status_t)ERROR_MALFORMED;
+    }
+
+    out->set_range(0, size);
+
+    out->meta_data()->setInt64(kKeyTime, timeUs);
+
+    if (isKey) {
+        out->meta_data()->setInt32(kKeyIsSyncFrame, 1);
+    }
+
+    *buffer = out;
+
+    return OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+AVIExtractor::AVIExtractor(const sp<DataSource> &dataSource)
+    : mDataSource(dataSource) {
+    mInitCheck = parseHeaders();
+
+    if (mInitCheck != OK) {
+        mTracks.clear();
+    }
+}
+
+AVIExtractor::~AVIExtractor() {
+}
+
+size_t AVIExtractor::countTracks() {
+    return mTracks.size();
+}
+
+sp<MediaSource> AVIExtractor::getTrack(size_t index) {
+    return index < mTracks.size() ? new AVISource(this, index) : NULL;
+}
+
+sp<MetaData> AVIExtractor::getTrackMetaData(
+        size_t index, uint32_t flags) {
+    return index < mTracks.size() ? mTracks.editItemAt(index).mMeta : NULL;
+}
+
+sp<MetaData> AVIExtractor::getMetaData() {
+    sp<MetaData> meta = new MetaData;
+
+    if (mInitCheck == OK) {
+        meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_AVI);
+    }
+
+    return meta;
+}
+
+status_t AVIExtractor::parseHeaders() {
+    mTracks.clear();
+    mMovieOffset = 0;
+    mFoundIndex = false;
+    mOffsetsAreAbsolute = false;
+
+    ssize_t res = parseChunk(0ll, -1ll);
+
+    if (res < 0) {
+        return (status_t)res;
+    }
+
+    if (mMovieOffset == 0ll || !mFoundIndex) {
+        return ERROR_MALFORMED;
+    }
+
+    return OK;
+}
+
+ssize_t AVIExtractor::parseChunk(off64_t offset, off64_t size, int depth) {
+    if (size >= 0 && size < 8) {
+        return ERROR_MALFORMED;
+    }
+
+    uint8_t tmp[12];
+    ssize_t n = mDataSource->readAt(offset, tmp, 8);
+
+    if (n < 8) {
+        return (n < 0) ? n : (ssize_t)ERROR_MALFORMED;
+    }
+
+    uint32_t fourcc = U32_AT(tmp);
+    uint32_t chunkSize = U32LE_AT(&tmp[4]);
+
+    if (size >= 0 && chunkSize + 8 > size) {
+        return ERROR_MALFORMED;
+    }
+
+    static const char kPrefix[] = "                              ";
+    const char *prefix = &kPrefix[strlen(kPrefix) - 2 * depth];
+
+    if (fourcc == FOURCC('L', 'I', 'S', 'T')
+            || fourcc == FOURCC('R', 'I', 'F', 'F')) {
+        // It's a list of chunks
+
+        if (size >= 0 && size < 12) {
+            return ERROR_MALFORMED;
+        }
+
+        n = mDataSource->readAt(offset + 8, &tmp[8], 4);
+
+        if (n < 4) {
+            return (n < 0) ? n : (ssize_t)ERROR_MALFORMED;
+        }
+
+        uint32_t subFourcc = U32_AT(&tmp[8]);
+
+        LOGV("%s offset 0x%08llx LIST of '%c%c%c%c', size %d",
+             prefix,
+             offset,
+             (char)(subFourcc >> 24),
+             (char)((subFourcc >> 16) & 0xff),
+             (char)((subFourcc >> 8) & 0xff),
+             (char)(subFourcc & 0xff),
+             chunkSize - 4);
+
+        if (subFourcc == FOURCC('m', 'o', 'v', 'i')) {
+            // We're not going to parse this, but will take note of the
+            // offset.
+
+            mMovieOffset = offset;
+        } else {
+            off64_t subOffset = offset + 12;
+            off64_t subOffsetLimit = subOffset + chunkSize - 4;
+            while (subOffset < subOffsetLimit) {
+                ssize_t res =
+                    parseChunk(subOffset, subOffsetLimit - subOffset, depth + 1);
+
+                if (res < 0) {
+                    return res;
+                }
+
+                subOffset += res;
+            }
+        }
+    } else {
+        LOGV("%s offset 0x%08llx CHUNK '%c%c%c%c'",
+             prefix,
+             offset,
+             (char)(fourcc >> 24),
+             (char)((fourcc >> 16) & 0xff),
+             (char)((fourcc >> 8) & 0xff),
+             (char)(fourcc & 0xff));
+
+        status_t err = OK;
+
+        switch (fourcc) {
+            case FOURCC('s', 't', 'r', 'h'):
+            {
+                err = parseStreamHeader(offset + 8, chunkSize);
+                break;
+            }
+
+            case FOURCC('s', 't', 'r', 'f'):
+            {
+                err = parseStreamFormat(offset + 8, chunkSize);
+                break;
+            }
+
+            case FOURCC('i', 'd', 'x', '1'):
+            {
+                err = parseIndex(offset + 8, chunkSize);
+                break;
+            }
+
+            default:
+                break;
+        }
+
+        if (err != OK) {
+            return err;
+        }
+    }
+
+    if (chunkSize & 1) {
+        ++chunkSize;
+    }
+
+    return chunkSize + 8;
+}
+
+static const char *GetMIMETypeForHandler(uint32_t handler) {
+    switch (handler) {
+        // Wow... shamelessly copied from
+        // http://wiki.multimedia.cx/index.php?title=ISO_MPEG-4
+
+        case FOURCC('3', 'I', 'V', '2'):
+        case FOURCC('3', 'i', 'v', '2'):
+        case FOURCC('B', 'L', 'Z', '0'):
+        case FOURCC('D', 'I', 'G', 'I'):
+        case FOURCC('D', 'I', 'V', '1'):
+        case FOURCC('d', 'i', 'v', '1'):
+        case FOURCC('D', 'I', 'V', 'X'):
+        case FOURCC('d', 'i', 'v', 'x'):
+        case FOURCC('D', 'X', '5', '0'):
+        case FOURCC('d', 'x', '5', '0'):
+        case FOURCC('D', 'X', 'G', 'M'):
+        case FOURCC('E', 'M', '4', 'A'):
+        case FOURCC('E', 'P', 'H', 'V'):
+        case FOURCC('F', 'M', 'P', '4'):
+        case FOURCC('f', 'm', 'p', '4'):
+        case FOURCC('F', 'V', 'F', 'W'):
+        case FOURCC('H', 'D', 'X', '4'):
+        case FOURCC('h', 'd', 'x', '4'):
+        case FOURCC('M', '4', 'C', 'C'):
+        case FOURCC('M', '4', 'S', '2'):
+        case FOURCC('m', '4', 's', '2'):
+        case FOURCC('M', 'P', '4', 'S'):
+        case FOURCC('m', 'p', '4', 's'):
+        case FOURCC('M', 'P', '4', 'V'):
+        case FOURCC('m', 'p', '4', 'v'):
+        case FOURCC('M', 'V', 'X', 'M'):
+        case FOURCC('R', 'M', 'P', '4'):
+        case FOURCC('S', 'E', 'D', 'G'):
+        case FOURCC('S', 'M', 'P', '4'):
+        case FOURCC('U', 'M', 'P', '4'):
+        case FOURCC('W', 'V', '1', 'F'):
+        case FOURCC('X', 'V', 'I', 'D'):
+        case FOURCC('X', 'v', 'i', 'D'):
+        case FOURCC('x', 'v', 'i', 'd'):
+        case FOURCC('X', 'V', 'I', 'X'):
+            return MEDIA_MIMETYPE_VIDEO_MPEG4;
+
+        default:
+            return NULL;
+    }
+}
+
+status_t AVIExtractor::parseStreamHeader(off64_t offset, size_t size) {
+    if (size != 56) {
+        return ERROR_MALFORMED;
+    }
+
+    if (mTracks.size() > 99) {
+        return -ERANGE;
+    }
+
+    sp<ABuffer> buffer = new ABuffer(size);
+    ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size());
+
+    if (n < (ssize_t)size) {
+        return n < 0 ? (status_t)n : ERROR_MALFORMED;
+    }
+
+    const uint8_t *data = buffer->data();
+
+    uint32_t type = U32_AT(data);
+    uint32_t handler = U32_AT(&data[4]);
+    uint32_t flags = U32LE_AT(&data[8]);
+
+    sp<MetaData> meta = new MetaData;
+
+    uint32_t rate = U32LE_AT(&data[20]);
+    uint32_t scale = U32LE_AT(&data[24]);
+
+    const char *mime = NULL;
+    Track::Kind kind = Track::OTHER;
+
+    if (type == FOURCC('v', 'i', 'd', 's')) {
+        mime = GetMIMETypeForHandler(handler);
+
+        if (mime && strncasecmp(mime, "video/", 6)) {
+            return ERROR_MALFORMED;
+        }
+
+        kind = Track::VIDEO;
+    } else if (type == FOURCC('a', 'u', 'd', 's')) {
+        if (mime && strncasecmp(mime, "audio/", 6)) {
+            return ERROR_MALFORMED;
+        }
+
+        kind = Track::AUDIO;
+    }
+
+    if (!mime) {
+        mime = "application/octet-stream";
+    }
+
+    meta->setCString(kKeyMIMEType, mime);
+
+    mTracks.push();
+    Track *track = &mTracks.editItemAt(mTracks.size() - 1);
+
+    track->mMeta = meta;
+    track->mRate = rate;
+    track->mScale = scale;
+    track->mKind = kind;
+    track->mNumSyncSamples = 0;
+    track->mThumbnailSampleSize = 0;
+    track->mThumbnailSampleIndex = -1;
+    track->mMaxSampleSize = 0;
+
+    return OK;
+}
+
+status_t AVIExtractor::parseStreamFormat(off64_t offset, size_t size) {
+    if (mTracks.isEmpty()) {
+        return ERROR_MALFORMED;
+    }
+
+    Track *track = &mTracks.editItemAt(mTracks.size() - 1);
+
+    if (track->mKind == Track::OTHER) {
+        // We don't support this content, but that's not a parsing error.
+        return OK;
+    }
+
+    bool isVideo = (track->mKind == Track::VIDEO);
+
+    if ((isVideo && size < 40) || (!isVideo && size < 18)) {
+        // Expected a BITMAPINFO or WAVEFORMATEX structure, respectively.
+        return ERROR_MALFORMED;
+    }
+
+    sp<ABuffer> buffer = new ABuffer(size);
+    ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size());
+
+    if (n < (ssize_t)size) {
+        return n < 0 ? (status_t)n : ERROR_MALFORMED;
+    }
+
+    const uint8_t *data = buffer->data();
+
+    if (isVideo) {
+        uint32_t width = U32LE_AT(&data[4]);
+        uint32_t height = U32LE_AT(&data[8]);
+
+        track->mMeta->setInt32(kKeyWidth, width);
+        track->mMeta->setInt32(kKeyHeight, height);
+    } else {
+        uint32_t format = U16LE_AT(data);
+        if (format == 0x55) {
+            track->mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
+        }
+
+        uint32_t numChannels = U16LE_AT(&data[2]);
+        uint32_t sampleRate = U32LE_AT(&data[4]);
+
+        track->mMeta->setInt32(kKeyChannelCount, numChannels);
+        track->mMeta->setInt32(kKeySampleRate, sampleRate);
+    }
+
+    return OK;
+}
+
+// static
+bool AVIExtractor::IsCorrectChunkType(
+        ssize_t trackIndex, Track::Kind kind, uint32_t chunkType) {
+    uint32_t chunkBase = chunkType & 0xffff;
+
+    switch (kind) {
+        case Track::VIDEO:
+        {
+            if (chunkBase != FOURCC(0, 0, 'd', 'c')
+                    && chunkBase != FOURCC(0, 0, 'd', 'b')) {
+                return false;
+            }
+            break;
+        }
+
+        case Track::AUDIO:
+        {
+            if (chunkBase != FOURCC(0, 0, 'w', 'b')) {
+                return false;
+            }
+            break;
+        }
+
+        default:
+            break;
+    }
+
+    if (trackIndex < 0) {
+        return true;
+    }
+
+    uint8_t hi = chunkType >> 24;
+    uint8_t lo = (chunkType >> 16) & 0xff;
+
+    if (hi < '0' || hi > '9' || lo < '0' || lo > '9') {
+        return false;
+    }
+
+    if (trackIndex != (10 * (hi - '0') + (lo - '0'))) {
+        return false;
+    }
+
+    return true;
+}
+
+status_t AVIExtractor::parseIndex(off64_t offset, size_t size) {
+    if ((size % 16) != 0) {
+        return ERROR_MALFORMED;
+    }
+
+    sp<ABuffer> buffer = new ABuffer(size);
+    ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size());
+
+    if (n < (ssize_t)size) {
+        return n < 0 ? (status_t)n : ERROR_MALFORMED;
+    }
+
+    const uint8_t *data = buffer->data();
+
+    while (size > 0) {
+        uint32_t chunkType = U32_AT(data);
+
+        uint8_t hi = chunkType >> 24;
+        uint8_t lo = (chunkType >> 16) & 0xff;
+
+        if (hi < '0' || hi > '9' || lo < '0' || lo > '9') {
+            return ERROR_MALFORMED;
+        }
+
+        size_t trackIndex = 10 * (hi - '0') + (lo - '0');
+
+        if (trackIndex >= mTracks.size()) {
+            return ERROR_MALFORMED;
+        }
+
+        Track *track = &mTracks.editItemAt(trackIndex);
+
+        if (!IsCorrectChunkType(-1, track->mKind, chunkType)) {
+            return ERROR_MALFORMED;
+        }
+
+        if (track->mKind == Track::OTHER) {
+            data += 16;
+            size -= 16;
+            continue;
+        }
+
+        uint32_t flags = U32LE_AT(&data[4]);
+        uint32_t offset = U32LE_AT(&data[8]);
+        uint32_t chunkSize = U32LE_AT(&data[12]);
+
+        if (chunkSize > track->mMaxSampleSize) {
+            track->mMaxSampleSize = chunkSize;
+        }
+
+        track->mSamples.push();
+
+        SampleInfo *info =
+            &track->mSamples.editItemAt(track->mSamples.size() - 1);
+
+        info->mOffset = offset;
+        info->mIsKey = (flags & 0x10) != 0;
+
+        if (info->mIsKey) {
+            static const size_t kMaxNumSyncSamplesToScan = 20;
+
+            if (track->mNumSyncSamples < kMaxNumSyncSamplesToScan) {
+                if (chunkSize > track->mThumbnailSampleSize) {
+                    track->mThumbnailSampleSize = chunkSize;
+
+                    track->mThumbnailSampleIndex =
+                        track->mSamples.size() - 1;
+                }
+            }
+
+            ++track->mNumSyncSamples;
+        }
+
+        data += 16;
+        size -= 16;
+    }
+
+    if (!mTracks.isEmpty()) {
+        off64_t offset;
+        size_t size;
+        bool isKey;
+        status_t err = getSampleInfo(0, 0, &offset, &size, &isKey);
+
+        if (err != OK) {
+            mOffsetsAreAbsolute = !mOffsetsAreAbsolute;
+            err = getSampleInfo(0, 0, &offset, &size, &isKey);
+
+            if (err != OK) {
+                return err;
+            }
+        }
+
+        LOGV("Chunk offsets are %s",
+             mOffsetsAreAbsolute ? "absolute" : "movie-chunk relative");
+    }
+
+    for (size_t i = 0; i < mTracks.size(); ++i) {
+        Track *track = &mTracks.editItemAt(i);
+
+        int64_t durationUs =
+            (track->mSamples.size() * 1000000ll * track->mRate) / track->mScale;
+
+        LOGV("track %d duration = %.2f secs", i, durationUs / 1E6);
+
+        track->mMeta->setInt64(kKeyDuration, durationUs);
+        track->mMeta->setInt32(kKeyMaxInputSize, track->mMaxSampleSize);
+
+        const char *tmp;
+        CHECK(track->mMeta->findCString(kKeyMIMEType, &tmp));
+
+        AString mime = tmp;
+
+        if (!strncasecmp("video/", mime.c_str(), 6)
+                && track->mThumbnailSampleIndex >= 0) {
+            int64_t thumbnailTimeUs =
+                (track->mThumbnailSampleIndex * 1000000ll * track->mRate)
+                    / track->mScale;
+
+            track->mMeta->setInt64(kKeyThumbnailTime, thumbnailTimeUs);
+
+            if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_VIDEO_MPEG4)) {
+                status_t err = addMPEG4CodecSpecificData(i);
+
+                if (err != OK) {
+                    return err;
+                }
+            }
+        }
+    }
+
+    mFoundIndex = true;
+
+    return OK;
+}
+
+static size_t GetSizeWidth(size_t x) {
+    size_t n = 1;
+    while (x > 127) {
+        ++n;
+        x >>= 7;
+    }
+    return n;
+}
+
+static uint8_t *EncodeSize(uint8_t *dst, size_t x) {
+    while (x > 127) {
+        *dst++ = (x & 0x7f) | 0x80;
+        x >>= 7;
+    }
+    *dst++ = x;
+    return dst;
+}
+
+sp<ABuffer> MakeMPEG4VideoCodecSpecificData(const sp<ABuffer> &config) {
+    size_t len1 = config->size() + GetSizeWidth(config->size()) + 1;
+    size_t len2 = len1 + GetSizeWidth(len1) + 1 + 13;
+    size_t len3 = len2 + GetSizeWidth(len2) + 1 + 3;
+
+    sp<ABuffer> csd = new ABuffer(len3);
+    uint8_t *dst = csd->data();
+    *dst++ = 0x03;
+    dst = EncodeSize(dst, len2 + 3);
+    *dst++ = 0x00;  // ES_ID
+    *dst++ = 0x00;
+    *dst++ = 0x00;  // streamDependenceFlag, URL_Flag, OCRstreamFlag
+
+    *dst++ = 0x04;
+    dst = EncodeSize(dst, len1 + 13);
+    *dst++ = 0x01;  // Video ISO/IEC 14496-2 Simple Profile
+    for (size_t i = 0; i < 12; ++i) {
+        *dst++ = 0x00;
+    }
+
+    *dst++ = 0x05;
+    dst = EncodeSize(dst, config->size());
+    memcpy(dst, config->data(), config->size());
+    dst += config->size();
+
+    // hexdump(csd->data(), csd->size());
+
+    return csd;
+}
+
+status_t AVIExtractor::addMPEG4CodecSpecificData(size_t trackIndex) {
+    Track *track = &mTracks.editItemAt(trackIndex);
+
+    off64_t offset;
+    size_t size;
+    bool isKey;
+    status_t err = getSampleInfo(trackIndex, 0, &offset, &size, &isKey);
+
+    if (err != OK) {
+        return err;
+    }
+
+    sp<ABuffer> buffer = new ABuffer(size);
+    ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size());
+
+    if (n < (ssize_t)size) {
+        return n < 0 ? (status_t)n : ERROR_MALFORMED;
+    }
+
+    // Extract everything up to the first VOP start code from the first
+    // frame's encoded data and use it to construct an ESDS with the
+    // codec specific data.
+
+    size_t i = 0;
+    bool found = false;
+    while (i + 3 < buffer->size()) {
+        if (!memcmp("\x00\x00\x01\xb6", &buffer->data()[i], 4)) {
+            found = true;
+            break;
+        }
+
+        ++i;
+    }
+
+    if (!found) {
+        return ERROR_MALFORMED;
+    }
+
+    buffer->setRange(0, i);
+
+    sp<ABuffer> csd = MakeMPEG4VideoCodecSpecificData(buffer);
+    track->mMeta->setData(kKeyESDS, kTypeESDS, csd->data(), csd->size());
+
+    return OK;
+}
+
+status_t AVIExtractor::getSampleInfo(
+        size_t trackIndex, size_t sampleIndex,
+        off64_t *offset, size_t *size, bool *isKey) {
+    if (trackIndex >= mTracks.size()) {
+        return -ERANGE;
+    }
+
+    const Track &track = mTracks.itemAt(trackIndex);
+
+    if (sampleIndex >= track.mSamples.size()) {
+        return -ERANGE;
+    }
+
+    const SampleInfo &info = track.mSamples.itemAt(sampleIndex);
+
+    if (!mOffsetsAreAbsolute) {
+        *offset = info.mOffset + mMovieOffset + 8;
+    } else {
+        *offset = info.mOffset;
+    }
+
+    *size = 0;
+
+    uint8_t tmp[8];
+    ssize_t n = mDataSource->readAt(*offset, tmp, 8);
+
+    if (n < 8) {
+        return n < 0 ? (status_t)n : (status_t)ERROR_MALFORMED;
+    }
+
+    uint32_t chunkType = U32_AT(tmp);
+
+    if (!IsCorrectChunkType(trackIndex, track.mKind, chunkType)) {
+        return ERROR_MALFORMED;
+    }
+
+    *offset += 8;
+    *size = U32LE_AT(&tmp[4]);
+
+    *isKey = info.mIsKey;
+
+    return OK;
+}
+
+status_t AVIExtractor::getSampleIndexAtTime(
+        size_t trackIndex,
+        int64_t timeUs, MediaSource::ReadOptions::SeekMode mode,
+        size_t *sampleIndex) const {
+    if (trackIndex >= mTracks.size()) {
+        return -ERANGE;
+    }
+
+    const Track &track = mTracks.itemAt(trackIndex);
+
+    ssize_t closestSampleIndex =
+        timeUs / track.mRate * track.mScale / 1000000ll;
+
+    ssize_t numSamples = track.mSamples.size();
+
+    if (closestSampleIndex < 0) {
+        closestSampleIndex = 0;
+    } else if (closestSampleIndex >= numSamples) {
+        closestSampleIndex = numSamples - 1;
+    }
+
+    if (mode == MediaSource::ReadOptions::SEEK_CLOSEST) {
+        *sampleIndex = closestSampleIndex;
+
+        return OK;
+    }
+
+    ssize_t prevSyncSampleIndex = closestSampleIndex;
+    while (prevSyncSampleIndex >= 0) {
+        const SampleInfo &info =
+            track.mSamples.itemAt(prevSyncSampleIndex);
+
+        if (info.mIsKey) {
+            break;
+        }
+
+        --prevSyncSampleIndex;
+    }
+
+    ssize_t nextSyncSampleIndex = closestSampleIndex;
+    while (nextSyncSampleIndex < numSamples) {
+        const SampleInfo &info =
+            track.mSamples.itemAt(nextSyncSampleIndex);
+
+        if (info.mIsKey) {
+            break;
+        }
+
+        ++nextSyncSampleIndex;
+    }
+
+    switch (mode) {
+        case MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC:
+        {
+            *sampleIndex = prevSyncSampleIndex;
+
+            return prevSyncSampleIndex >= 0 ? OK : UNKNOWN_ERROR;
+        }
+
+        case MediaSource::ReadOptions::SEEK_NEXT_SYNC:
+        {
+            *sampleIndex = nextSyncSampleIndex;
+
+            return nextSyncSampleIndex < numSamples ? OK : UNKNOWN_ERROR;
+        }
+
+        case MediaSource::ReadOptions::SEEK_CLOSEST_SYNC:
+        {
+            if (prevSyncSampleIndex < 0 && nextSyncSampleIndex >= numSamples) {
+                return UNKNOWN_ERROR;
+            }
+
+            if (prevSyncSampleIndex < 0) {
+                *sampleIndex = nextSyncSampleIndex;
+                return OK;
+            }
+
+            if (nextSyncSampleIndex >= numSamples) {
+                *sampleIndex = prevSyncSampleIndex;
+                return OK;
+            }
+
+            size_t dist1 = closestSampleIndex - prevSyncSampleIndex;
+            size_t dist2 = nextSyncSampleIndex - closestSampleIndex;
+
+            *sampleIndex =
+                (dist1 < dist2) ? prevSyncSampleIndex : nextSyncSampleIndex;
+
+            return OK;
+        }
+
+        default:
+            TRESPASS();
+            break;
+    }
+}
+
+bool SniffAVI(
+        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+        sp<AMessage> *) {
+    char tmp[12];
+    if (source->readAt(0, tmp, 12) < 12) {
+        return false;
+    }
+
+    if (!memcmp(tmp, "RIFF", 4) && !memcmp(&tmp[8], "AVI ", 4)) {
+        mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_AVI);
+        *confidence = 0.2;
+
+        return true;
+    }
+
+    return false;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index d2e8b46..2f3e1410 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -8,6 +8,7 @@
         AACExtractor.cpp                  \
         AMRExtractor.cpp                  \
         AMRWriter.cpp                     \
+        AVIExtractor.cpp                  \
         AudioPlayer.cpp                   \
         AudioSource.cpp                   \
         AwesomePlayer.cpp                 \
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 7940de0..6b0b1b9 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define DEBUG_HDCP
+#undef DEBUG_HDCP
 
 //#define LOG_NDEBUG 0
 #define LOG_TAG "AwesomePlayer"
@@ -1693,29 +1693,37 @@
 
         dataSource = mCachedSource;
 
-        // We're going to prefill the cache before trying to instantiate
-        // the extractor below, as the latter is an operation that otherwise
-        // could block on the datasource for a significant amount of time.
-        // During that time we'd be unable to abort the preparation phase
-        // without this prefill.
+        String8 contentType = dataSource->getMIMEType();
 
-        mLock.unlock();
+        if (strncasecmp(contentType.string(), "audio/", 6)) {
+            // We're not doing this for streams that appear to be audio-only
+            // streams to ensure that even low bandwidth streams start
+            // playing back fairly instantly.
 
-        for (;;) {
-            status_t finalStatus;
-            size_t cachedDataRemaining =
-                mCachedSource->approxDataRemaining(&finalStatus);
+            // We're going to prefill the cache before trying to instantiate
+            // the extractor below, as the latter is an operation that otherwise
+            // could block on the datasource for a significant amount of time.
+            // During that time we'd be unable to abort the preparation phase
+            // without this prefill.
 
-            if (finalStatus != OK || cachedDataRemaining >= kHighWaterMarkBytes
-                    || (mFlags & PREPARE_CANCELLED)) {
-                break;
+            mLock.unlock();
+
+            for (;;) {
+                status_t finalStatus;
+                size_t cachedDataRemaining =
+                    mCachedSource->approxDataRemaining(&finalStatus);
+
+                if (finalStatus != OK || cachedDataRemaining >= kHighWaterMarkBytes
+                        || (mFlags & PREPARE_CANCELLED)) {
+                    break;
+                }
+
+                usleep(200000);
             }
 
-            usleep(200000);
+            mLock.lock();
         }
 
-        mLock.lock();
-
         if (mFlags & PREPARE_CANCELLED) {
             LOGI("Prepare cancelled while waiting for initial cache fill.");
             return UNKNOWN_ERROR;
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index b5c51f4..c16b3b5 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -15,6 +15,7 @@
  */
 
 #include "include/AMRExtractor.h"
+#include "include/AVIExtractor.h"
 #include "include/MP3Extractor.h"
 #include "include/MPEG4Extractor.h"
 #include "include/WAVExtractor.h"
@@ -111,6 +112,7 @@
     RegisterSniffer(SniffMPEG2TS);
     RegisterSniffer(SniffMP3);
     RegisterSniffer(SniffAAC);
+    RegisterSniffer(SniffAVI);
 
     char value[PROPERTY_VALUE_MAX];
     if (property_get("drm.service.enabled", value, NULL)
@@ -144,4 +146,8 @@
     return source;
 }
 
+String8 DataSource::getMIMEType() const {
+    return String8("application/octet-stream");
+}
+
 }  // namespace android
diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp
index 0be7261..8ca6ee8 100644
--- a/media/libstagefright/MediaDefs.cpp
+++ b/media/libstagefright/MediaDefs.cpp
@@ -43,6 +43,7 @@
 const char *MEDIA_MIMETYPE_CONTAINER_OGG = "application/ogg";
 const char *MEDIA_MIMETYPE_CONTAINER_MATROSKA = "video/x-matroska";
 const char *MEDIA_MIMETYPE_CONTAINER_MPEG2TS = "video/mp2ts";
+const char *MEDIA_MIMETYPE_CONTAINER_AVI = "video/avi";
 
 const char *MEDIA_MIMETYPE_CONTAINER_WVM = "video/wvm";
 
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index 23bad5b..af0131e 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -19,6 +19,7 @@
 #include <utils/Log.h>
 
 #include "include/AMRExtractor.h"
+#include "include/AVIExtractor.h"
 #include "include/MP3Extractor.h"
 #include "include/MPEG4Extractor.h"
 #include "include/WAVExtractor.h"
@@ -108,6 +109,8 @@
         ret = new MatroskaExtractor(source);
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
         ret = new MPEG2TSExtractor(source);
+    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_AVI)) {
+        ret = new AVIExtractor(source);
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WVM)) {
         ret = new WVMExtractor(source);
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC_ADTS)) {
diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp
index 3c99d1c..c1aa46e 100644
--- a/media/libstagefright/NuCachedSource2.cpp
+++ b/media/libstagefright/NuCachedSource2.cpp
@@ -493,4 +493,8 @@
     return mSource->getUri();
 }
 
+String8 NuCachedSource2::getMIMEType() const {
+    return mSource->getMIMEType();
+}
+
 }  // namespace android
diff --git a/media/libstagefright/NuHTTPDataSource.cpp b/media/libstagefright/NuHTTPDataSource.cpp
index 73daf12..821ba9b 100644
--- a/media/libstagefright/NuHTTPDataSource.cpp
+++ b/media/libstagefright/NuHTTPDataSource.cpp
@@ -136,6 +136,7 @@
     unsigned port;
 
     mUri = uri;
+    mContentType = String8("application/octet-stream");
 
     bool https;
     if (!ParseURL(uri, &host, &port, &path, &https)) {
@@ -265,6 +266,15 @@
             }
         }
 
+        {
+            AString value;
+            if (mHTTP.find_header_value("Content-Type", &value)) {
+                mContentType = String8(value.c_str());
+            } else {
+                mContentType = String8("application/octet-stream");
+            }
+        }
+
         applyTimeoutResponse();
 
         if (offset == 0) {
@@ -410,7 +420,14 @@
             internalRead((uint8_t *)data + numBytesRead, size - numBytesRead);
 
         if (n < 0) {
-            return n;
+            if (numBytesRead == 0 || mContentLengthValid) {
+                return n;
+            }
+
+            // If there was an error we want to at least return the data
+            // we've already successfully read. The next call to read will
+            // then return the error.
+            n = 0;
         }
 
         int64_t delayUs = ALooper::GetNowUs() - startTimeUs;
@@ -564,4 +581,8 @@
     return mUri;
 }
 
+String8 NuHTTPDataSource::getMIMEType() const {
+    return mContentType;
+}
+
 }  // namespace android
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 904bd62..c278992 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -2240,8 +2240,8 @@
                         android_native_rect_t crop;
                         crop.left = left;
                         crop.top = top;
-                        crop.right = right;
-                        crop.bottom = bottom;
+                        crop.right = right + 1;
+                        crop.bottom = bottom + 1;
 
                         // We'll ignore any errors here, if the surface is
                         // already invalid, we'll know soon enough.
diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp
index 8b86e53..f82ff32 100644
--- a/media/libstagefright/StagefrightMediaScanner.cpp
+++ b/media/libstagefright/StagefrightMediaScanner.cpp
@@ -38,6 +38,7 @@
         ".mpeg", ".ogg", ".mid", ".smf", ".imy", ".wma", ".aac",
         ".wav", ".amr", ".midi", ".xmf", ".rtttl", ".rtx", ".ota",
         ".mkv", ".mka", ".webm", ".ts", ".fl", ".flac", ".mxmf",
+        ".avi",
     };
     static const size_t kNumValidExtensions =
         sizeof(kValidExtensions) / sizeof(kValidExtensions[0]);
diff --git a/media/libstagefright/WAVExtractor.cpp b/media/libstagefright/WAVExtractor.cpp
index e9e5ef9..76f47f7 100644
--- a/media/libstagefright/WAVExtractor.cpp
+++ b/media/libstagefright/WAVExtractor.cpp
@@ -425,6 +425,11 @@
         return false;
     }
 
+    sp<MediaExtractor> extractor = new WAVExtractor(source);
+    if (extractor->countTracks() == 0) {
+        return false;
+    }
+
     *mimeType = MEDIA_MIMETYPE_CONTAINER_WAV;
     *confidence = 0.3f;
 
diff --git a/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp b/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp
index 949a5e4..1096717 100644
--- a/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp
+++ b/media/libstagefright/chromium_http/ChromiumHTTPDataSource.cpp
@@ -79,6 +79,7 @@
     }
 
     mURI = uri;
+    mContentType = String8("application/octet-stream");
 
     if (headers != NULL) {
         mHeaders = *headers;
@@ -99,10 +100,12 @@
     return mState == CONNECTED ? OK : mIOResult;
 }
 
-void ChromiumHTTPDataSource::onConnectionEstablished(int64_t contentSize) {
+void ChromiumHTTPDataSource::onConnectionEstablished(
+        int64_t contentSize, const char *contentType) {
     Mutex::Autolock autoLock(mLock);
     mState = CONNECTED;
     mContentSize = (contentSize < 0) ? -1 : contentSize + mCurrentOffset;
+    mContentType = String8(contentType);
     mCondition.broadcast();
 }
 
@@ -314,6 +317,12 @@
     return String8(mURI.c_str());
 }
 
+String8 ChromiumHTTPDataSource::getMIMEType() const {
+    Mutex::Autolock autoLock(mLock);
+
+    return mContentType;
+}
+
 void ChromiumHTTPDataSource::clearDRMState_l() {
     if (mDecryptHandle != NULL) {
         // To release mDecryptHandle
diff --git a/media/libstagefright/chromium_http/support.cpp b/media/libstagefright/chromium_http/support.cpp
index 7ac56e8..af2f6ac 100644
--- a/media/libstagefright/chromium_http/support.cpp
+++ b/media/libstagefright/chromium_http/support.cpp
@@ -253,7 +253,11 @@
 
     MY_LOGV(StringPrintf("response headers: %s", headers.c_str()).c_str());
 
-    mOwner->onConnectionEstablished(request->GetExpectedContentSize());
+    std::string contentType;
+    request->GetResponseHeaderByName("Content-Type", &contentType);
+
+    mOwner->onConnectionEstablished(
+            request->GetExpectedContentSize(), contentType.c_str());
 }
 
 void SfDelegate::OnReadCompleted(URLRequest *request, int bytes_read) {
diff --git a/media/libstagefright/include/AVIExtractor.h b/media/libstagefright/include/AVIExtractor.h
new file mode 100644
index 0000000..375a94d
--- /dev/null
+++ b/media/libstagefright/include/AVIExtractor.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2011 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.
+ */
+
+#ifndef AVI_EXTRACTOR_H_
+
+#define AVI_EXTRACTOR_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MediaSource.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+struct AVIExtractor : public MediaExtractor {
+    AVIExtractor(const sp<DataSource> &dataSource);
+
+    virtual size_t countTracks();
+
+    virtual sp<MediaSource> getTrack(size_t index);
+
+    virtual sp<MetaData> getTrackMetaData(
+            size_t index, uint32_t flags);
+
+    virtual sp<MetaData> getMetaData();
+
+protected:
+    virtual ~AVIExtractor();
+
+private:
+    struct AVISource;
+
+    struct SampleInfo {
+        uint32_t mOffset;
+        bool mIsKey;
+    };
+
+    struct Track {
+        sp<MetaData> mMeta;
+        Vector<SampleInfo> mSamples;
+        uint32_t mRate;
+        uint32_t mScale;
+
+        enum Kind {
+            AUDIO,
+            VIDEO,
+            OTHER
+
+        } mKind;
+
+        size_t mNumSyncSamples;
+        size_t mThumbnailSampleSize;
+        ssize_t mThumbnailSampleIndex;
+        size_t mMaxSampleSize;
+    };
+
+    sp<DataSource> mDataSource;
+    status_t mInitCheck;
+    Vector<Track> mTracks;
+
+    off64_t mMovieOffset;
+    bool mFoundIndex;
+    bool mOffsetsAreAbsolute;
+
+    ssize_t parseChunk(off64_t offset, off64_t size, int depth = 0);
+    status_t parseStreamHeader(off64_t offset, size_t size);
+    status_t parseStreamFormat(off64_t offset, size_t size);
+    status_t parseIndex(off64_t offset, size_t size);
+
+    status_t parseHeaders();
+
+    status_t getSampleInfo(
+            size_t trackIndex, size_t sampleIndex,
+            off64_t *offset, size_t *size, bool *isKey);
+
+    status_t getSampleIndexAtTime(
+            size_t trackIndex,
+            int64_t timeUs, MediaSource::ReadOptions::SeekMode mode,
+            size_t *sampleIndex) const;
+
+    status_t addMPEG4CodecSpecificData(size_t trackIndex);
+
+    static bool IsCorrectChunkType(
+        ssize_t trackIndex, Track::Kind kind, uint32_t chunkType);
+
+    DISALLOW_EVIL_CONSTRUCTORS(AVIExtractor);
+};
+
+class String8;
+struct AMessage;
+
+bool SniffAVI(
+        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+        sp<AMessage> *);
+
+}  // namespace android
+
+#endif  // AVI_EXTRACTOR_H_
diff --git a/media/libstagefright/include/ChromiumHTTPDataSource.h b/media/libstagefright/include/ChromiumHTTPDataSource.h
index af49059..0e2927d 100644
--- a/media/libstagefright/include/ChromiumHTTPDataSource.h
+++ b/media/libstagefright/include/ChromiumHTTPDataSource.h
@@ -51,6 +51,8 @@
 
     virtual String8 getUri();
 
+    virtual String8 getMIMEType() const;
+
 protected:
     virtual ~ChromiumHTTPDataSource();
 
@@ -90,6 +92,8 @@
 
     int64_t mContentSize;
 
+    String8 mContentType;
+
     List<BandwidthEntry> mBandwidthHistory;
     size_t mNumBandwidthHistoryItems;
     int64_t mTotalTransferTimeUs;
@@ -110,7 +114,9 @@
 
     void initiateRead(void *data, size_t size);
 
-    void onConnectionEstablished(int64_t contentSize);
+    void onConnectionEstablished(
+            int64_t contentSize, const char *contentType);
+
     void onConnectionFailed(status_t err);
     void onReadCompleted(ssize_t size);
     void onDisconnectComplete();
diff --git a/media/libstagefright/include/NuCachedSource2.h b/media/libstagefright/include/NuCachedSource2.h
index 02d5817..2128682 100644
--- a/media/libstagefright/include/NuCachedSource2.h
+++ b/media/libstagefright/include/NuCachedSource2.h
@@ -40,6 +40,9 @@
     virtual sp<DecryptHandle> DrmInitialization();
     virtual void getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client);
     virtual String8 getUri();
+
+    virtual String8 getMIMEType() const;
+
     ////////////////////////////////////////////////////////////////////////////
 
     size_t cachedSize();
diff --git a/media/libstagefright/include/NuHTTPDataSource.h b/media/libstagefright/include/NuHTTPDataSource.h
index 7dd5d59..2ab1f19 100644
--- a/media/libstagefright/include/NuHTTPDataSource.h
+++ b/media/libstagefright/include/NuHTTPDataSource.h
@@ -51,6 +51,8 @@
     virtual void getDrmInfo(sp<DecryptHandle> &handle, DrmManagerClient **client);
     virtual String8 getUri();
 
+    virtual String8 getMIMEType() const;
+
 protected:
     virtual ~NuHTTPDataSource();
 
@@ -85,6 +87,8 @@
     bool mContentLengthValid;
     bool mHasChunkedTransferEncoding;
 
+    String8 mContentType;
+
     // The number of data bytes in the current chunk before any subsequent
     // chunk header (or -1 if no more chunks).
     ssize_t mChunkDataBytesLeft;
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index a53b375..6474c87 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -120,7 +120,7 @@
 
     SortedVector<egl_object_t*> objects;
 
-    egl_display_t() : magic('_dpy'), numTotalConfigs(0), configs(0) { }
+    egl_display_t() : magic('_dpy'), numTotalConfigs(0), configs(0), refs(0) { }
     ~egl_display_t() { magic = 0; }
     inline bool isReady() const { return (refs > 0); }
     inline bool isValid() const { return magic == '_dpy'; }
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 12ac052..3997702 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -543,18 +543,8 @@
      */
     public NetworkInfo getActiveNetworkInfo() {
         enforceAccessPermission();
-        for (int type=0; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) {
-            if (mNetAttributes[type] == null || !mNetAttributes[type].isDefault()) {
-                continue;
-            }
-            NetworkStateTracker t = mNetTrackers[type];
-            NetworkInfo info = t.getNetworkInfo();
-            if (info.isConnected()) {
-                if (DBG && type != mActiveDefaultNetwork) {
-                    loge("connected default network is not mActiveDefaultNetwork!");
-                }
-                return info;
-            }
+        if (mActiveDefaultNetwork != -1) {
+            return mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
         }
         return null;
     }
@@ -1353,6 +1343,19 @@
                 handleApplyDefaultProxy(netType);
                 addDefaultRoute(mNetTrackers[netType]);
             } else {
+                // many radios add a default route even when we don't want one.
+                // remove the default route unless we need it for our active network
+                if (mActiveDefaultNetwork != -1) {
+                    LinkProperties defaultLinkProperties =
+                            mNetTrackers[mActiveDefaultNetwork].getLinkProperties();
+                    LinkProperties newLinkProperties =
+                            mNetTrackers[netType].getLinkProperties();
+                    String defaultIface = defaultLinkProperties.getInterfaceName();
+                    if (defaultIface != null &&
+                            !defaultIface.equals(newLinkProperties.getInterfaceName())) {
+                        removeDefaultRoute(mNetTrackers[netType]);
+                    }
+                }
                 addPrivateDnsRoutes(mNetTrackers[netType]);
             }
         } else {
diff --git a/services/java/com/android/server/LightsService.java b/services/java/com/android/server/LightsService.java
index 21f2bcf..1e95f3e 100644
--- a/services/java/com/android/server/LightsService.java
+++ b/services/java/com/android/server/LightsService.java
@@ -148,7 +148,6 @@
                 fis.close();
                 return (result != '0');
             } catch (Exception e) {
-                Slog.e(TAG, "getFlashlightEnabled failed", e);
                 return false;
             }
         }
@@ -168,7 +167,7 @@
                 fos.write(bytes);
                 fos.close();
             } catch (Exception e) {
-                Slog.e(TAG, "setFlashlightEnabled failed", e);
+                // fail silently
             }
         }
     };
diff --git a/services/java/com/android/server/VibratorService.java b/services/java/com/android/server/VibratorService.java
index 2fcdb5d..c39dc80 100755
--- a/services/java/com/android/server/VibratorService.java
+++ b/services/java/com/android/server/VibratorService.java
@@ -247,6 +247,7 @@
     // Lock held on mVibrations
     private void startNextVibrationLocked() {
         if (mVibrations.size() <= 0) {
+            mCurrentVibration = null;
             return;
         }
         mCurrentVibration = mVibrations.getFirst();
@@ -273,17 +274,27 @@
             Vibration vib = iter.next();
             if (vib.mToken == token) {
                 iter.remove();
+                unlinkVibration(vib);
                 return vib;
             }
         }
         // We might be looking for a simple vibration which is only stored in
         // mCurrentVibration.
         if (mCurrentVibration != null && mCurrentVibration.mToken == token) {
+            unlinkVibration(mCurrentVibration);
             return mCurrentVibration;
         }
         return null;
     }
 
+    private void unlinkVibration(Vibration vib) {
+        if (vib.mPattern != null) {
+            // If Vibration object has a pattern,
+            // the Vibration object has also been linkedToDeath.
+            vib.mToken.unlinkToDeath(vib, 0);
+        }
+    }
+
     private class VibrateThread extends Thread {
         final Vibration mVibration;
         boolean mDone;
@@ -360,6 +371,7 @@
                     // If this vibration finished naturally, start the next
                     // vibration.
                     mVibrations.remove(mVibration);
+                    unlinkVibration(mVibration);
                     startNextVibrationLocked();
                 }
             }
diff --git a/services/java/com/android/server/usb/UsbService.java b/services/java/com/android/server/usb/UsbService.java
index b7f6346..a151af0 100644
--- a/services/java/com/android/server/usb/UsbService.java
+++ b/services/java/com/android/server/usb/UsbService.java
@@ -561,11 +561,14 @@
                     case MSG_UPDATE_STATE:
                         if (mConnected != mLastConnected || mConfiguration != mLastConfiguration) {
                             if (mConnected == 0) {
-                                // make sure accessory mode is off, and restore default functions
-                                if (mCurrentAccessory != null && UsbManager.setFunctionEnabled(
-                                        UsbManager.USB_FUNCTION_ACCESSORY, false)) {
+                                if (UsbManager.isFunctionEnabled(
+                                            UsbManager.USB_FUNCTION_ACCESSORY)) {
+                                    // make sure accessory mode is off, and restore default functions
                                     Log.d(TAG, "exited USB accessory mode");
-
+                                    if (!UsbManager.setFunctionEnabled
+                                            (UsbManager.USB_FUNCTION_ACCESSORY, false)) {
+                                        Log.e(TAG, "could not disable accessory function");
+                                    }
                                     int count = mDefaultFunctions.size();
                                     for (int i = 0; i < count; i++) {
                                         String function = mDefaultFunctions.get(i);
@@ -574,8 +577,10 @@
                                         }
                                     }
 
-                                    mDeviceManager.accessoryDetached(mCurrentAccessory);
-                                    mCurrentAccessory = null;
+                                    if (mCurrentAccessory != null) {
+                                        mDeviceManager.accessoryDetached(mCurrentAccessory);
+                                        mCurrentAccessory = null;
+                                    }
                                 }
                             }
 
diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java
index b5578c3..e21e951 100644
--- a/telephony/java/com/android/internal/telephony/DataConnection.java
+++ b/telephony/java/com/android/internal/telephony/DataConnection.java
@@ -109,14 +109,17 @@
      * Used internally for saving disconnecting parameters.
      */
     protected static class DisconnectParams {
-        public DisconnectParams(Message onCompletedMsg) {
+        public DisconnectParams(String reason, Message onCompletedMsg) {
+            this.reason = reason;
             this.onCompletedMsg = onCompletedMsg;
         }
         public DisconnectParams(ResetSynchronouslyLock lockObj) {
+            this.reason = null;
             this.lockObj = lockObj;
         }
 
         public int tag;
+        public String reason;
         public Message onCompletedMsg;
         public ResetSynchronouslyLock lockObj;
     }
@@ -274,10 +277,8 @@
         if ((o != null) && (o instanceof DisconnectParams)) {
             DisconnectParams dp = (DisconnectParams)o;
             Message m = dp.onCompletedMsg;
-            if ((m != null) && (m.obj != null) && (m.obj instanceof String)) {
-                String reason = (String)m.obj;
-                if (TextUtils.equals(reason, Phone.REASON_RADIO_TURNED_OFF))
-                    discReason = RILConstants.DEACTIVATE_REASON_RADIO_OFF;
+            if (TextUtils.equals(dp.reason, Phone.REASON_RADIO_TURNED_OFF)) {
+                discReason = RILConstants.DEACTIVATE_REASON_RADIO_OFF;
             }
         }
         if (phone.mCM.getRadioState().isOn()) {
@@ -963,7 +964,7 @@
      *        With AsyncResult.userObj set to the original msg.obj.
      */
     public void reset(Message onCompletedMsg) {
-        sendMessage(obtainMessage(EVENT_RESET, new DisconnectParams(onCompletedMsg)));
+        sendMessage(obtainMessage(EVENT_RESET, new DisconnectParams(null, onCompletedMsg)));
     }
 
     /**
@@ -1014,8 +1015,8 @@
      * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
      *        With AsyncResult.userObj set to the original msg.obj.
      */
-    public void disconnect(Message onCompletedMsg) {
-        sendMessage(obtainMessage(EVENT_DISCONNECT, new DisconnectParams(onCompletedMsg)));
+    public void disconnect(String reason, Message onCompletedMsg) {
+        sendMessage(obtainMessage(EVENT_DISCONNECT, new DisconnectParams(reason, onCompletedMsg)));
     }
 
     // ****** The following are used for debugging.
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index 8a029f1..fba73fb5 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -461,7 +461,7 @@
     protected abstract void onVoiceCallStarted();
     protected abstract void onVoiceCallEnded();
     protected abstract void onCleanUpConnection(boolean tearDown, int apnId, String reason);
-    protected abstract void onCleanUpAllConnections();
+    protected abstract void onCleanUpAllConnections(String cause);
 
     @Override
     public void handleMessage(Message msg) {
@@ -517,7 +517,7 @@
                 break;
 
             case EVENT_CLEAN_UP_ALL_CONNECTIONS: {
-                onCleanUpAllConnections();
+                onCleanUpAllConnections((String) msg.obj);
                 break;
             }
             case EVENT_CLEAN_UP_CONNECTION: {
@@ -920,7 +920,7 @@
                     resetAllRetryCounts();
                     onTrySetupData(Phone.REASON_DATA_ENABLED);
                 } else {
-                    cleanUpAllConnections();
+                    cleanUpAllConnections(null);
                 }
             }
         }
@@ -930,8 +930,9 @@
         return mDataEnabled;
     }
 
-    public void cleanUpAllConnections() {
+    public void cleanUpAllConnections(String cause) {
         Message msg = obtainMessage(EVENT_CLEAN_UP_ALL_CONNECTIONS);
+        msg.obj = cause;
         sendMessage(msg);
     }
 
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index 5408ce9..779b125 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -243,7 +243,7 @@
         synchronized(PhoneProxy.lockForRadioTechnologyChange) {
             mCM.unSetOnCallRing(this);
             // Must cleanup all connectionS and needs to use sendMessage!
-            mDataConnection.cleanUpAllConnections();
+            mDataConnection.cleanUpAllConnections(null);
             mIsTheCurrentActivePhone = false;
         }
     }
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 8c9fb79..4faf297 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -66,8 +66,11 @@
     int NETWORK_MODE_EVDO_NO_CDMA   = 6; /* EvDo only */
     int NETWORK_MODE_GLOBAL         = 7; /* GSM/WCDMA, CDMA, and EvDo (auto mode, according to PRL)
                                             AVAILABLE Application Settings menu*/
-    int NETWORK_MODE_LTE_ONLY       = 8; /* LTE Only mode. Used only for testing purposes.Not
-                                            user selectable from regular UI */
+    int NETWORK_MODE_LTE_CDMA_EVDO  = 8; /* LTE, CDMA and EvDo */
+    int NETWORK_MODE_LTE_GSM_WCDMA  = 9; /* LTE, GSM/WCDMA */
+    int NETWORK_MODE_LTE_CMDA_EVDO_GSM_WCDMA = 10; /* LTE, CDMA, EvDo, GSM/WCDMA */
+    int NETWORK_MODE_LTE_ONLY       = 11; /* LTE Only mode. */
+
     int PREFERRED_NETWORK_MODE      = NETWORK_MODE_WCDMA_PREF;
 
     /* CDMA subscription source. See ril.h RIL_REQUEST_CDMA_SET_SUBSCRIPTION */
diff --git a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
index 1b5bad9..5501361 100644
--- a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -68,6 +68,9 @@
     protected RegistrantList mPsRestrictEnabledRegistrants = new RegistrantList();
     protected RegistrantList mPsRestrictDisabledRegistrants = new RegistrantList();
 
+    /* Radio power off pending flag and tag counter */
+    private boolean mPendingRadioPowerOffAfterDataOff = false;
+    private int mPendingRadioPowerOffAfterDataOffTag = 0;
 
     protected  static final boolean DBG = true;
 
@@ -77,8 +80,6 @@
     /** Waiting period before recheck gprs and voice registration. */
     public static final int DEFAULT_GPRS_CHECK_PERIOD_MILLIS = 60 * 1000;
 
-    public static final int DATA_STATE_POLL_SLEEP_MS = 100;
-
     /** GSM events */
     protected static final int EVENT_RADIO_STATE_CHANGED               = 1;
     protected static final int EVENT_NETWORK_STATE_CHANGED             = 2;
@@ -262,7 +263,29 @@
         }
     }
 
-    public abstract void handleMessage(Message msg);
+    @Override
+    public void handleMessage(Message msg) {
+        switch (msg.what) {
+            case EVENT_SET_RADIO_POWER_OFF:
+                synchronized(this) {
+                    if (mPendingRadioPowerOffAfterDataOff &&
+                            (msg.arg1 == mPendingRadioPowerOffAfterDataOffTag)) {
+                        if (DBG) log("EVENT_SET_RADIO_OFF, turn radio off now.");
+                        hangupAndPowerOff();
+                        mPendingRadioPowerOffAfterDataOffTag += 1;
+                        mPendingRadioPowerOffAfterDataOff = false;
+                    } else {
+                        log("EVENT_SET_RADIO_OFF is stale arg1=" + msg.arg1 +
+                                "!= tag=" + mPendingRadioPowerOffAfterDataOffTag);
+                    }
+                }
+                break;
+
+            default:
+                log("Unhandled message with number: " + msg.what);
+                break;
+        }
+    }
 
     protected abstract Phone getPhone();
     protected abstract void handlePollStateResult(int what, AsyncResult ar);
@@ -370,7 +393,52 @@
      *
      * Hang up the existing voice calls to decrease call drop rate.
      */
-    public abstract void powerOffRadioSafely();
+    public void powerOffRadioSafely(DataConnectionTracker dcTracker) {
+        synchronized (this) {
+            if (!mPendingRadioPowerOffAfterDataOff) {
+                if (dcTracker.isAnyActiveDataConnections()) {
+                    dcTracker.cleanUpAllConnections(null);
+                    Message msg = Message.obtain(this);
+                    msg.what = EVENT_SET_RADIO_POWER_OFF;
+                    msg.arg1 = ++mPendingRadioPowerOffAfterDataOffTag;
+                    if (sendMessageDelayed(msg, 30000)) {
+                        if (DBG) log("Wait upto 30s for data to disconnect, then turn off radio.");
+                        mPendingRadioPowerOffAfterDataOff = true;
+                    } else {
+                        log("Cannot send delayed Msg, turn off radio right away.");
+                        hangupAndPowerOff();
+                    }
+                } else {
+                    dcTracker.cleanUpAllConnections(null);
+                    if (DBG) log("Data disconnected, turn off radio right away.");
+                    hangupAndPowerOff();
+                }
+            }
+        }
+    }
+
+    /**
+     * process the pending request to turn radio off after data is disconnected
+     *
+     * return true if there is pending request to process; false otherwise.
+     */
+    public boolean processPendingRadioPowerOffAfterDataOff() {
+        synchronized(this) {
+            if (mPendingRadioPowerOffAfterDataOff) {
+                if (DBG) log("Process pending request to turn radio off.");
+                mPendingRadioPowerOffAfterDataOffTag += 1;
+                hangupAndPowerOff();
+                mPendingRadioPowerOffAfterDataOff = false;
+                return true;
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Hang up all voice call and turn off radio. Implemented by derived class.
+     */
+    protected abstract void hangupAndPowerOff();
 
     /** Cancel a pending (if any) pollState() operation */
     protected void cancelPollState() {
diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
index c4fab66..4927006 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
@@ -75,7 +75,7 @@
     /** 'true' if device supports both LTE and CDMA mode of operation.
      *  Availability: Set only on devices supporting LTE and CDMA.
      */
-    static final String PROPERTY_NETWORK_LTE_ON_CDMA = "ro.telephony.lte_on_cdma";
+    static final String PROPERTY_NETWORK_LTE_ON_CDMA = "telephony.lte_on_cdma";
 
     static final String CURRENT_ACTIVE_PHONE = "gsm.current.phone-type";
 
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index 01519a7..05361cd 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -269,7 +269,7 @@
             if(conn != null) {
                 if (tearDown) {
                     if (DBG) log("cleanUpConnection: teardown, call conn.disconnect");
-                    conn.disconnect(obtainMessage(EVENT_DISCONNECT_DONE,
+                    conn.disconnect(reason, obtainMessage(EVENT_DISCONNECT_DONE,
                             conn.getDataConnectionId(), 0, reason));
                     notificationDeferred = true;
                 } else {
@@ -367,7 +367,7 @@
     protected void restartRadio() {
         if (DBG) log("Cleanup connection and wait " +
                 (TIME_DELAYED_TO_RESTART_RADIO / 1000) + "s to restart radio");
-        cleanUpAllConnections();
+        cleanUpAllConnections(null);
         sendEmptyMessageDelayed(EVENT_RESTART_RADIO, TIME_DELAYED_TO_RESTART_RADIO);
         mPendingRestartRadio = true;
     }
@@ -524,14 +524,14 @@
 
     protected void onRecordsLoaded() {
         if (mState == State.FAILED) {
-            cleanUpAllConnections();
+            cleanUpAllConnections(null);
         }
         sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA, Phone.REASON_SIM_LOADED));
     }
 
     protected void onNVReady() {
         if (mState == State.FAILED) {
-            cleanUpAllConnections();
+            cleanUpAllConnections(null);
         }
         sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA));
     }
@@ -570,7 +570,7 @@
             trySetupData(Phone.REASON_ROAMING_ON);
         } else {
             if (DBG) log("Tear down data connection on roaming.");
-            cleanUpAllConnections();
+            cleanUpAllConnections(null);
         }
     }
 
@@ -591,7 +591,7 @@
         notifyDataAvailability(null);
 
         if (mState != State.IDLE) {
-            cleanUpAllConnections();
+            cleanUpAllConnections(null);
         }
     }
 
@@ -608,7 +608,7 @@
             log("We're on the simulator; assuming radio off is meaningless");
         } else {
             if (DBG) log("Radio is off and clean up all connection");
-            cleanUpAllConnections();
+            cleanUpAllConnections(null);
         }
     }
 
@@ -714,9 +714,9 @@
     }
 
     @Override
-    protected void onCleanUpAllConnections() {
+    protected void onCleanUpAllConnections(String cause) {
         // Only one CDMA connection is supported
-        cleanUpConnection(true, null);
+        cleanUpConnection(true, cause);
     }
 
     private void createAllDataConnectionList() {
@@ -907,6 +907,11 @@
     }
 
     @Override
+    public boolean isAnyActiveDataConnections() {
+        return (mState != State.IDLE);
+    }
+
+    @Override
     protected void log(String s) {
         Log.d(LOG_TAG, "[CdmaDataConnectionTracker] " + s);
     }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
index 81b4077..7ca3bea 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaLteServiceStateTracker.java
@@ -152,17 +152,6 @@
                 pollStateDone();
                 break;
 
-            case SIM_NOT_READY:
-            case SIM_LOCKED_OR_ABSENT:
-            case SIM_READY:
-                log("Radio Technology Change ongoing, setting SS to off");
-                newSS.setStateOff();
-                newCellLoc.setStateInvalid();
-                setSignalStrengthDefaultValues();
-                mGotCountryCode = false;
-                // NOTE: pollStateDone() is not needed in this case
-                break;
-
             default:
                 // Issue all poll-related commands at once, then count
                 // down the responses which are allowed to arrive
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index 658de84..07f9e38 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -139,8 +139,6 @@
     private boolean isEriTextLoaded = false;
     private boolean isSubscriptionFromRuim = false;
 
-    private boolean mPendingRadioPowerOffAfterDataOff = false;
-
     /* Used only for debugging purposes. */
     private String mRegistrationDeniedReason;
 
@@ -485,18 +483,8 @@
             }
             break;
 
-        case EVENT_SET_RADIO_POWER_OFF:
-            synchronized(this) {
-                if (mPendingRadioPowerOffAfterDataOff) {
-                    if (DBG) log("EVENT_SET_RADIO_OFF, turn radio off now.");
-                    hangupAndPowerOff();
-                    mPendingRadioPowerOffAfterDataOff = false;
-                }
-            }
-            break;
-
         default:
-            Log.e(LOG_TAG, "Unhandled message with number: " + msg.what);
+            super.handleMessage(msg);
         break;
         }
     }
@@ -513,35 +501,10 @@
             DataConnectionTracker dcTracker = phone.mDataConnection;
 
             // If it's on and available and we want it off gracefully
-            powerOffRadioSafely();
+            powerOffRadioSafely(dcTracker);
         } // Otherwise, we're in the desired state
     }
 
-    // TODO: Consider moving this method to DataConnectionTracker
-    @Override
-    public void powerOffRadioSafely() {
-        DataConnectionTracker dcTracker = phone.mDataConnection;
-
-        synchronized (this) {
-            if (!mPendingRadioPowerOffAfterDataOff) {
-                if (dcTracker.isAnyActiveDataConnections()) {
-                    dcTracker.cleanUpAllConnections();
-                    if (sendEmptyMessageDelayed(EVENT_SET_RADIO_POWER_OFF, 30000)) {
-                        if (DBG) log("Wait upto 30s for data to disconnect, then turn off radio.");
-                        mPendingRadioPowerOffAfterDataOff = true;
-                    } else {
-                        Log.w(LOG_TAG, "Cannot send delayed Msg, turn off radio right away.");
-                        hangupAndPowerOff();
-                    }
-                } else {
-                    dcTracker.cleanUpAllConnections();
-                    if (DBG) log("Data disconnected, turn off radio right away.");
-                    hangupAndPowerOff();
-                }
-            }
-        }
-    }
-
     @Override
     protected void updateSpnDisplay() {
         // TODO RUIM SPN is not implemented, EF_SPN has to be read and Display Condition
@@ -1658,24 +1621,6 @@
     }
 
     /**
-     * process the pending request to turn radio off after data is disconnected
-     *
-     * return true if there is pending request to process; false otherwise.
-     */
-    public boolean processPendingRadioPowerOffAfterDataOff() {
-        synchronized(this) {
-            if (mPendingRadioPowerOffAfterDataOff) {
-                if (DBG) log("Process pending request to turn radio off.");
-                removeMessages(EVENT_SET_RADIO_POWER_OFF);
-                hangupAndPowerOff();
-                mPendingRadioPowerOffAfterDataOff = false;
-                return true;
-            }
-            return false;
-        }
-    }
-
-    /**
      * Returns OTASP_UNKNOWN, OTASP_NEEDED or OTASP_NOT_NEEDED
      */
     int getOtasp() {
@@ -1701,7 +1646,8 @@
         Log.d(LOG_TAG, "[CdmaServiceStateTracker] " + s);
     }
 
-    private void hangupAndPowerOff() {
+    @Override
+    protected void hangupAndPowerOff() {
         // hang up all active voice calls
         phone.mCT.ringingCall.hangupIfAlive();
         phone.mCT.backgroundCall.hangupIfAlive();
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 22c4640..7dad459 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -708,8 +708,8 @@
      */
 
     @Override
-    protected void onCleanUpAllConnections() {
-        cleanUpAllConnections(true, null);
+    protected void onCleanUpAllConnections(String cause) {
+        cleanUpAllConnections(true, cause);
     }
 
     private void cleanUpConnection(boolean tearDown, ApnContext apnContext) {
@@ -745,7 +745,7 @@
             apnContext.setState(State.DISCONNECTING);
             if (tearDown ) {
                 Message msg = obtainMessage(EVENT_DISCONNECT_DONE, apnContext);
-                conn.disconnect(msg);
+                conn.disconnect(apnContext.getReason(), msg);
             } else {
                 conn.resetSynchronously();
                 apnContext.setState(State.IDLE);
@@ -1073,7 +1073,7 @@
     protected void restartRadio() {
         log("************TURN OFF RADIO**************");
         cleanUpAllConnections(true, Phone.REASON_RADIO_TURNED_OFF);
-        mPhone.getServiceStateTracker().powerOffRadioSafely();
+        mPhone.getServiceStateTracker().powerOffRadioSafely(this);
         /* Note: no need to call setRadioPower(true).  Assuming the desired
          * radio power state is still ON (as tracked by ServiceStateTracker),
          * ServiceStateTracker will call setRadioPower when it receives the
@@ -1491,14 +1491,25 @@
         }
 
         mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
+
+        apnContext.setState(State.IDLE);
+        apnContext.setApnSetting(null);
+
+        // if all data connection are gone, check whether Airplane mode request was
+        // pending.
+        if (!isConnected()) {
+            if (mPhone.getServiceStateTracker().processPendingRadioPowerOffAfterDataOff()) {
+                // Radio will be turned off. No need to retry data setup
+                return;
+            }
+        }
+
         // Check if APN disabled.
         if (apnContext.getPendingAction() == ApnContext.PENDING_ACTION_APN_DISABLE) {
            mApnContexts.remove(apnContext.getApnType());
            return;
         }
 
-        apnContext.setState(State.IDLE);
-        apnContext.setApnSetting(null);
         if (TextUtils.equals(apnContext.getApnType(), Phone.APN_TYPE_DEFAULT)
             && retryAfterDisconnected(apnContext.getReason())) {
             SystemProperties.set("gsm.defaultpdpcontext.active", "false");
@@ -1894,6 +1905,11 @@
     }
 
     @Override
+    public boolean isAnyActiveDataConnections() {
+        return isConnected();
+    }
+
+    @Override
     protected void log(String s) {
         Log.d(LOG_TAG, "[GsmDataConnectionTracker] " + s);
     }
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
index 3f521a0..ef3eed8 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
@@ -164,8 +164,6 @@
     static final int PS_NOTIFICATION = 888;  // Id to update and cancel PS restricted
     static final int CS_NOTIFICATION = 999;  // Id to update and cancel CS restricted
 
-    static final int MAX_NUM_DATA_STATE_READS = 15;
-
     private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -459,7 +457,7 @@
                 break;
 
             default:
-                Log.e(LOG_TAG, "Unhandled message with number: " + msg.what);
+                super.handleMessage(msg);
             break;
         }
     }
@@ -471,23 +469,13 @@
             cm.setRadioPower(true, null);
         } else if (!mDesiredPowerState && cm.getRadioState().isOn()) {
             // If it's on and available and we want it off gracefully
-            powerOffRadioSafely();
+            DataConnectionTracker dcTracker = phone.mDataConnection;
+            powerOffRadioSafely(dcTracker);
         } // Otherwise, we're in the desired state
     }
 
     @Override
-    public void powerOffRadioSafely() {
-        // Cleanup all connections
-        DataConnectionTracker dcTracker = phone.mDataConnection;
-        Message msg = dcTracker.obtainMessage(DataConnectionTracker.EVENT_CLEAN_UP_ALL_CONNECTIONS);
-        dcTracker.sendMessage(msg);
-
-        // poll data state up to 15 times, with a 100ms delay
-        // totaling 1.5 sec. Normal data disable action will finish in 100ms.
-        for (int i = 0; i < MAX_NUM_DATA_STATE_READS; i++) {
-            SystemClock.sleep(DATA_STATE_POLL_SLEEP_MS);
-        }
-
+    protected void hangupAndPowerOff() {
         // hang up all active voice calls
         if (phone.isInCall()) {
             phone.mCT.ringingCall.hangupIfAlive();
diff --git a/tests/BiDiTests/res/layout/biditest_main.xml b/tests/BiDiTests/res/layout/biditest_main.xml
index 9f77ad2..087c9a3 100644
--- a/tests/BiDiTests/res/layout/biditest_main.xml
+++ b/tests/BiDiTests/res/layout/biditest_main.xml
@@ -48,6 +48,11 @@
 
     </LinearLayout>
 
+    <SeekBar android:id="@+id/seekbar"
+               android:layout_height="wrap_content"
+               android:layout_width="match_parent"
+               />
+
     <view class="com.android.bidi.BiDiTestView"
         android:id="@+id/main"
         android:layout_width="match_parent"
diff --git a/tests/BiDiTests/res/values/strings.xml b/tests/BiDiTests/res/values/strings.xml
index ecff76e..632a02e 100644
--- a/tests/BiDiTests/res/values/strings.xml
+++ b/tests/BiDiTests/res/values/strings.xml
@@ -18,9 +18,11 @@
     <string name="edittext_text">mmmmmmmmmmmmmmmmmmmmmmmm</string>
     <string name="normal_text">Normal String</string>
     <string name="normal_long_text">mmmmmmmmmmmmmmmmmmmmmmmm</string>
+    <string name="normal_long_text_2">nnnnnnnnnnnnnnnnnnnnnnnn</string>
+    <string name="normal_long_text_3">Notify me when an open network is available</string>
     <string name="arabic_text">&#x0644;&#x0627;</string>
     <string name="chinese_text">利比亚局势或影响美俄关系发展</string>
     <string name="italic_text">Italic String</string>
-    <string name="bold_text">Bold String</string>
+    <string name="bold_text">Bold String - other text</string>
     <string name="bold_italic_text">Bold Italic String</string>
 </resources>
\ No newline at end of file
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
index 3d7dd81..6c71574 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
@@ -20,16 +20,44 @@
 import android.os.Bundle;
 import android.util.Log;
 import android.view.View;
+import android.widget.SeekBar;
+
+import static com.android.bidi.BiDiTestConstants.FONT_MIN_SIZE;
+import static com.android.bidi.BiDiTestConstants.FONT_MAX_SIZE;
 
 public class BiDiTestActivity extends Activity {
 
     static final String TAG = "BiDiTestActivity";
 
+    static final int INIT_TEXT_SIZE = (FONT_MAX_SIZE - FONT_MIN_SIZE) / 2;
+
+    private BiDiTestView textView;
+    private SeekBar textSizeSeekBar;
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
         setContentView(R.layout.biditest_main);
+
+        textView = (BiDiTestView) findViewById(R.id.main);
+        textView.setCurrentTextSize(INIT_TEXT_SIZE);
+
+        textSizeSeekBar = (SeekBar) findViewById(R.id.seekbar);
+        textSizeSeekBar.setProgress(INIT_TEXT_SIZE);
+        textSizeSeekBar.setMax(FONT_MAX_SIZE - FONT_MIN_SIZE);
+
+        textSizeSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+                textView.setCurrentTextSize(FONT_MIN_SIZE + progress);
+            }
+
+            public void onStartTrackingTouch(SeekBar seekBar) {
+            }
+
+            public void onStopTrackingTouch(SeekBar seekBar) {
+            }
+        });
     }
 
     @Override
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestConstants.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestConstants.java
new file mode 100644
index 0000000..5c28e3d
--- /dev/null
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestConstants.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2011 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.bidi;
+
+public class BiDiTestConstants {
+    public static final int FONT_MIN_SIZE = 8;
+    public static final int FONT_MAX_SIZE = 72;
+}
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java
index e9b6fa6..cd415c2 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java
@@ -32,9 +32,8 @@
 
     private static final int BORDER_PADDING = 4;
     private static final int TEXT_PADDING = 16;
-    private static final int TEXT_SIZE = 32;
-    private static final int ORIGIN = 48;
-    private static final int DELTA_Y = TEXT_SIZE;
+    private static final int TEXT_SIZE = 16;
+    private static final int ORIGIN = 80;
 
     private static final float DEFAULT_ITALIC_SKEW_X = -0.25f;
 
@@ -43,6 +42,8 @@
 
     private String NORMAL_TEXT;
     private String NORMAL_LONG_TEXT;
+    private String NORMAL_LONG_TEXT_2;
+    private String NORMAL_LONG_TEXT_3;
     private String ITALIC_TEXT;
     private String BOLD_TEXT;
     private String BOLD_ITALIC_TEXT;
@@ -51,6 +52,8 @@
 
     private Typeface typeface;
 
+    private int currentTextSize;
+
     public BiDiTestView(Context context) {
         super(context);
         init(context);
@@ -69,6 +72,8 @@
     private void init(Context context) {
         NORMAL_TEXT = context.getString(R.string.normal_text);
         NORMAL_LONG_TEXT = context.getString(R.string.normal_long_text);
+        NORMAL_LONG_TEXT_2 = context.getString(R.string.normal_long_text_2);
+        NORMAL_LONG_TEXT_3 = context.getString(R.string.normal_long_text_3);
         ITALIC_TEXT = context.getString(R.string.italic_text);
         BOLD_TEXT = context.getString(R.string.bold_text);
         BOLD_ITALIC_TEXT = context.getString(R.string.bold_italic_text);
@@ -79,34 +84,50 @@
         paint.setAntiAlias(true);
     }
 
+    public void setCurrentTextSize(int size) {
+        currentTextSize = size;
+        invalidate();
+    }
+
     @Override
     public void onDraw(Canvas canvas) {
         drawInsideRect(canvas, Color.BLACK);
 
-        int deltaX = testString(canvas, NORMAL_TEXT, ORIGIN, ORIGIN, paint, typeface,
-                false, false,  Paint.DIRECTION_LTR);
-        deltaX += testString(canvas, ITALIC_TEXT, ORIGIN + deltaX, ORIGIN, paint, typeface,
-                true, false,  Paint.DIRECTION_LTR);
-        deltaX += testString(canvas, BOLD_TEXT, ORIGIN + deltaX, ORIGIN, paint, typeface,
-                false, true,  Paint.DIRECTION_LTR);
-        deltaX += testString(canvas, BOLD_ITALIC_TEXT, ORIGIN + deltaX, ORIGIN, paint, typeface,
-                true, true,  Paint.DIRECTION_LTR);
+        int deltaX = testString(canvas, NORMAL_TEXT, ORIGIN, ORIGIN,
+                paint, typeface, false, false,  Paint.DIRECTION_LTR, currentTextSize);
+
+        deltaX += testString(canvas, ITALIC_TEXT, ORIGIN + deltaX, ORIGIN,
+                paint, typeface, true, false,  Paint.DIRECTION_LTR, currentTextSize);
+
+        deltaX += testString(canvas, BOLD_TEXT, ORIGIN + deltaX, ORIGIN,
+                paint, typeface, false, true,  Paint.DIRECTION_LTR, currentTextSize);
+
+        deltaX += testString(canvas, BOLD_ITALIC_TEXT, ORIGIN + deltaX, ORIGIN,
+                paint, typeface, true, true,  Paint.DIRECTION_LTR, currentTextSize);
 
         // Test with a long string
-        deltaX = testString(canvas, NORMAL_LONG_TEXT, ORIGIN, ORIGIN + 2 * DELTA_Y, paint, typeface,
-                false, false,  Paint.DIRECTION_LTR);
+        deltaX = testString(canvas, NORMAL_LONG_TEXT, ORIGIN, ORIGIN + 2 * currentTextSize,
+                paint, typeface, false, false,  Paint.DIRECTION_LTR, currentTextSize);
+
+        // Test with a long string
+        deltaX = testString(canvas, NORMAL_LONG_TEXT_2, ORIGIN, ORIGIN + 4 * currentTextSize,
+                paint, typeface, false, false,  Paint.DIRECTION_LTR, currentTextSize);
+
+        // Test with a long string
+        deltaX = testString(canvas, NORMAL_LONG_TEXT_3, ORIGIN, ORIGIN + 6 * currentTextSize,
+                paint, typeface, false, false,  Paint.DIRECTION_LTR, currentTextSize);
 
         // Test Arabic ligature
-        deltaX = testString(canvas, ARABIC_TEXT, ORIGIN, ORIGIN + 4 * DELTA_Y, paint, typeface,
-                false, false,  Paint.DIRECTION_RTL);
+        deltaX = testString(canvas, ARABIC_TEXT, ORIGIN, ORIGIN + 8 * currentTextSize,
+                paint, typeface, false, false,  Paint.DIRECTION_RTL, currentTextSize);
 
         // Test Chinese
-        deltaX = testString(canvas, CHINESE_TEXT, ORIGIN, ORIGIN + 6 * DELTA_Y, paint, typeface,
-                false, false,  Paint.DIRECTION_LTR);
+        deltaX = testString(canvas, CHINESE_TEXT, ORIGIN, ORIGIN + 10 * currentTextSize,
+                paint, typeface, false, false,  Paint.DIRECTION_LTR, currentTextSize);
     }
 
     private int testString(Canvas canvas, String text, int x, int y, Paint paint, Typeface typeface,
-            boolean isItalic, boolean isBold, int dir) {
+            boolean isItalic, boolean isBold, int dir, int textSize) {
         paint.setTypeface(typeface);
 
         // Set paint properties
@@ -118,27 +139,28 @@
             paint.setTextSkewX(DEFAULT_ITALIC_SKEW_X);
         }
 
-        drawTextWithCanvasDrawText(text, canvas, x, y, TEXT_SIZE, Color.WHITE);
+        drawTextWithCanvasDrawText(text, canvas, x, y, textSize, Color.WHITE);
 
         int length = text.length();
         float[] advances = new float[length];
-        float textWidth = paint.getTextRunAdvances(text, 0, length, 0, length, 0, advances, 0);
+        float textWidthHB = paint.getTextRunAdvances(text, 0, length, 0, length, 0, advances, 0);
+        float textWidthICU = paint.getTextRunAdvancesICU(text, 0, length, 0, length, 0, advances, 0);
 
-        logAdvances(text, textWidth, advances);
-        drawBoxAroundText(canvas, x, y, textWidth, TEXT_SIZE, Color.RED);
+        logAdvances(text, textWidthHB, textWidthICU, advances);
+        drawMetricsAroundText(canvas, x, y, textWidthHB, textWidthICU, textSize, Color.RED, Color.GREEN);
 
         paint.setColor(Color.WHITE);
         char[] glyphs = new char[2*length];
         int count = getGlyphs(text, glyphs, dir);
 
-        logGlypths(glyphs, count);
-        drawTextWithDrawGlyph(canvas, glyphs, count, x, y + DELTA_Y);
+//        logGlypths(glyphs, count);
+        drawTextWithDrawGlyph(canvas, glyphs, count, x, y + currentTextSize);
 
         // Restore old paint properties
         paint.setFakeBoldText(oldFakeBold);
         paint.setTextSkewX(oldTextSkewX);
 
-        return (int) Math.ceil(textWidth) + TEXT_PADDING;
+        return (int) Math.ceil(textWidthHB) + TEXT_PADDING;
     }
 
     private void drawTextWithDrawGlyph(Canvas canvas, char[] glyphs, int count, int x, int y) {
@@ -172,19 +194,21 @@
         canvas.drawText(text, x, y, paint);
     }
 
-    private void drawBoxAroundText(Canvas canvas, int x, int y, float textWidth, int textSize,
-            int color) {
+    private void drawMetricsAroundText(Canvas canvas, int x, int y, float textWidthHB,
+            float textWidthICU, int textSize, int color, int colorICU) {
         paint.setColor(color);
         canvas.drawLine(x, y - textSize, x, y + 8, paint);
-        canvas.drawLine(x, y + 8, x + textWidth, y + 8, paint);
-        canvas.drawLine(x + textWidth, y - textSize, x + textWidth, y + 8, paint);
+        canvas.drawLine(x, y + 8, x + textWidthHB, y + 8, paint);
+        canvas.drawLine(x + textWidthHB, y - textSize, x + textWidthHB, y + 8, paint);
+        paint.setColor(colorICU);
+        canvas.drawLine(x + textWidthICU, y - textSize, x + textWidthICU, y + 8, paint);
     }
 
-    private void logAdvances(String text, float textWidth, float[] advances) {
-        Log.v(TAG, "Advances for text: " + text + " total=" + textWidth);
-        int length = advances.length;
-        for(int n=0; n<length; n++){
-            Log.v(TAG, "adv[" + n + "]=" + advances[n]);
-        }
+    private void logAdvances(String text, float textWidth, float textWidthICU, float[] advances) {
+        Log.v(TAG, "Advances for text: " + text + " total= " + textWidth + " - totalICU= " + textWidthICU);
+//        int length = advances.length;
+//        for(int n=0; n<length; n++){
+//            Log.v(TAG, "adv[" + n + "]=" + advances[n]);
+//        }
     }
 }
diff --git a/tests/CoreTests/android/core/HttpHeaderTest.java b/tests/CoreTests/android/core/HttpHeaderTest.java
index a5d48578..eedbc3f 100644
--- a/tests/CoreTests/android/core/HttpHeaderTest.java
+++ b/tests/CoreTests/android/core/HttpHeaderTest.java
@@ -19,12 +19,19 @@
 import org.apache.http.util.CharArrayBuffer;
 
 import android.net.http.Headers;
+import android.util.Log;
+import android.webkit.CacheManager;
+import android.webkit.CacheManager.CacheResult;
+
+import java.lang.reflect.Method;
 
 public class HttpHeaderTest extends AndroidTestCase {
 
     static final String LAST_MODIFIED = "Last-Modified: Fri, 18 Jun 2010 09:56:47 GMT";
     static final String CACHE_CONTROL_MAX_AGE = "Cache-Control:max-age=15";
     static final String CACHE_CONTROL_PRIVATE = "Cache-Control: private";
+    static final String CACHE_CONTROL_COMPOUND = "Cache-Control: no-cache, max-age=200000";
+    static final String CACHE_CONTROL_COMPOUND2 = "Cache-Control: max-age=200000, no-cache";
 
     /**
      * Tests that cache control header supports multiple instances of the header,
@@ -59,4 +66,39 @@
         h.parseHeader(buffer);
         assertEquals("max-age=15,private", h.getCacheControl());
     }
+
+    // Test that cache behaves correctly when receiving a compund
+    // cache-control statement containing no-cache and max-age argument.
+    //
+    // If a cache control header contains both a max-age arument and
+    // a no-cache argument the max-age argument should be ignored.
+    // The resource can be cached, but a validity check must be done on
+    // every request. Test case checks that the expiry time is 0 for
+    // this item, so item will be validated on subsequent requests.
+    public void testCacheControlMultipleArguments() throws Exception {
+        // get private method CacheManager.parseHeaders()
+        Method m = CacheManager.class.getDeclaredMethod("parseHeaders",
+                new Class[] {int.class, Headers.class, String.class});
+        m.setAccessible(true);
+
+        // create indata
+        Headers h = new Headers();
+        CharArrayBuffer buffer = new CharArrayBuffer(64);
+        buffer.append(CACHE_CONTROL_COMPOUND);
+        h.parseHeader(buffer);
+
+        CacheResult c = (CacheResult)m.invoke(null, 200, h, "text/html");
+
+        // Check that expires is set to 0, to ensure that no-cache has overridden
+        // the max-age argument
+        assertEquals(0, c.getExpires());
+
+        // check reverse order
+        buffer.clear();
+        buffer.append(CACHE_CONTROL_COMPOUND2);
+        h.parseHeader(buffer);
+
+        c = (CacheResult)m.invoke(null, 200, h, "text/html");
+        assertEquals(0, c.getExpires());
+    }
 }