Merge change I0fa1b245

* changes:
  telephony: Populate the User-to-user signaling info fields.
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index 100af89..68d8bb0 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -8,7 +8,7 @@
 	stagefright.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-	libstagefright
+	libstagefright libmedia libutils libbinder
 
 LOCAL_C_INCLUDES:= \
 	$(JNI_H_INCLUDE) \
@@ -30,7 +30,7 @@
         record.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-	libstagefright
+	libstagefright liblog libutils libbinder
 
 LOCAL_C_INCLUDES:= \
 	$(JNI_H_INCLUDE) \
@@ -52,7 +52,7 @@
         audioloop.cpp
 
 LOCAL_SHARED_LIBRARIES := \
-	libstagefright
+	libstagefright liblog libutils libbinder
 
 LOCAL_C_INCLUDES:= \
 	$(JNI_H_INCLUDE) \
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index b590449..dfb775f 100644
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -74,6 +74,7 @@
     private int mNativeData;
     private BluetoothEventLoop mEventLoop;
     private boolean mIsAirplaneSensitive;
+    private boolean mIsAirplaneToggleable;
     private int mBluetoothState;
     private boolean mRestart = false;  // need to call enable() after disable()
     private boolean mIsDiscovering;
@@ -370,7 +371,7 @@
                                                 "Need BLUETOOTH_ADMIN permission");
 
         // Airplane mode can prevent Bluetooth radio from being turned on.
-        if (mIsAirplaneSensitive && isAirplaneModeOn()) {
+        if (mIsAirplaneSensitive && isAirplaneModeOn() && !mIsAirplaneToggleable) {
             return false;
         }
         if (mBluetoothState != BluetoothAdapter.STATE_OFF) {
@@ -545,7 +546,7 @@
                 mEventLoop.onPropertyChanged(propVal);
             }
 
-            if (mIsAirplaneSensitive && isAirplaneModeOn()) {
+            if (mIsAirplaneSensitive && isAirplaneModeOn() && !mIsAirplaneToggleable) {
                 disable(false);
             }
 
@@ -1597,10 +1598,17 @@
     };
 
     private void registerForAirplaneMode(IntentFilter filter) {
-        String airplaneModeRadios = Settings.System.getString(mContext.getContentResolver(),
+        final ContentResolver resolver = mContext.getContentResolver();
+        final String airplaneModeRadios = Settings.System.getString(resolver,
                 Settings.System.AIRPLANE_MODE_RADIOS);
-        mIsAirplaneSensitive = airplaneModeRadios == null
-                ? true : airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH);
+        final String toggleableRadios = Settings.System.getString(resolver,
+                Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
+
+        mIsAirplaneSensitive = airplaneModeRadios == null ? true :
+                airplaneModeRadios.contains(Settings.System.RADIO_BLUETOOTH);
+        mIsAirplaneToggleable = toggleableRadios == null ? false :
+                toggleableRadios.contains(Settings.System.RADIO_BLUETOOTH);
+
         if (mIsAirplaneSensitive) {
             filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
         }
@@ -1661,6 +1669,7 @@
         }
 
         pw.println("mIsAirplaneSensitive = " + mIsAirplaneSensitive);
+        pw.println("mIsAirplaneToggleable = " + mIsAirplaneToggleable);
 
         pw.println("Local address = " + getAddress());
         pw.println("Local name = " + getName());
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index b6ac14a..880e459 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -171,9 +171,10 @@
     public Adapter1D createAdapter1D() {
         mRS.validate();
         int id = mRS.nAdapter1DCreate();
-        if (id != 0) {
-            mRS.nAdapter1DBindAllocation(id, mID);
+        if(id == 0) {
+            throw new IllegalStateException("allocation failed.");
         }
+        mRS.nAdapter1DBindAllocation(id, mID);
         return new Adapter1D(id, mRS);
     }
 
@@ -213,9 +214,10 @@
     public Adapter2D createAdapter2D() {
         mRS.validate();
         int id = mRS.nAdapter2DCreate();
-        if (id != 0) {
-            mRS.nAdapter2DBindAllocation(id, mID);
+        if(id == 0) {
+            throw new IllegalStateException("allocation failed.");
         }
+        mRS.nAdapter2DBindAllocation(id, mID);
         return new Adapter2D(id, mRS);
     }
 
@@ -258,6 +260,9 @@
 
         rs.validate();
         int id = rs.nAllocationCreateFromBitmap(dstFmt.mID, genMips, b);
+        if(id == 0) {
+            throw new IllegalStateException("Load failed.");
+        }
         return new Allocation(id, rs, null);
     }
 
@@ -266,6 +271,9 @@
 
         rs.validate();
         int id = rs.nAllocationCreateFromBitmapBoxed(dstFmt.mID, genMips, b);
+        if(id == 0) {
+            throw new IllegalStateException("Load failed.");
+        }
         return new Allocation(id, rs, null);
     }
 
@@ -282,6 +290,9 @@
             int allocationId = rs.nAllocationCreateFromAssetStream(dstFmt.mID, genMips,
                     asset);
 
+            if(allocationId == 0) {
+                throw new IllegalStateException("Load failed.");
+            }
             return new Allocation(allocationId, rs, null);
         } catch (Exception e) {
             // Ignore
diff --git a/graphics/java/android/renderscript/BaseObj.java b/graphics/java/android/renderscript/BaseObj.java
index e802ec51..002fc78 100644
--- a/graphics/java/android/renderscript/BaseObj.java
+++ b/graphics/java/android/renderscript/BaseObj.java
@@ -25,6 +25,7 @@
 class BaseObj {
 
     BaseObj(RenderScript rs) {
+        rs.validate();
         mRS = rs;
         mID = 0;
         mDestroyed = false;
diff --git a/graphics/java/android/renderscript/Element.java b/graphics/java/android/renderscript/Element.java
index ee9b098..1324179a 100644
--- a/graphics/java/android/renderscript/Element.java
+++ b/graphics/java/android/renderscript/Element.java
@@ -24,248 +24,66 @@
  **/
 public class Element extends BaseObj {
     int mSize;
-    Entry[] mEntries;
+    Element[] mElements;
+    String[] mElementNames;
 
-    int getSizeBytes() {
-        return mSize;
-    }
-    int getComponentCount() {
-        return mEntries.length;
-    }
-    Element.DataType getComponentDataType(int num) {
-        return mEntries[num].mType;
-    }
-    Element.DataKind getComponentDataKind(int num) {
-        return mEntries[num].mKind;
-    }
-    boolean getComponentIsNormalized(int num) {
-        return mEntries[num].mIsNormalized;
-    }
-    int getComponentBits(int num) {
-        return mEntries[num].mBits;
-    }
-    String getComponentName(int num) {
-        return mEntries[num].mName;
-    }
+    DataType mType;
+    DataKind mKind;
+    boolean mNormalized;
+    int mVectorSize;
 
-    static class Entry {
-        //Element mElement;
-        Element.DataType mType;
-        Element.DataKind mKind;
-        boolean mIsNormalized;
-        int mBits;
-        String mName;
-
-        //Entry(Element e, int bits) {
-            //mElement = e;
-            //int mBits = bits;
-        //}
-
-        Entry(DataType dt, DataKind dk, boolean isNorm, int bits, String name) {
-            mType = dt;
-            mKind = dk;
-            mIsNormalized = isNorm;
-            mBits = bits;
-            mName = name;
-        }
-    }
-
-    public static Element USER_U8(RenderScript rs) {
-        if(rs.mElement_USER_U8 == null) {
-            rs.mElement_USER_U8 = new Element(rs, 1);
-            rs.mElement_USER_U8.mEntries[0] = new Entry(DataType.UNSIGNED, DataKind.USER, false, 8, null);
-            rs.mElement_USER_U8.init();
-        }
-        return rs.mElement_USER_U8;
-    }
-
-    public static Element USER_I8(RenderScript rs) {
-        if(rs.mElement_USER_I8 == null) {
-            rs.mElement_USER_I8 = new Element(rs, 1);
-            rs.mElement_USER_I8.mEntries[0] = new Entry(DataType.SIGNED, DataKind.USER, false, 8, null);
-            rs.mElement_USER_I8.init();
-        }
-        return rs.mElement_USER_I8;
-    }
-
-    public static Element USER_U16(RenderScript rs) {
-        if(rs.mElement_USER_U16 == null) {
-            rs.mElement_USER_U16 = new Element(rs, 1);
-            rs.mElement_USER_U16.mEntries[0] = new Entry(DataType.UNSIGNED, DataKind.USER, false, 16, null);
-            rs.mElement_USER_U16.init();
-        }
-        return rs.mElement_USER_U16;
-    }
-
-    public static Element USER_I16(RenderScript rs) {
-        if(rs.mElement_USER_I16 == null) {
-            rs.mElement_USER_I16 = new Element(rs, 1);
-            rs.mElement_USER_I16.mEntries[0] = new Entry(DataType.SIGNED, DataKind.USER, false, 16, null);
-            rs.mElement_USER_I16.init();
-        }
-        return rs.mElement_USER_I16;
-    }
-
-    public static Element USER_U32(RenderScript rs) {
-        if(rs.mElement_USER_U32 == null) {
-            rs.mElement_USER_U32 = new Element(rs, 1);
-            rs.mElement_USER_U32.mEntries[0] = new Entry(DataType.UNSIGNED, DataKind.USER, false, 32, null);
-            rs.mElement_USER_U32.init();
-        }
-        return rs.mElement_USER_U32;
-    }
-
-    public static Element USER_I32(RenderScript rs) {
-        if(rs.mElement_USER_I32 == null) {
-            rs.mElement_USER_I32 = new Element(rs, 1);
-            rs.mElement_USER_I32.mEntries[0] = new Entry(DataType.SIGNED, DataKind.USER, false, 32, null);
-            rs.mElement_USER_I32.init();
-        }
-        return rs.mElement_USER_I32;
-    }
-
-    public static Element USER_F32(RenderScript rs) {
-        if(rs.mElement_USER_FLOAT == null) {
-            rs.mElement_USER_FLOAT = new Element(rs, 1);
-            rs.mElement_USER_FLOAT.mEntries[0] = new Entry(DataType.FLOAT, DataKind.USER, false, 32, null);
-            rs.mElement_USER_FLOAT.init();
-        }
-        return rs.mElement_USER_FLOAT;
-    }
-
-    public static Element A_8(RenderScript rs) {
-        if(rs.mElement_A_8 == null) {
-            rs.mElement_A_8 = new Element(rs, 1);
-            rs.mElement_A_8.mEntries[0] = new Entry(DataType.UNSIGNED, DataKind.ALPHA, true, 8, "a");
-            rs.mElement_A_8.init();
-        }
-        return rs.mElement_A_8;
-    }
-
-    public static Element RGB_565(RenderScript rs) {
-        if(rs.mElement_RGB_565 == null) {
-            rs.mElement_RGB_565 = new Element(rs, 3);
-            rs.mElement_RGB_565.mEntries[0] = new Entry(DataType.UNSIGNED, DataKind.RED, true, 5, "r");
-            rs.mElement_RGB_565.mEntries[1] = new Entry(DataType.UNSIGNED, DataKind.GREEN, true, 6, "g");
-            rs.mElement_RGB_565.mEntries[2] = new Entry(DataType.UNSIGNED, DataKind.BLUE, true, 5, "b");
-            rs.mElement_RGB_565.init();
-        }
-        return rs.mElement_RGB_565;
-    }
-
-    public static Element RGB_888(RenderScript rs) {
-        if(rs.mElement_RGB_888 == null) {
-            rs.mElement_RGB_888 = new Element(rs, 3);
-            rs.mElement_RGB_888.mEntries[0] = new Entry(DataType.UNSIGNED, DataKind.RED, true, 8, "r");
-            rs.mElement_RGB_888.mEntries[1] = new Entry(DataType.UNSIGNED, DataKind.GREEN, true, 8, "g");
-            rs.mElement_RGB_888.mEntries[2] = new Entry(DataType.UNSIGNED, DataKind.BLUE, true, 8, "b");
-            rs.mElement_RGB_888.init();
-        }
-        return rs.mElement_RGB_888;
-    }
-
-    public static Element RGBA_5551(RenderScript rs) {
-        if(rs.mElement_RGBA_5551 == null) {
-            rs.mElement_RGBA_5551 = new Element(rs, 4);
-            rs.mElement_RGBA_5551.mEntries[0] = new Entry(DataType.UNSIGNED, DataKind.RED, true, 5, "r");
-            rs.mElement_RGBA_5551.mEntries[1] = new Entry(DataType.UNSIGNED, DataKind.GREEN, true, 5, "g");
-            rs.mElement_RGBA_5551.mEntries[2] = new Entry(DataType.UNSIGNED, DataKind.BLUE, true, 5, "b");
-            rs.mElement_RGBA_5551.mEntries[3] = new Entry(DataType.UNSIGNED, DataKind.ALPHA, true, 1, "a");
-            rs.mElement_RGBA_5551.init();
-        }
-        return rs.mElement_RGBA_5551;
-    }
-
-    public static Element RGBA_4444(RenderScript rs) {
-        if(rs.mElement_RGBA_4444 == null) {
-            rs.mElement_RGBA_4444 = new Element(rs, 4);
-            rs.mElement_RGBA_4444.mEntries[0] = new Entry(DataType.UNSIGNED, DataKind.RED, true, 4, "r");
-            rs.mElement_RGBA_4444.mEntries[1] = new Entry(DataType.UNSIGNED, DataKind.GREEN, true, 4, "g");
-            rs.mElement_RGBA_4444.mEntries[2] = new Entry(DataType.UNSIGNED, DataKind.BLUE, true, 4, "b");
-            rs.mElement_RGBA_4444.mEntries[3] = new Entry(DataType.UNSIGNED, DataKind.ALPHA, true, 4, "a");
-            rs.mElement_RGBA_4444.init();
-        }
-        return rs.mElement_RGBA_4444;
-    }
-
-    public static Element RGBA_8888(RenderScript rs) {
-        if(rs.mElement_RGBA_8888 == null) {
-            rs.mElement_RGBA_8888 = new Element(rs, 4);
-            rs.mElement_RGBA_8888.mEntries[0] = new Entry(DataType.UNSIGNED, DataKind.RED, true, 8, "r");
-            rs.mElement_RGBA_8888.mEntries[1] = new Entry(DataType.UNSIGNED, DataKind.GREEN, true, 8, "g");
-            rs.mElement_RGBA_8888.mEntries[2] = new Entry(DataType.UNSIGNED, DataKind.BLUE, true, 8, "b");
-            rs.mElement_RGBA_8888.mEntries[3] = new Entry(DataType.UNSIGNED, DataKind.ALPHA, true, 8, "a");
-            rs.mElement_RGBA_8888.init();
-        }
-        return rs.mElement_RGBA_8888;
-    }
-
-    public static Element INDEX_16(RenderScript rs) {
-        if(rs.mElement_INDEX_16 == null) {
-            rs.mElement_INDEX_16 = new Element(rs, 1);
-            rs.mElement_INDEX_16.mEntries[0] = new Entry(DataType.UNSIGNED, DataKind.INDEX, false, 16, "index");
-            rs.mElement_INDEX_16.init();
-        }
-        return rs.mElement_INDEX_16;
-    }
-
-    public static Element XY_F32(RenderScript rs) {
-        if(rs.mElement_XY_F32 == null) {
-            rs.mElement_XY_F32 = new Element(rs, 2);
-            rs.mElement_XY_F32.mEntries[0] = new Entry(DataType.UNSIGNED, DataKind.X, false, 32, "x");
-            rs.mElement_XY_F32.mEntries[1] = new Entry(DataType.UNSIGNED, DataKind.Y, false, 32, "y");
-            rs.mElement_XY_F32.init();
-        }
-        return rs.mElement_XY_F32;
-    }
-
-    public static Element XYZ_F32(RenderScript rs) {
-        if(rs.mElement_XYZ_F32 == null) {
-            rs.mElement_XYZ_F32 = new Element(rs, 3);
-            rs.mElement_XYZ_F32.mEntries[0] = new Entry(DataType.UNSIGNED, DataKind.X, false, 32, "x");
-            rs.mElement_XYZ_F32.mEntries[1] = new Entry(DataType.UNSIGNED, DataKind.Y, false, 32, "y");
-            rs.mElement_XYZ_F32.mEntries[2] = new Entry(DataType.UNSIGNED, DataKind.Z, false, 32, "z");
-            rs.mElement_XYZ_F32.init();
-        }
-        return rs.mElement_XYZ_F32;
-    }
-
-    static void initPredefined(RenderScript rs) {
-        rs.nInitElements(A_8(rs).mID, RGBA_4444(rs).mID, RGBA_8888(rs).mID, RGB_565(rs).mID);
-    }
+    int getSizeBytes() {return mSize;}
 
     public enum DataType {
-        FLOAT (0),
-        UNSIGNED (1),
-        SIGNED (2);
+        //FLOAT_16 (1, 2),
+        FLOAT_32 (2, 4),
+        //FLOAT_64 (3, 8),
+        SIGNED_8 (4, 1),
+        SIGNED_16 (5, 2),
+        SIGNED_32 (6, 4),
+        //SIGNED_64 (7, 8),
+        UNSIGNED_8 (8, 1),
+        UNSIGNED_16 (9, 2),
+        UNSIGNED_32 (10, 4),
+        //UNSIGNED_64 (11, 8),
+
+        UNSIGNED_5_6_5 (12, 2),
+        UNSIGNED_5_5_5_1 (13, 2),
+        UNSIGNED_4_4_4_4 (14, 2),
+
+        RS_ELEMENT (15, 4),
+        RS_TYPE (16, 4),
+        RS_ALLOCATION (17, 4),
+        RS_SAMPLER (18, 4),
+        RS_SCRIPT (19, 4),
+        RS_MESH (20, 4),
+        RS_PROGRAM_FRAGMENT (21, 4),
+        RS_PROGRAM_VERTEX (22, 4),
+        RS_PROGRAM_RASTER (23, 4),
+        RS_PROGRAM_STORE (24, 4);
 
         int mID;
-        DataType(int id) {
+        int mSize;
+        DataType(int id, int size) {
             mID = id;
+            mSize = size;
         }
     }
 
     public enum DataKind {
         USER (0),
-        RED (1),
-        GREEN (2),
-        BLUE (3),
-        ALPHA (4),
-        LUMINANCE (5),
-        INTENSITY (6),
-        X (7),
-        Y (8),
-        Z (9),
-        W (10),
-        S (11),
-        T (12),
-        Q (13),
-        R (14),
-        NX (15),
-        NY (16),
-        NZ (17),
-        INDEX (18),
-        POINT_SIZE(19);
+        COLOR (1),
+        POSITION (2),
+        TEXTURE (3),
+        NORMAL (4),
+        INDEX (5),
+        POINT_SIZE(6),
+
+        PIXEL_L (7),
+        PIXEL_A (8),
+        PIXEL_LA (9),
+        PIXEL_RGB (10),
+        PIXEL_RGBA (11);
 
         int mID;
         DataKind(int id) {
@@ -273,10 +91,153 @@
         }
     }
 
-    Element(RenderScript rs, int count) {
+    public static Element USER_U8(RenderScript rs) {
+        if(rs.mElement_USER_U8 == null) {
+            rs.mElement_USER_U8 = createUser(rs, DataType.UNSIGNED_8);
+        }
+        return rs.mElement_USER_U8;
+    }
+
+    public static Element USER_I8(RenderScript rs) {
+        if(rs.mElement_USER_I8 == null) {
+            rs.mElement_USER_I8 = createUser(rs, DataType.SIGNED_8);
+        }
+        return rs.mElement_USER_I8;
+    }
+
+    public static Element USER_U32(RenderScript rs) {
+        if(rs.mElement_USER_U32 == null) {
+            rs.mElement_USER_U32 = createUser(rs, DataType.UNSIGNED_32);
+        }
+        return rs.mElement_USER_U32;
+    }
+
+    public static Element USER_I32(RenderScript rs) {
+        if(rs.mElement_USER_I32 == null) {
+            rs.mElement_USER_I32 = createUser(rs, DataType.SIGNED_32);
+        }
+        return rs.mElement_USER_I32;
+    }
+
+    public static Element USER_F32(RenderScript rs) {
+        if(rs.mElement_USER_F32 == null) {
+            rs.mElement_USER_F32 = createUser(rs, DataType.FLOAT_32);
+        }
+        return rs.mElement_USER_F32;
+    }
+
+    public static Element A_8(RenderScript rs) {
+        if(rs.mElement_A_8 == null) {
+            rs.mElement_A_8 = createPixel(rs, DataType.UNSIGNED_8, DataKind.PIXEL_A);
+        }
+        return rs.mElement_A_8;
+    }
+
+    public static Element RGB_565(RenderScript rs) {
+        if(rs.mElement_RGB_565 == null) {
+            rs.mElement_RGB_565 = createPixel(rs, DataType.UNSIGNED_5_6_5, DataKind.PIXEL_RGB);
+        }
+        return rs.mElement_RGB_565;
+    }
+
+    public static Element RGB_888(RenderScript rs) {
+        if(rs.mElement_RGB_888 == null) {
+            rs.mElement_RGB_888 = createPixel(rs, DataType.UNSIGNED_8, DataKind.PIXEL_RGB);
+        }
+        return rs.mElement_RGB_888;
+    }
+
+    public static Element RGBA_5551(RenderScript rs) {
+        if(rs.mElement_RGBA_5551 == null) {
+            rs.mElement_RGBA_5551 = createPixel(rs, DataType.UNSIGNED_5_5_5_1, DataKind.PIXEL_RGBA);
+        }
+        return rs.mElement_RGBA_5551;
+    }
+
+    public static Element RGBA_4444(RenderScript rs) {
+        if(rs.mElement_RGBA_4444 == null) {
+            rs.mElement_RGBA_4444 = createPixel(rs, DataType.UNSIGNED_4_4_4_4, DataKind.PIXEL_RGBA);
+        }
+        return rs.mElement_RGBA_4444;
+    }
+
+    public static Element RGBA_8888(RenderScript rs) {
+        if(rs.mElement_RGBA_8888 == null) {
+            rs.mElement_RGBA_8888 = createPixel(rs, DataType.UNSIGNED_8, DataKind.PIXEL_RGBA);
+        }
+        return rs.mElement_RGBA_8888;
+    }
+
+    public static Element INDEX_16(RenderScript rs) {
+        if(rs.mElement_INDEX_16 == null) {
+            rs.mElement_INDEX_16 = createIndex(rs);
+        }
+        return rs.mElement_INDEX_16;
+    }
+
+    public static Element ATTRIB_POSITION_2(RenderScript rs) {
+        if(rs.mElement_POSITION_2 == null) {
+            rs.mElement_POSITION_2 = createAttrib(rs, DataType.FLOAT_32, DataKind.POSITION, 2);
+        }
+        return rs.mElement_POSITION_2;
+    }
+
+    public static Element ATTRIB_POSITION_3(RenderScript rs) {
+        if(rs.mElement_POSITION_3 == null) {
+            rs.mElement_POSITION_3 = createAttrib(rs, DataType.FLOAT_32, DataKind.POSITION, 3);
+        }
+        return rs.mElement_POSITION_3;
+    }
+
+    public static Element ATTRIB_TEXTURE_2(RenderScript rs) {
+        if(rs.mElement_TEXTURE_2 == null) {
+            rs.mElement_TEXTURE_2 = createAttrib(rs, DataType.FLOAT_32, DataKind.TEXTURE, 2);
+        }
+        return rs.mElement_TEXTURE_2;
+    }
+
+    public static Element ATTRIB_NORMAL_3(RenderScript rs) {
+        if(rs.mElement_NORMAL_3 == null) {
+            rs.mElement_NORMAL_3 = createAttrib(rs, DataType.FLOAT_32, DataKind.NORMAL, 3);
+        }
+        return rs.mElement_NORMAL_3;
+    }
+
+    public static Element ATTRIB_COLOR_U8_4(RenderScript rs) {
+        if(rs.mElement_COLOR_U8_4 == null) {
+            rs.mElement_COLOR_U8_4 = createAttrib(rs, DataType.UNSIGNED_8, DataKind.COLOR, 4);
+        }
+        return rs.mElement_COLOR_U8_4;
+    }
+
+    public static Element ATTRIB_COLOR_F32_4(RenderScript rs) {
+        if(rs.mElement_COLOR_F32_4 == null) {
+            rs.mElement_COLOR_F32_4 = createAttrib(rs, DataType.FLOAT_32, DataKind.COLOR, 4);
+        }
+        return rs.mElement_COLOR_F32_4;
+    }
+
+    Element(RenderScript rs, Element[] e, String[] n) {
         super(rs);
         mSize = 0;
-        mEntries = new Entry[count];
+        mElements = e;
+        mElementNames = n;
+        int[] ids = new int[mElements.length];
+        for (int ct = 0; ct < mElements.length; ct++ ) {
+            mSize += mElements[ct].mSize;
+            ids[ct] = mElements[ct].mID;
+        }
+        mID = rs.nElementCreate2(ids, mElementNames);
+    }
+
+    Element(RenderScript rs, DataType dt, DataKind dk, boolean norm, int size) {
+        super(rs);
+        mSize = dt.mSize * size;
+        mType = dt;
+        mKind = dk;
+        mNormalized = norm;
+        mVectorSize = size;
+        mID = rs.nElementCreate(dt.mID, dk.mID, norm, size);
     }
 
     public void destroy() throws IllegalStateException {
@@ -291,13 +252,13 @@
         for(Field f: fields) {
             Class fc = f.getType();
             if(fc == int.class) {
-                b.add(Element.DataType.SIGNED, Element.DataKind.USER, false, 32, f.getName());
+                b.add(createUser(rs, DataType.SIGNED_32), f.getName());
             } else if(fc == short.class) {
-                b.add(Element.DataType.SIGNED, Element.DataKind.USER, false, 16, f.getName());
+                b.add(createUser(rs, DataType.SIGNED_16), f.getName());
             } else if(fc == byte.class) {
-                b.add(Element.DataType.SIGNED, Element.DataKind.USER, false, 8, f.getName());
+                b.add(createUser(rs, DataType.SIGNED_8), f.getName());
             } else if(fc == float.class) {
-                b.add(Element.DataType.FLOAT, Element.DataKind.USER, false, 32, f.getName());
+                b.add(createUser(rs, DataType.FLOAT_32), f.getName());
             } else {
                 throw new IllegalArgumentException("Unkown field type");
             }
@@ -305,193 +266,156 @@
         return b.create();
     }
 
-    static synchronized void internalCreate(RenderScript rs, Element e) {
-        rs.nElementBegin();
-        int bits = 0;
-        for (int ct=0; ct < e.mEntries.length; ct++) {
-            Entry en = e.mEntries[ct];
-            //if(en.mElement !=  null) {
-                //rs.nElementAdd(en.mElement.mID);
-            //} else
-            {
-                rs.nElementAdd(en.mKind.mID, en.mType.mID, en.mIsNormalized, en.mBits, en.mName);
-                bits += en.mBits;
-            }
+
+    /////////////////////////////////////////
+    public static Element createUser(RenderScript rs, DataType dt) {
+        return new Element(rs, dt, DataKind.USER, false, 1);
+    }
+
+    public static Element createVector(RenderScript rs, DataType dt, int size) {
+        if (size < 2 || size > 4) {
+            throw new IllegalArgumentException("Bad size");
         }
-        e.mID = rs.nElementCreate();
-        e.mSize = (bits + 7) >> 3;
+        return new Element(rs, dt, DataKind.USER, false, size);
     }
 
-    void init() {
-        mRS.validate();
-        internalCreate(mRS, this);
+    public static Element createIndex(RenderScript rs) {
+        return new Element(rs, DataType.UNSIGNED_16, DataKind.INDEX, false, 1);
     }
 
+    public static Element createAttrib(RenderScript rs, DataType dt, DataKind dk, int size) {
+        if (!(dt == DataType.FLOAT_32 ||
+              dt == DataType.UNSIGNED_8 ||
+              dt == DataType.UNSIGNED_16 ||
+              dt == DataType.UNSIGNED_32 ||
+              dt == DataType.SIGNED_8 ||
+              dt == DataType.SIGNED_16 ||
+              dt == DataType.SIGNED_32)) {
+            throw new IllegalArgumentException("Unsupported DataType");
+        }
+
+        if (!(dk == DataKind.COLOR ||
+              dk == DataKind.POSITION ||
+              dk == DataKind.TEXTURE ||
+              dk == DataKind.NORMAL ||
+              dk == DataKind.POINT_SIZE)) {
+            throw new IllegalArgumentException("Unsupported DataKind");
+        }
+
+        if (dk == DataKind.COLOR &&
+            ((dt != DataType.FLOAT_32 && dt != DataType.UNSIGNED_8) ||
+             size < 3 || size > 4)) {
+            throw new IllegalArgumentException("Bad combo");
+        }
+        if (dk == DataKind.POSITION && (size < 1 || size > 4)) {
+            throw new IllegalArgumentException("Bad combo");
+        }
+        if (dk == DataKind.TEXTURE &&
+            (dt != DataType.FLOAT_32 || size < 1 || size > 4)) {
+            throw new IllegalArgumentException("Bad combo");
+        }
+        if (dk == DataKind.NORMAL &&
+            (dt != DataType.FLOAT_32 || size != 3)) {
+            throw new IllegalArgumentException("Bad combo");
+        }
+        if (dk == DataKind.POINT_SIZE &&
+            (dt != DataType.FLOAT_32 || size != 1)) {
+            throw new IllegalArgumentException("Bad combo");
+        }
+
+        boolean norm = false;
+        if (dk == DataKind.COLOR && dt == DataType.UNSIGNED_8) {
+            norm = true;
+        }
+
+        return new Element(rs, dt, dk, norm, size);
+    }
+
+    public static Element createPixel(RenderScript rs, DataType dt, DataKind dk) {
+        if (!(dk == DataKind.PIXEL_L ||
+              dk == DataKind.PIXEL_A ||
+              dk == DataKind.PIXEL_LA ||
+              dk == DataKind.PIXEL_RGB ||
+              dk == DataKind.PIXEL_RGBA)) {
+            throw new IllegalArgumentException("Unsupported DataKind");
+        }
+        if (!(dt == DataType.UNSIGNED_8 ||
+              dt == DataType.UNSIGNED_5_6_5 ||
+              dt == DataType.UNSIGNED_4_4_4_4 ||
+              dt == DataType.UNSIGNED_5_5_5_1)) {
+            throw new IllegalArgumentException("Unsupported DataType");
+        }
+        if (dt == DataType.UNSIGNED_5_6_5 && dk != DataKind.PIXEL_RGB) {
+            throw new IllegalArgumentException("Bad kind and type combo");
+        }
+        if (dt == DataType.UNSIGNED_5_5_5_1 && dk != DataKind.PIXEL_RGBA) {
+            throw new IllegalArgumentException("Bad kind and type combo");
+        }
+        if (dt == DataType.UNSIGNED_4_4_4_4 && dk != DataKind.PIXEL_RGBA) {
+            throw new IllegalArgumentException("Bad kind and type combo");
+        }
+
+        int size = 1;
+        if (dk == DataKind.PIXEL_LA) {
+            size = 2;
+        }
+        if (dk == DataKind.PIXEL_RGB) {
+            size = 3;
+        }
+        if (dk == DataKind.PIXEL_RGBA) {
+            size = 4;
+        }
+
+        return new Element(rs, dt, dk, true, size);
+    }
 
     public static class Builder {
         RenderScript mRS;
-        Entry[] mEntries;
-        int mEntryCount;
+        Element[] mElements;
+        String[] mElementNames;
+        int mCount;
 
         public Builder(RenderScript rs) {
             mRS = rs;
-            mEntryCount = 0;
-            mEntries = new Entry[8];
+            mCount = 0;
+            mElements = new Element[8];
+            mElementNames = new String[8];
         }
 
-        void addEntry(Entry e) {
-            if(mEntries.length >= mEntryCount) {
-                Entry[] en = new Entry[mEntryCount + 8];
-                System.arraycopy(mEntries, 0, en, 0, mEntries.length);
-                mEntries = en;
+        public void add(Element element, String name) {
+            if(mCount == mElements.length) {
+                Element[] e = new Element[mCount + 8];
+                String[] s = new String[mCount + 8];
+                System.arraycopy(mElements, 0, e, 0, mCount);
+                System.arraycopy(mElementNames, 0, s, 0, mCount);
+                mElements = e;
+                mElementNames = s;
             }
-            mEntries[mEntryCount] = e;
-            mEntryCount++;
-        }
-
-        //public Builder add(Element e) throws IllegalArgumentException {
-            //Entry en = new Entry(e, e.mSize * 8);
-            //addEntry(en);
-            //return this;
-        //}
-
-        public Builder add(Element.DataType dt, Element.DataKind dk, boolean isNormalized, int bits, String name) {
-            Entry en = new Entry(dt, dk, isNormalized, bits, name);
-            addEntry(en);
-            return this;
-        }
-
-        public Builder add(Element.DataType dt, Element.DataKind dk, boolean isNormalized, int bits) {
-            add(dt, dk, isNormalized, bits, null);
-            return this;
-        }
-
-        public Builder addFloat(Element.DataKind dk) {
-            add(DataType.FLOAT, dk, false, 32, null);
-            return this;
-        }
-
-        public Builder addFloat(Element.DataKind dk, String name) {
-            add(DataType.FLOAT, dk, false, 32, name);
-            return this;
-        }
-
-        public Builder addFloatXY() {
-            add(DataType.FLOAT, DataKind.X, false, 32, null);
-            add(DataType.FLOAT, DataKind.Y, false, 32, null);
-            return this;
-        }
-
-        public Builder addFloatXY(String prefix) {
-            add(DataType.FLOAT, DataKind.X, false, 32, prefix + "x");
-            add(DataType.FLOAT, DataKind.Y, false, 32, prefix + "y");
-            return this;
-        }
-
-        public Builder addFloatXYZ() {
-            add(DataType.FLOAT, DataKind.X, false, 32, null);
-            add(DataType.FLOAT, DataKind.Y, false, 32, null);
-            add(DataType.FLOAT, DataKind.Z, false, 32, null);
-            return this;
-        }
-
-        public Builder addFloatXYZ(String prefix) {
-            add(DataType.FLOAT, DataKind.X, false, 32, prefix + "x");
-            add(DataType.FLOAT, DataKind.Y, false, 32, prefix + "y");
-            add(DataType.FLOAT, DataKind.Z, false, 32, prefix + "z");
-            return this;
-        }
-
-        public Builder addFloatST() {
-            add(DataType.FLOAT, DataKind.S, false, 32, null);
-            add(DataType.FLOAT, DataKind.T, false, 32, null);
-            return this;
-        }
-
-        public Builder addFloatST(String prefix) {
-            add(DataType.FLOAT, DataKind.S, false, 32, prefix + "s");
-            add(DataType.FLOAT, DataKind.T, false, 32, prefix + "t");
-            return this;
-        }
-
-        public Builder addFloatNorm() {
-            add(DataType.FLOAT, DataKind.NX, false, 32, null);
-            add(DataType.FLOAT, DataKind.NY, false, 32, null);
-            add(DataType.FLOAT, DataKind.NZ, false, 32, null);
-            return this;
-        }
-
-        public Builder addFloatNorm(String prefix) {
-            add(DataType.FLOAT, DataKind.NX, false, 32, prefix + "nx");
-            add(DataType.FLOAT, DataKind.NY, false, 32, prefix + "ny");
-            add(DataType.FLOAT, DataKind.NZ, false, 32, prefix + "nz");
-            return this;
-        }
-
-        public Builder addFloatPointSize() {
-            add(DataType.FLOAT, DataKind.POINT_SIZE, false, 32, null);
-            return this;
-        }
-
-        public Builder addFloatPointSize(String prefix) {
-            add(DataType.FLOAT, DataKind.POINT_SIZE, false, 32, prefix + "pointSize");
-            return this;
-        }
-
-        public Builder addFloatRGB() {
-            add(DataType.FLOAT, DataKind.RED, false, 32, null);
-            add(DataType.FLOAT, DataKind.GREEN, false, 32, null);
-            add(DataType.FLOAT, DataKind.BLUE, false, 32, null);
-            return this;
-        }
-
-        public Builder addFloatRGB(String prefix) {
-            add(DataType.FLOAT, DataKind.RED, false, 32, prefix + "r");
-            add(DataType.FLOAT, DataKind.GREEN, false, 32, prefix + "g");
-            add(DataType.FLOAT, DataKind.BLUE, false, 32, prefix + "b");
-            return this;
-        }
-
-        public Builder addFloatRGBA() {
-            add(DataType.FLOAT, DataKind.RED, false, 32, null);
-            add(DataType.FLOAT, DataKind.GREEN, false, 32, null);
-            add(DataType.FLOAT, DataKind.BLUE, false, 32, null);
-            add(DataType.FLOAT, DataKind.ALPHA, false, 32, null);
-            return this;
-        }
-
-        public Builder addFloatRGBA(String prefix) {
-            add(DataType.FLOAT, DataKind.RED, false, 32, prefix + "r");
-            add(DataType.FLOAT, DataKind.GREEN, false, 32, prefix + "g");
-            add(DataType.FLOAT, DataKind.BLUE, false, 32, prefix + "b");
-            add(DataType.FLOAT, DataKind.ALPHA, false, 32, prefix + "a");
-            return this;
-        }
-
-        public Builder addUNorm8RGBA() {
-            add(DataType.UNSIGNED, DataKind.RED, true, 8, null);
-            add(DataType.UNSIGNED, DataKind.GREEN, true, 8, null);
-            add(DataType.UNSIGNED, DataKind.BLUE, true, 8, null);
-            add(DataType.UNSIGNED, DataKind.ALPHA, true, 8, null);
-            return this;
-        }
-
-        public Builder addUNorm8RGBA(String prefix) {
-            add(DataType.UNSIGNED, DataKind.RED, true, 8, prefix + "r");
-            add(DataType.UNSIGNED, DataKind.GREEN, true, 8, prefix + "g");
-            add(DataType.UNSIGNED, DataKind.BLUE, true, 8, prefix + "b");
-            add(DataType.UNSIGNED, DataKind.ALPHA, true, 8, prefix + "a");
-            return this;
+            mElements[mCount] = element;
+            mElementNames[mCount] = name;
+            mCount++;
         }
 
         public Element create() {
             mRS.validate();
-            Element e = new Element(mRS, mEntryCount);
-            java.lang.System.arraycopy(mEntries, 0, e.mEntries, 0, mEntryCount);
-            e.init();
-            return e;
+            Element[] ein = new Element[mCount];
+            String[] sin = new String[mCount];
+            java.lang.System.arraycopy(mElements, 0, ein, 0, mCount);
+            java.lang.System.arraycopy(mElementNames, 0, sin, 0, mCount);
+            return new Element(mRS, ein, sin);
         }
     }
 
+    static void initPredefined(RenderScript rs) {
+        int a8 = rs.nElementCreate(DataType.UNSIGNED_8.mID,
+                                   DataKind.PIXEL_A.mID, true, 1);
+        int rgba4444 = rs.nElementCreate(DataType.UNSIGNED_4_4_4_4.mID,
+                                         DataKind.PIXEL_RGBA.mID, true, 4);
+        int rgba8888 = rs.nElementCreate(DataType.UNSIGNED_8.mID,
+                                         DataKind.PIXEL_RGBA.mID, true, 4);
+        int rgb565 = rs.nElementCreate(DataType.UNSIGNED_5_6_5.mID,
+                                       DataKind.PIXEL_RGB.mID, true, 3);
+        rs.nInitElements(a8, rgba4444, rgba8888, rgb565);
+    }
 }
 
diff --git a/graphics/java/android/renderscript/ProgramVertex.java b/graphics/java/android/renderscript/ProgramVertex.java
index 101f030..84f6f2d 100644
--- a/graphics/java/android/renderscript/ProgramVertex.java
+++ b/graphics/java/android/renderscript/ProgramVertex.java
@@ -107,7 +107,7 @@
             mProjection = new Matrix();
             mTexture = new Matrix();
 
-            mAlloc = Allocation.createSized(rs, Element.USER_F32(rs), 48);
+            mAlloc = Allocation.createSized(rs, Element.createUser(rs, Element.DataType.FLOAT_32), 48);
             mAlloc.subData1D(MODELVIEW_OFFSET, 16, mModel.mMat);
             mAlloc.subData1D(PROJECTION_OFFSET, 16, mProjection.mMat);
             mAlloc.subData1D(TEXTURE_OFFSET, 16, mTexture.mMat);
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index 6574219..cc97a8f 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -89,9 +89,9 @@
     native void nObjDestroyOOB(int id);
     native int  nFileOpen(byte[] name);
 
-    native void nElementBegin();
-    native void nElementAdd(int kind, int type, boolean norm, int bits, String s);
-    native int  nElementCreate();
+
+    native int  nElementCreate(int type, int kind, boolean norm, int vecSize);
+    native int  nElementCreate2(int[] elements, String[] names);
 
     native void nTypeBegin(int elementID);
     native void nTypeAdd(int dim, int val);
@@ -198,14 +198,13 @@
     private Surface mSurface;
     private MessageThread mMessageThread;
 
-
     Element mElement_USER_U8;
     Element mElement_USER_I8;
     Element mElement_USER_U16;
     Element mElement_USER_I16;
     Element mElement_USER_U32;
     Element mElement_USER_I32;
-    Element mElement_USER_FLOAT;
+    Element mElement_USER_F32;
 
     Element mElement_A_8;
     Element mElement_RGB_565;
@@ -215,9 +214,12 @@
     Element mElement_RGBA_8888;
 
     Element mElement_INDEX_16;
-    Element mElement_XY_F32;
-    Element mElement_XYZ_F32;
-
+    Element mElement_POSITION_2;
+    Element mElement_POSITION_3;
+    Element mElement_TEXTURE_2;
+    Element mElement_NORMAL_3;
+    Element mElement_COLOR_U8_4;
+    Element mElement_COLOR_F32_4;
 
     ///////////////////////////////////////////////////////////////////////////////////
     //
@@ -303,9 +305,9 @@
             nDeviceSetConfig(mDev, 0, 1);
         }
         mContext = nContextCreate(mDev, 0, useDepth);
-        Element.initPredefined(this);
         mMessageThread = new MessageThread(this);
         mMessageThread.start();
+        Element.initPredefined(this);
     }
 
     public void contextSetSurface(int w, int h, Surface sur) {
diff --git a/graphics/java/android/renderscript/SimpleMesh.java b/graphics/java/android/renderscript/SimpleMesh.java
index f45074e..4a217a9 100644
--- a/graphics/java/android/renderscript/SimpleMesh.java
+++ b/graphics/java/android/renderscript/SimpleMesh.java
@@ -313,28 +313,36 @@
         public SimpleMesh create() {
             Element.Builder b = new Element.Builder(mRS);
             int floatCount = mVtxSize;
-            if (mVtxSize == 2) {
-                b.addFloatXY();
-            } else {
-                b.addFloatXYZ();
-            }
+            b.add(Element.createAttrib(mRS,
+                                       Element.DataType.FLOAT_32,
+                                       Element.DataKind.POSITION,
+                                       mVtxSize), "position");
             if ((mFlags & COLOR) != 0) {
                 floatCount += 4;
-                b.addFloatRGBA();
+                b.add(Element.createAttrib(mRS,
+                                           Element.DataType.FLOAT_32,
+                                           Element.DataKind.COLOR,
+                                           4), "color");
             }
             if ((mFlags & TEXTURE_0) != 0) {
                 floatCount += 2;
-                b.addFloatST();
+                b.add(Element.createAttrib(mRS,
+                                           Element.DataType.FLOAT_32,
+                                           Element.DataKind.TEXTURE,
+                                           2), "texture");
             }
             if ((mFlags & NORMAL) != 0) {
                 floatCount += 3;
-                b.addFloatNorm();
+                b.add(Element.createAttrib(mRS,
+                                           Element.DataType.FLOAT_32,
+                                           Element.DataKind.NORMAL,
+                                           3), "normal");
             }
             mElement = b.create();
 
             Builder smb = new Builder(mRS);
             smb.addVertexType(mElement, mVtxCount / floatCount);
-            smb.setIndexType(Element.INDEX_16(mRS), mIndexCount);
+            smb.setIndexType(Element.createIndex(mRS), mIndexCount);
             smb.setPrimitive(Primitive.TRIANGLE);
             SimpleMesh sm = smb.create();
 
diff --git a/graphics/java/android/renderscript/Type.java b/graphics/java/android/renderscript/Type.java
index ad4cf6b..8e59a31 100644
--- a/graphics/java/android/renderscript/Type.java
+++ b/graphics/java/android/renderscript/Type.java
@@ -122,16 +122,16 @@
                 Field f = fields[ct];
                 Class fc = f.getType();
                 if(fc == int.class) {
-                    arTypes[ct] = Element.DataType.SIGNED.mID;
+                    arTypes[ct] = Element.DataType.SIGNED_32.mID;
                     arBits[ct] = 32;
                 } else if(fc == short.class) {
-                    arTypes[ct] = Element.DataType.SIGNED.mID;
+                    arTypes[ct] = Element.DataType.SIGNED_16.mID;
                     arBits[ct] = 16;
                 } else if(fc == byte.class) {
-                    arTypes[ct] = Element.DataType.SIGNED.mID;
+                    arTypes[ct] = Element.DataType.SIGNED_8.mID;
                     arBits[ct] = 8;
                 } else if(fc == float.class) {
-                    arTypes[ct] = Element.DataType.FLOAT.mID;
+                    arTypes[ct] = Element.DataType.FLOAT_32.mID;
                     arBits[ct] = 32;
                 } else {
                     throw new IllegalArgumentException("Unkown field type");
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index 6ae93a7..f4e752f 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -247,36 +247,39 @@
 }
 
 
-static void
-nElementBegin(JNIEnv *_env, jobject _this)
+static jint
+nElementCreate(JNIEnv *_env, jobject _this, jint type, jint kind, jboolean norm, jint size)
 {
     RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
-    LOG_API("nElementBegin, con(%p)", con);
-    rsElementBegin(con);
-}
-
-
-static void
-nElementAdd(JNIEnv *_env, jobject _this, jint kind, jint type, jboolean norm, jint bits, jstring name)
-{
-    RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
-    const char* n = NULL;
-    if (name) {
-        n = _env->GetStringUTFChars(name, NULL);
-    }
-    LOG_API("nElementAdd, con(%p), kind(%i), type(%i), norm(%i), bits(%i)", con, kind, type, norm, bits);
-    rsElementAdd(con, (RsDataKind)kind, (RsDataType)type, norm != 0, (size_t)bits, n);
-    if (n) {
-        _env->ReleaseStringUTFChars(name, n);
-    }
+    LOG_API("nElementCreate, con(%p), type(%i), kind(%i), norm(%i), size(%i)", con, type, kind, norm, size);
+    return (jint)rsElementCreate(con, (RsDataType)type, (RsDataKind)kind, norm, size);
 }
 
 static jint
-nElementCreate(JNIEnv *_env, jobject _this)
+nElementCreate2(JNIEnv *_env, jobject _this, jintArray _ids, jobjectArray _names)
 {
+    int fieldCount = _env->GetArrayLength(_ids);
     RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
-    LOG_API("nElementCreate, con(%p)", con);
-    return (jint)rsElementCreate(con);
+    LOG_API("nElementCreate, con(%p), type(%i), kind(%i), norm(%i), size(%i)", con, type, kind, norm, size);
+
+    jint *ids = _env->GetIntArrayElements(_ids, NULL);
+    const char ** nameArray = (const char **)calloc(fieldCount, sizeof(char *));
+    size_t* sizeArray = (size_t*)calloc(fieldCount, sizeof(size_t));
+
+    for (int ct=0; ct < fieldCount; ct++) {
+        jstring s = (jstring)_env->GetObjectArrayElement(_names, ct);
+        nameArray[ct] = _env->GetStringUTFChars(s, NULL);
+        sizeArray[ct] = _env->GetStringUTFLength(s);
+    }
+    jint id = (jint)rsElementCreate2(con, fieldCount, (RsElement *)ids, nameArray, sizeArray);
+    for (int ct=0; ct < fieldCount; ct++) {
+        jstring s = (jstring)_env->GetObjectArrayElement(_names, ct);
+        _env->ReleaseStringUTFChars(s, nameArray[ct]);
+    }
+    _env->ReleaseIntArrayElements(_ids, ids, JNI_ABORT);
+    free(nameArray);
+    free(sizeArray);
+    return (jint)id;
 }
 
 // -----------------------------------
@@ -395,26 +398,24 @@
         tfc[ct].bits = fBits[ct];
 
         switch(fType[ct]) {
-        case RS_TYPE_FLOAT:
+        case RS_TYPE_FLOAT_32:
             tfc[ct].ptr = SF_LoadFloat;
             tfc[ct].readPtr = SF_SaveFloat;
             break;
-        case RS_TYPE_UNSIGNED:
-        case RS_TYPE_SIGNED:
-            switch(tfc[ct].bits) {
-            case 32:
-                tfc[ct].ptr = SF_LoadInt;
-                tfc[ct].readPtr = SF_SaveInt;
-                break;
-            case 16:
-                tfc[ct].ptr = SF_LoadShort;
-                tfc[ct].readPtr = SF_SaveShort;
-                break;
-            case 8:
-                tfc[ct].ptr = SF_LoadByte;
-                tfc[ct].readPtr = SF_SaveByte;
-                break;
-            }
+        case RS_TYPE_UNSIGNED_32:
+        case RS_TYPE_SIGNED_32:
+            tfc[ct].ptr = SF_LoadInt;
+            tfc[ct].readPtr = SF_SaveInt;
+            break;
+        case RS_TYPE_UNSIGNED_16:
+        case RS_TYPE_SIGNED_16:
+            tfc[ct].ptr = SF_LoadShort;
+            tfc[ct].readPtr = SF_SaveShort;
+            break;
+        case RS_TYPE_UNSIGNED_8:
+        case RS_TYPE_SIGNED_8:
+            tfc[ct].ptr = SF_LoadByte;
+            tfc[ct].readPtr = SF_SaveByte;
             break;
         }
         tc->size += 4;
@@ -1367,9 +1368,8 @@
 
 {"nFileOpen",                      "([B)I",                                (void*)nFileOpen },
 
-{"nElementBegin",                  "()V",                                  (void*)nElementBegin },
-{"nElementAdd",                    "(IIZILjava/lang/String;)V",            (void*)nElementAdd },
-{"nElementCreate",                 "()I",                                  (void*)nElementCreate },
+{"nElementCreate",                 "(IIZI)I",                              (void*)nElementCreate },
+{"nElementCreate2",                "([I[Ljava/lang/String;)I",             (void*)nElementCreate2 },
 
 {"nTypeBegin",                     "(I)V",                                 (void*)nTypeBegin },
 {"nTypeAdd",                       "(II)V",                                (void*)nTypeAdd },
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 29aaa3f..c87007c 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -282,7 +282,8 @@
         FORCE_BT_SCO,
         FORCE_BT_A2DP,
         FORCE_WIRED_ACCESSORY,
-        FORCE_BT_DOCK,
+        FORCE_BT_CAR_DOCK,
+        FORCE_BT_DESK_DOCK,
         NUM_FORCE_CONFIG,
         FORCE_DEFAULT = FORCE_NONE
     };
diff --git a/libs/rs/Android.mk b/libs/rs/Android.mk
index 111bdd4..3080ab0 100644
--- a/libs/rs/Android.mk
+++ b/libs/rs/Android.mk
@@ -76,6 +76,7 @@
 LOCAL_SRC_FILES:= \
 	rsAdapter.cpp \
 	rsAllocation.cpp \
+	rsComponent.cpp \
 	rsContext.cpp \
 	rsDevice.cpp \
 	rsElement.cpp \
diff --git a/libs/rs/RenderScript.h b/libs/rs/RenderScript.h
index d10eeda..bb2c06a 100644
--- a/libs/rs/RenderScript.h
+++ b/libs/rs/RenderScript.h
@@ -66,32 +66,50 @@
 #define RS_MAX_TEXTURE 2
 
 enum RsDataType {
-    RS_TYPE_FLOAT,
-    RS_TYPE_UNSIGNED,
-    RS_TYPE_SIGNED
+    RS_TYPE_NONE,
+    RS_TYPE_FLOAT_16,
+    RS_TYPE_FLOAT_32,
+    RS_TYPE_FLOAT_64,
+    RS_TYPE_SIGNED_8,
+    RS_TYPE_SIGNED_16,
+    RS_TYPE_SIGNED_32,
+    RS_TYPE_SIGNED_64,
+    RS_TYPE_UNSIGNED_8,
+    RS_TYPE_UNSIGNED_16,
+    RS_TYPE_UNSIGNED_32,
+    RS_TYPE_UNSIGNED_64,
+
+    RS_TYPE_UNSIGNED_5_6_5,
+    RS_TYPE_UNSIGNED_5_5_5_1,
+    RS_TYPE_UNSIGNED_4_4_4_4,
+
+    RS_TYPE_ELEMENT,
+    RS_TYPE_TYPE,
+    RS_TYPE_ALLOCATION,
+    RS_TYPE_SAMPLER,
+    RS_TYPE_SCRIPT,
+    RS_TYPE_MESH,
+    RS_TYPE_PROGRAM_FRAGMENT,
+    RS_TYPE_PROGRAM_VERTEX,
+    RS_TYPE_PROGRAM_RASTER,
+    RS_TYPE_PROGRAM_STORE
 };
 
 enum RsDataKind {
     RS_KIND_USER,
-    RS_KIND_RED,
-    RS_KIND_GREEN,
-    RS_KIND_BLUE,
-    RS_KIND_ALPHA,
-    RS_KIND_LUMINANCE,
-    RS_KIND_INTENSITY,
-    RS_KIND_X,
-    RS_KIND_Y,
-    RS_KIND_Z,
-    RS_KIND_W,
-    RS_KIND_S,
-    RS_KIND_T,
-    RS_KIND_Q,
-    RS_KIND_R,
-    RS_KIND_NX,
-    RS_KIND_NY,
-    RS_KIND_NZ,
+    RS_KIND_COLOR,
+    RS_KIND_POSITION,
+    RS_KIND_TEXTURE,
+    RS_KIND_NORMAL,
     RS_KIND_INDEX,
-    RS_KIND_POINT_SIZE
+    RS_KIND_POINT_SIZE,
+
+    RS_KIND_PIXEL_L,
+    RS_KIND_PIXEL_A,
+    RS_KIND_PIXEL_LA,
+    RS_KIND_PIXEL_RGB,
+    RS_KIND_PIXEL_RGBA,
+
 };
 
 enum RsSamplerParam {
diff --git a/libs/rs/java/Film/src/com/android/film/FilmRS.java b/libs/rs/java/Film/src/com/android/film/FilmRS.java
index dccc1d2..fcf487c 100644
--- a/libs/rs/java/Film/src/com/android/film/FilmRS.java
+++ b/libs/rs/java/Film/src/com/android/film/FilmRS.java
@@ -152,10 +152,13 @@
         mBufferIDs = new int[13];
         mImages = new Allocation[13];
         mAllocIDs = Allocation.createSized(mRS,
-            Element.USER_F32(mRS), mBufferIDs.length);
+            Element.createUser(mRS, Element.DataType.FLOAT_32),
+            mBufferIDs.length);
 
-        Element ie = Element.RGB_565(mRS);
+        Element ie = Element.createPixel(mRS, Element.DataType.UNSIGNED_5_6_5, Element.DataKind.PIXEL_RGB);
+        android.util.Log.e("rs", "load 1");
         mImages[0] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p01, ie, true);
+        android.util.Log.e("rs", "load 2");
         mImages[1] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p02, ie, true);
         mImages[2] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p03, ie, true);
         mImages[3] = Allocation.createFromBitmapResourceBoxed(mRS, mRes, R.drawable.p04, ie, true);
@@ -195,7 +198,8 @@
     {
         mBufferState = new int[10];
         mAllocState = Allocation.createSized(mRS,
-            Element.USER_F32(mRS), mBufferState.length);
+            Element.createUser(mRS, Element.DataType.FLOAT_32),
+            mBufferState.length);
         mBufferState[STATE_LAST_FOCUS] = -1;
         mAllocState.data(mBufferState);
     }
@@ -238,12 +242,12 @@
 
 
         mAllocOffsets = Allocation.createSized(mRS,
-            Element.USER_I32(mRS), mFSM.mTriangleOffsets.length);
+            Element.createUser(mRS, Element.DataType.SIGNED_32), mFSM.mTriangleOffsets.length);
         mAllocOffsets.data(mFSM.mTriangleOffsets);
         mScriptStrip.bindAllocation(mAllocOffsets, 4);
 
         mAllocOffsetsTex = Allocation.createSized(mRS,
-            Element.USER_F32(mRS), mFSM.mTriangleOffsetsTex.length);
+            Element.createUser(mRS, Element.DataType.FLOAT_32), mFSM.mTriangleOffsetsTex.length);
         mAllocOffsetsTex.data(mFSM.mTriangleOffsetsTex);
         mScriptStrip.bindAllocation(mAllocOffsetsTex, 5);
 
diff --git a/libs/rs/java/Fountain/res/raw/fountain.c b/libs/rs/java/Fountain/res/raw/fountain.c
index f218f9b..73b819b 100644
--- a/libs/rs/java/Fountain/res/raw/fountain.c
+++ b/libs/rs/java/Fountain/res/raw/fountain.c
@@ -14,19 +14,17 @@
         float rMax = ((float)rate) * 0.005f;
         int x = Control->x;
         int y = Control->y;
-        char r = Control->r * 255.f;
-        char g = Control->g * 255.f;
-        char b = Control->b * 255.f;
+        int color = ((int)(Control->r * 255.f)) |
+                    ((int)(Control->g * 255.f)) << 8 |
+                    ((int)(Control->b * 255.f)) << 16 |
+                    (0xf0 << 24);
         struct point_s * np = &p[newPart];
 
         while (rate--) {
-            vec2Rand((float *)np, rMax);
-            np->x = x;
-            np->y = y;
-            np->r = r;
-            np->g = g;
-            np->b = b;
-            np->a = 0xf0;
+            vec2Rand((float *)&np->delta.x, rMax);
+            np->position.x = x;
+            np->position.y = y;
+            np->color = color;
             newPart++;
             np++;
             if (newPart >= count) {
@@ -37,14 +35,14 @@
     }
 
     for (ct=0; ct < count; ct++) {
-        float dy = p->dy + 0.15f;
-        float posy = p->y + dy;
+        float dy = p->delta.y + 0.15f;
+        float posy = p->position.y + dy;
         if ((posy > height) && (dy > 0)) {
             dy *= -0.3f;
         }
-        p->dy = dy;
-        p->x += p->dx;
-        p->y = posy;
+        p->delta.y = dy;
+        p->position.x += p->delta.x;
+        p->position.y = posy;
         p++;
     }
 
diff --git a/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java b/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java
index f4f9b0c..71f95a7 100644
--- a/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java
+++ b/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java
@@ -79,10 +79,9 @@
         mIntAlloc.data(mSD);
 
         Element.Builder eb = new Element.Builder(mRS);
-        eb.addFloat(Element.DataKind.USER, "dx");
-        eb.addFloat(Element.DataKind.USER, "dy");
-        eb.addFloatXY("");
-        eb.addUNorm8RGBA("");
+        eb.add(Element.createVector(mRS, Element.DataType.FLOAT_32, 2), "delta");
+        eb.add(Element.createAttrib(mRS, Element.DataType.FLOAT_32, Element.DataKind.POSITION, 2), "position");
+        eb.add(Element.createAttrib(mRS, Element.DataType.UNSIGNED_8, Element.DataKind.COLOR, 4), "color");
         Element primElement = eb.create();
 
 
diff --git a/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
index 334fd9c..0ca00b3 100644
--- a/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
+++ b/libs/rs/java/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
@@ -62,7 +62,7 @@
 
         public float threshold;
     }
-    
+
     static class Pixel {
         public byte a;
         public byte r;
@@ -78,7 +78,7 @@
                         mParams.outWidth, mParams.outHeight);
                 mDisplayView.invalidate();
             }
-        };        
+        };
 
         @Override
         public void run() {
@@ -131,7 +131,7 @@
 
     public void surfaceDestroyed(SurfaceHolder holder) {
     }
-        
+
     private Script.Invokable createScript() {
         mRS = new RenderScript(false, false);
         mRS.mMessageCallback = new FilterCallback();
@@ -143,9 +143,11 @@
         final int pixelCount = mParams.inWidth * mParams.inHeight;
 
         mPixelType = Type.createFromClass(mRS, Pixel.class, 1, "Pixel");
-        mInPixelsAllocation = Allocation.createSized(mRS, Element.USER_I32(mRS),
+        mInPixelsAllocation = Allocation.createSized(mRS,
+                Element.createUser(mRS, Element.DataType.SIGNED_32),
                 pixelCount);
-        mOutPixelsAllocation = Allocation.createSized(mRS, Element.USER_I32(mRS),
+        mOutPixelsAllocation = Allocation.createSized(mRS,
+                Element.createUser(mRS, Element.DataType.SIGNED_32),
                 pixelCount);
 
         final int[] data = new int[pixelCount];
@@ -154,7 +156,7 @@
 
         mOutData = new int[pixelCount];
         mOutPixelsAllocation.data(mOutData);
-        
+
         ScriptC.Builder sb = new ScriptC.Builder(mRS);
         sb.setType(mParamsType, "Params", 0);
         sb.setType(mPixelType, "InPixel", 1);
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index df415685..d12431f 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -60,18 +60,19 @@
 	param void *obj
 	}
 
-ElementBegin {
-}
-
-ElementAdd {
-	param RsDataKind dataKind
-	param RsDataType dataType
-	param bool isNormalized
-	param size_t bits
-	param const char * name
+ElementCreate {
+	param RsDataType mType
+	param RsDataKind mKind
+	param bool mNormalized
+	param uint32_t mVectorSize
+	ret RsElement
 	}
 
-ElementCreate {
+ElementCreate2 {
+	param size_t count
+	param const RsElement * elements
+	param const char ** names
+	param const size_t * nameLengths
 	ret RsElement
 	}
 
diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp
index 7f76390..19699dc 100644
--- a/libs/rs/rsAllocation.cpp
+++ b/libs/rs/rsAllocation.cpp
@@ -106,8 +106,8 @@
         return;
     }
 
-    GLenum type = mType->getElement()->getGLType();
-    GLenum format = mType->getElement()->getGLFormat();
+    GLenum type = mType->getElement()->getComponent().getGLType();
+    GLenum format = mType->getElement()->getComponent().getGLFormat();
 
     if (!type || !format) {
         return;
@@ -422,10 +422,10 @@
 
 static ElementConverter_t pickConverter(const Element *dst, const Element *src)
 {
-    GLenum srcGLType = src->getGLType();
-    GLenum srcGLFmt = src->getGLFormat();
-    GLenum dstGLType = dst->getGLType();
-    GLenum dstGLFmt = dst->getGLFormat();
+    GLenum srcGLType = src->getComponent().getGLType();
+    GLenum srcGLFmt = src->getComponent().getGLFormat();
+    GLenum dstGLType = dst->getComponent().getGLType();
+    GLenum dstGLFmt = dst->getComponent().getGLFormat();
 
     if (srcGLFmt == dstGLFmt && srcGLType == dstGLType) {
         switch(dst->getSizeBytes()) {
diff --git a/libs/rs/rsComponent.cpp b/libs/rs/rsComponent.cpp
new file mode 100644
index 0000000..0574343
--- /dev/null
+++ b/libs/rs/rsComponent.cpp
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+#include "rsComponent.h"
+
+#include <GLES/gl.h>
+
+using namespace android;
+using namespace android::renderscript;
+
+Component::Component()
+{
+    set(RS_TYPE_NONE, RS_KIND_USER, false, 1);
+}
+
+Component::~Component()
+{
+}
+
+void Component::set(RsDataType dt, RsDataKind dk, bool norm, uint32_t vecSize)
+{
+    mType = dt;
+    mKind = dk;
+    mNormalized = norm;
+    mVectorSize = vecSize;
+    rsAssert(vecSize <= 4);
+
+    mBits = 0;
+    mTypeBits = 0;
+    mIsFloat = false;
+    mIsSigned = false;
+    mIsPixel = false;
+
+    switch(mKind) {
+    case RS_KIND_PIXEL_L:
+    case RS_KIND_PIXEL_A:
+        mIsPixel = true;
+        rsAssert(mVectorSize == 1);
+        rsAssert(mNormalized == true);
+        break;
+    case RS_KIND_PIXEL_LA:
+        mIsPixel = true;
+        rsAssert(mVectorSize == 2);
+        rsAssert(mNormalized == true);
+        break;
+    case RS_KIND_PIXEL_RGB:
+        mIsPixel = true;
+        rsAssert(mVectorSize == 3);
+        rsAssert(mNormalized == true);
+        break;
+    case RS_KIND_PIXEL_RGBA:
+        mIsPixel = true;
+        rsAssert(mVectorSize == 4);
+        rsAssert(mNormalized == true);
+        break;
+    default:
+        break;
+    }
+
+    switch(mType) {
+    case RS_TYPE_NONE:
+        return;
+    case RS_TYPE_UNSIGNED_5_6_5:
+        mVectorSize = 3;
+        mBits = 16;
+        mNormalized = true;
+        rsAssert(mKind == RS_KIND_PIXEL_RGB);
+        return;
+    case RS_TYPE_UNSIGNED_5_5_5_1:
+        mVectorSize = 4;
+        mBits = 16;
+        mNormalized = true;
+        rsAssert(mKind == RS_KIND_PIXEL_RGBA);
+        return;
+    case RS_TYPE_UNSIGNED_4_4_4_4:
+        mVectorSize = 4;
+        mBits = 16;
+        mNormalized = true;
+        rsAssert(mKind == RS_KIND_PIXEL_RGBA);
+        return;
+    case RS_TYPE_ELEMENT:
+    case RS_TYPE_TYPE:
+    case RS_TYPE_ALLOCATION:
+    case RS_TYPE_SAMPLER:
+    case RS_TYPE_SCRIPT:
+    case RS_TYPE_MESH:
+    case RS_TYPE_PROGRAM_FRAGMENT:
+    case RS_TYPE_PROGRAM_VERTEX:
+    case RS_TYPE_PROGRAM_RASTER:
+    case RS_TYPE_PROGRAM_STORE:
+        rsAssert(mVectorSize == 1);
+        rsAssert(mNormalized == false);
+        rsAssert(mKind == RS_KIND_USER);
+        mBits = 32;
+        mTypeBits = 32;
+        return;
+
+    case RS_TYPE_FLOAT_16:
+        mTypeBits = 16;
+        mIsFloat = true;
+        break;
+    case RS_TYPE_FLOAT_32:
+        mTypeBits = 32;
+        mIsFloat = true;
+        break;
+    case RS_TYPE_FLOAT_64:
+        mTypeBits = 64;
+        mIsFloat = true;
+        break;
+    case RS_TYPE_SIGNED_8:
+        mTypeBits = 8;
+        mIsSigned = true;
+        break;
+    case RS_TYPE_SIGNED_16:
+        mTypeBits = 16;
+        mIsSigned = true;
+        break;
+    case RS_TYPE_SIGNED_32:
+        mTypeBits = 32;
+        mIsSigned = true;
+        break;
+    case RS_TYPE_SIGNED_64:
+        mTypeBits = 64;
+        mIsSigned = true;
+        break;
+    case RS_TYPE_UNSIGNED_8:
+        mTypeBits = 8;
+        break;
+    case RS_TYPE_UNSIGNED_16:
+        mTypeBits = 16;
+        break;
+    case RS_TYPE_UNSIGNED_32:
+        mTypeBits = 32;
+        break;
+    case RS_TYPE_UNSIGNED_64:
+        mTypeBits = 64;
+        break;
+    }
+
+    mBits = mTypeBits * mVectorSize;
+}
+
+
+
+
+uint32_t Component::getGLType() const
+{
+    switch (mType) {
+    case RS_TYPE_UNSIGNED_5_6_5:    return GL_UNSIGNED_SHORT_5_6_5;
+    case RS_TYPE_UNSIGNED_5_5_5_1:  return GL_UNSIGNED_SHORT_5_5_5_1;
+    case RS_TYPE_UNSIGNED_4_4_4_4:  return GL_UNSIGNED_SHORT_4_4_4_4;
+
+    //case RS_TYPE_FLOAT_16:      return GL_HALF_FLOAT;
+    case RS_TYPE_FLOAT_32:      return GL_FLOAT;
+    case RS_TYPE_UNSIGNED_8:    return GL_UNSIGNED_BYTE;
+    case RS_TYPE_UNSIGNED_16:   return GL_UNSIGNED_SHORT;
+    case RS_TYPE_SIGNED_8:      return GL_BYTE;
+    case RS_TYPE_SIGNED_16:     return GL_SHORT;
+    default:    break;
+    }
+
+    return 0;
+}
+
+uint32_t Component::getGLFormat() const
+{
+    switch (mKind) {
+    case RS_KIND_PIXEL_L: return GL_LUMINANCE;
+    case RS_KIND_PIXEL_A: return GL_ALPHA;
+    case RS_KIND_PIXEL_LA: return GL_LUMINANCE_ALPHA;
+    case RS_KIND_PIXEL_RGB: return GL_RGB;
+    case RS_KIND_PIXEL_RGBA: return GL_RGBA;
+    default: break;
+    }
+    return 0;
+}
+
+static const char * gCTypeStrings[] = {
+    0,
+    0,//"F16",
+    "float",
+    "double",
+    "char",
+    "short",
+    "int",
+    0,//"S64",
+    "char",//U8",
+    "short",//U16",
+    "int",//U32",
+    0,//"U64",
+    0,//"UP_565",
+    0,//"UP_5551",
+    0,//"UP_4444",
+    0,//"ELEMENT",
+    0,//"TYPE",
+    0,//"ALLOCATION",
+    0,//"SAMPLER",
+    0,//"SCRIPT",
+    0,//"MESH",
+    0,//"PROGRAM_FRAGMENT",
+    0,//"PROGRAM_VERTEX",
+    0,//"PROGRAM_RASTER",
+    0,//"PROGRAM_STORE",
+};
+
+static const char * gCVecTypeStrings[] = {
+    0,
+    0,//"F16",
+    "vecF32",
+    "vecF64",
+    "vecI8",
+    "vecI16",
+    "vecI32",
+    0,//"S64",
+    "vecU8",//U8",
+    "vecU16",//U16",
+    "vecU32",//U32",
+    0,//"U64",
+    0,//"UP_565",
+    0,//"UP_5551",
+    0,//"UP_4444",
+    0,//"ELEMENT",
+    0,//"TYPE",
+    0,//"ALLOCATION",
+    0,//"SAMPLER",
+    0,//"SCRIPT",
+    0,//"MESH",
+    0,//"PROGRAM_FRAGMENT",
+    0,//"PROGRAM_VERTEX",
+    0,//"PROGRAM_RASTER",
+    0,//"PROGRAM_STORE",
+};
+
+String8 Component::getCType() const
+{
+    char buf[64];
+    if (mVectorSize == 1) {
+        return String8(gCTypeStrings[mType]);
+    }
+
+    // Yuck, acc WAR
+    // Appears to have problems packing chars
+    if (mVectorSize == 4 && mType == RS_TYPE_UNSIGNED_8) {
+        return String8("int");
+    }
+
+
+    String8 s(gCVecTypeStrings[mType]);
+    sprintf(buf, "_%i_t", mVectorSize);
+    s.append(buf);
+    return s;
+}
+
+static const char * gTypeStrings[] = {
+    "NONE",
+    "F16",
+    "F32",
+    "F64",
+    "S8",
+    "S16",
+    "S32",
+    "S64",
+    "U8",
+    "U16",
+    "U32",
+    "U64",
+    "UP_565",
+    "UP_5551",
+    "UP_4444",
+    "ELEMENT",
+    "TYPE",
+    "ALLOCATION",
+    "SAMPLER",
+    "SCRIPT",
+    "MESH",
+    "PROGRAM_FRAGMENT",
+    "PROGRAM_VERTEX",
+    "PROGRAM_RASTER",
+    "PROGRAM_STORE",
+};
+
+static const char * gKindStrings[] = {
+    "USER",
+    "COLOR",
+    "POSITION",
+    "TEXTURE",
+    "NORMAL",
+    "INDEX",
+    "POINT_SIZE",
+    "PIXEL_L",
+    "PIXEL_A",
+    "PIXEL_LA",
+    "PIXEL_RGB",
+    "PIXEL_RGBA",
+};
+
+void Component::dumpLOGV(const char *prefix) const
+{
+    LOGV("%s   Component: %s, %s, vectorSize=%i, bits=%i",
+         prefix, gTypeStrings[mType], gKindStrings[mKind], mVectorSize, mBits);
+}
+
+
diff --git a/libs/rs/rsComponent.h b/libs/rs/rsComponent.h
new file mode 100644
index 0000000..c122c8e
--- /dev/null
+++ b/libs/rs/rsComponent.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2009 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 ANDROID_COMPONENT_H
+#define ANDROID_COMPONENT_H
+
+#include "rsUtils.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+
+// An element is a group of Components that occupies one cell in a structure.
+class Component
+{
+public:
+    Component();
+    ~Component();
+
+    void set(RsDataType dt, RsDataKind dk, bool norm, uint32_t vecSize=1);
+
+    uint32_t getGLType() const;
+    uint32_t getGLFormat() const;
+    String8 getCType() const;
+    void dumpLOGV(const char *prefix) const;
+
+
+    RsDataType getType() const {return mType;}
+    RsDataKind getKind() const {return mKind;}
+    bool getIsNormalized() const {return mNormalized;}
+    uint32_t getVectorSize() const {return mVectorSize;}
+    bool getIsFloat() const {return mIsFloat;}
+    bool getIsSigned() const {return mIsSigned;}
+    uint32_t getBits() const {return mBits;}
+
+protected:
+    RsDataType mType;
+    RsDataKind mKind;
+    bool mNormalized;
+    uint32_t mVectorSize;
+
+    // derived
+    uint32_t mBits;
+    uint32_t mTypeBits;
+    bool mIsFloat;
+    bool mIsSigned;
+    bool mIsPixel;
+};
+
+}
+}
+
+#endif
+
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index 8f56efa..11f26b9 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -142,6 +142,13 @@
     return ret;
 }
 
+void Context::checkError(const char *msg) const
+{
+    GLenum err = glGetError();
+    if (err != GL_NO_ERROR) {
+        LOGE("GL Error, 0x%x, from %s", err, msg);
+    }
+}
 
 uint32_t Context::runRootScript()
 {
@@ -169,11 +176,7 @@
     mStateFragmentStore.mLast.clear();
     uint32_t ret = runScript(mRootScript.get(), 0);
 
-    GLenum err = glGetError();
-    if (err != GL_NO_ERROR) {
-        LOGE("Pending GL Error, 0x%x", err);
-    }
-
+    checkError("runRootScript");
     return ret;
 }
 
@@ -340,10 +343,6 @@
      rsc->mObjDestroy.mNeedToEmpty = true;
      rsc->objDestroyOOBRun();
 
-     glClearColor(0,0,0,0);
-     glClear(GL_COLOR_BUFFER_BIT);
-     eglSwapBuffers(rsc->mEGL.mDisplay, rsc->mEGL.mSurface);
-
      pthread_mutex_lock(&gInitMutex);
      rsc->deinitEGL();
      pthread_mutex_unlock(&gInitMutex);
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index dd0423e..aa7436d 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -168,6 +168,7 @@
     } props;
 
     void dumpDebug() const;
+    void checkError(const char *) const;
 
     mutable const ObjectBase * mObjHead;
 
diff --git a/libs/rs/rsElement.cpp b/libs/rs/rsElement.cpp
index e796556..9944c0e 100644
--- a/libs/rs/rsElement.cpp
+++ b/libs/rs/rsElement.cpp
@@ -24,9 +24,6 @@
 
 Element::Element(Context *rsc) : ObjectBase(rsc)
 {
-    mType = RS_TYPE_FLOAT;
-    mIsNormalized = false;
-    mKind = RS_KIND_USER;
     mBits = 0;
     mAllocFile = __FILE__;
     mAllocLine = __LINE__;
@@ -80,161 +77,6 @@
     return offset;
 }
 
-uint32_t Element::getGLType() const
-{
-    int bits[4];
-
-    if (!mFieldCount) {
-        switch (mType) {
-        case RS_TYPE_FLOAT:
-            if (mBits == 32) {
-                return GL_FLOAT;
-            }
-            return 0;
-        case RS_TYPE_SIGNED:
-            switch (mBits) {
-            case 8:
-                return GL_BYTE;
-            case 16:
-                return GL_SHORT;
-            //case 32:
-                //return GL_INT;
-            }
-            return 0;
-        case RS_TYPE_UNSIGNED:
-            switch (mBits) {
-            case 8:
-                return GL_UNSIGNED_BYTE;
-            case 16:
-                return GL_UNSIGNED_SHORT;
-            //case 32:
-                //return GL_UNSIGNED_INT;
-            }
-            return 0;
-        }
-    }
-
-    if (mFieldCount > 4) {
-        return 0;
-    }
-
-    for (uint32_t ct=0; ct < mFieldCount; ct++) {
-        bits[ct] = mFields[ct].e->mBits;
-        if (mFields[ct].e->mFieldCount) {
-            return 0;
-        }
-        if (mFields[ct].e->mType != RS_TYPE_UNSIGNED) {
-            return 0;
-        }
-        if (!mFields[ct].e->mIsNormalized) {
-            return 0;
-        }
-    }
-
-    switch(mFieldCount) {
-    case 1:
-        if (bits[0] == 8) {
-            return GL_UNSIGNED_BYTE;
-        }
-        return 0;
-    case 2:
-        if ((bits[0] == 8) &&
-            (bits[1] == 8)) {
-            return GL_UNSIGNED_BYTE;
-        }
-        return 0;
-    case 3:
-        if ((bits[0] == 8) &&
-            (bits[1] == 8) &&
-            (bits[2] == 8)) {
-            return GL_UNSIGNED_BYTE;
-        }
-        if ((bits[0] == 5) &&
-            (bits[1] == 6) &&
-            (bits[2] == 5)) {
-            return GL_UNSIGNED_SHORT_5_6_5;
-        }
-        return 0;
-    case 4:
-        if ((bits[0] == 8) &&
-            (bits[1] == 8) &&
-            (bits[2] == 8) &&
-            (bits[3] == 8)) {
-            return GL_UNSIGNED_BYTE;
-        }
-        if ((bits[0] == 4) &&
-            (bits[1] == 4) &&
-            (bits[2] == 4) &&
-            (bits[3] == 4)) {
-            return GL_UNSIGNED_SHORT_4_4_4_4;
-        }
-        if ((bits[0] == 5) &&
-            (bits[1] == 5) &&
-            (bits[2] == 5) &&
-            (bits[3] == 1)) {
-            return GL_UNSIGNED_SHORT_5_5_5_1;
-        }
-    }
-    return 0;
-}
-
-uint32_t Element::getGLFormat() const
-{
-    if (!mFieldCount) {
-        if (mKind == RS_KIND_ALPHA) {
-            return GL_ALPHA;
-        }
-        if (mKind == RS_KIND_LUMINANCE) {
-            return GL_LUMINANCE;
-        }
-    }
-
-    switch(mFieldCount) {
-    case 2:
-        if ((mFields[0].e->mKind == RS_KIND_LUMINANCE) &&
-            (mFields[1].e->mKind == RS_KIND_ALPHA)) {
-            return GL_LUMINANCE_ALPHA;
-        }
-        break;
-    case 3:
-        if ((mFields[0].e->mKind == RS_KIND_RED) &&
-            (mFields[1].e->mKind == RS_KIND_GREEN) &&
-            (mFields[2].e->mKind == RS_KIND_BLUE)) {
-            return GL_RGB;
-        }
-        break;
-    case 4:
-        if ((mFields[0].e->mKind == RS_KIND_RED) &&
-            (mFields[1].e->mKind == RS_KIND_GREEN) &&
-            (mFields[2].e->mKind == RS_KIND_BLUE) &&
-            (mFields[3].e->mKind == RS_KIND_ALPHA)) {
-            return GL_RGBA;
-        }
-        break;
-    }
-    return 0;
-}
-
-const char * Element::getCType() const
-{
-    switch(mType) {
-    case RS_TYPE_FLOAT:
-        return "float";
-    case RS_TYPE_SIGNED:
-    case RS_TYPE_UNSIGNED:
-        switch(mBits) {
-        case 32:
-            return "int";
-        case 16:
-            return "short";
-        case 8:
-            return "char";
-        }
-        break;
-    }
-    return NULL;
-}
-
 void Element::dumpLOGV(const char *prefix) const
 {
     ObjectBase::dumpLOGV(prefix);
@@ -246,19 +88,18 @@
     }
 }
 
-Element * Element::create(Context *rsc, RsDataKind dk, RsDataType dt,
-                          bool isNorm, size_t bits)
+
+Element * Element::create(Context *rsc, RsDataType dt, RsDataKind dk,
+                            bool isNorm, uint32_t vecSize)
 {
     Element *e = new Element(rsc);
-    e->mKind = dk;
-    e->mType = dt;
-    e->mIsNormalized = isNorm;
-    e->mBits = bits;
+    e->mComponent.set(dt, dk, isNorm, vecSize);
+    e->mBits = e->mComponent.getBits();
     return e;
 }
 
-Element * Element::create(Context *rsc, Element **ein, const char **nin,
-                          const size_t * lengths, size_t count)
+Element * Element::create(Context *rsc, size_t count, const Element **ein,
+                            const char **nin, const size_t * lengths)
 {
     Element *e = new Element(rsc);
     e->mFields = new ElementField_t [count];
@@ -272,6 +113,47 @@
     return e;
 }
 
+String8 Element::getCStructBody(uint32_t indent) const
+{
+    String8 si;
+    for (uint32_t ct=0; ct < indent; ct++) {
+        si.append(" ");
+    }
+
+    String8 s(si);
+    s.append("{\n");
+    for (uint32_t ct = 0; ct < mFieldCount; ct++) {
+        s.append(si);
+        s.append(mFields[ct].e->getCType(indent+4));
+        s.append(" ");
+        s.append(mFields[ct].name);
+        s.append(";\n");
+    }
+    s.append(si);
+    s.append("}");
+    return s;
+}
+
+String8 Element::getCType(uint32_t indent) const
+{
+    String8 s;
+    for (uint32_t ct=0; ct < indent; ct++) {
+        s.append(" ");
+    }
+
+    if (!mFieldCount) {
+        // Basic component.
+        s.append(mComponent.getCType());
+    } else {
+        s.append("struct ");
+        s.append(getCStructBody(indent));
+    }
+
+    return s;
+}
+
+
+
 
 ElementState::ElementState()
 {
@@ -288,14 +170,31 @@
 namespace android {
 namespace renderscript {
 
-void rsi_ElementBegin(Context *rsc)
+RsElement rsi_ElementCreate(Context *rsc,
+                            RsDataType dt,
+                            RsDataKind dk,
+                            bool norm,
+                            uint32_t vecSize)
 {
-    ElementState * sec = &rsc->mStateElement;
-
-    sec->mBuildList.clear();
-    sec->mNames.clear();
+    //LOGE("rsi_ElementCreate %i %i %i %i", dt, dk, norm, vecSize);
+    Element *e = Element::create(rsc, dt, dk, norm, vecSize);
+    e->incUserRef();
+    return e;
 }
 
+RsElement rsi_ElementCreate2(Context *rsc,
+                             size_t count,
+                             const RsElement * ein,
+                             const char ** names,
+                             const size_t * nameLengths)
+{
+    //LOGE("rsi_ElementCreate2 %i", count);
+    Element *e = Element::create(rsc, count, (const Element **)ein, names, nameLengths);
+    e->incUserRef();
+    return e;
+}
+
+/*
 void rsi_ElementAdd(Context *rsc, RsDataKind dk, RsDataType dt, bool isNormalized, size_t bits, const char *name)
 {
     ElementState * sec = &rsc->mStateElement;
@@ -345,6 +244,7 @@
     free(tmpLengths);
     return se;
 }
+*/
 
 
 }
diff --git a/libs/rs/rsElement.h b/libs/rs/rsElement.h
index 43e2820..c46922c 100644
--- a/libs/rs/rsElement.h
+++ b/libs/rs/rsElement.h
@@ -17,7 +17,7 @@
 #ifndef ANDROID_STRUCTURED_ELEMENT_H
 #define ANDROID_STRUCTURED_ELEMENT_H
 
-//#include "rsComponent.h"
+#include "rsComponent.h"
 #include "rsUtils.h"
 #include "rsObjectBase.h"
 
@@ -53,20 +53,22 @@
     const Element * getField(uint32_t idx) const {return mFields[idx].e.get();}
     const char * getFieldName(uint32_t idx) const {return mFields[idx].name.string();}
 
-    RsDataType getType() const {return mType;}
-    bool getIsNormalized() const {return mIsNormalized;}
-    RsDataKind getKind() const {return mKind;}
+    const Component & getComponent() const {return mComponent;}
+    RsDataType getType() const {return mComponent.getType();}
+    //bool getIsNormalized() const {return mIsNormalized;}
+    RsDataKind getKind() const {return mComponent.getKind();}
     uint32_t getBits() const {return mBits;}
     //uint32_t getGLType() const;
-    const char * getCType() const;
+
+    String8 getCType(uint32_t indent=0) const;
+    String8 getCStructBody(uint32_t indent=0) const;
 
     void dumpLOGV(const char *prefix) const;
 
-
-    static Element * create(Context *rsc, RsDataKind dk, RsDataType dt,
-                            bool isNorm, size_t bits);
-    static Element * create(Context *rsc, Element **, const char **,
-                            const size_t * lengths, size_t count);
+    static Element * create(Context *rsc, RsDataType dt, RsDataKind dk,
+                            bool isNorm, uint32_t vecSize);
+    static Element * create(Context *rsc, size_t count, const Element **,
+                            const char **, const size_t * lengths);
 
 protected:
     // deallocate any components that are part of this element.
@@ -74,7 +76,7 @@
 
     typedef struct {
         String8 name;
-        ObjectBaseRef<Element> e;
+        ObjectBaseRef<const Element> e;
     } ElementField_t;
     ElementField_t *mFields;
     size_t mFieldCount;
@@ -82,12 +84,8 @@
 
     Element(Context *);
 
-
-    RsDataType mType;
-    bool mIsNormalized;
-    RsDataKind mKind;
+    Component mComponent;
     uint32_t mBits;
-    //String8 mName;
 };
 
 
diff --git a/libs/rs/rsFileA3D.cpp b/libs/rs/rsFileA3D.cpp
index c566665..e3272c5 100644
--- a/libs/rs/rsFileA3D.cpp
+++ b/libs/rs/rsFileA3D.cpp
@@ -324,6 +324,7 @@
 
 void FileA3D::processChunk_Element(Context *rsc, IO *io, A3DIndexEntry *ie)
 {
+    /*
     rsi_ElementBegin(rsc);
 
     uint32_t count = io->loadU32();
@@ -338,6 +339,7 @@
     }
     LOGE("processChunk_Element create");
     ie->mRsObj = rsi_ElementCreate(rsc);
+    */
 }
 
 void FileA3D::processChunk_ElementSource(Context *rsc, IO *io, A3DIndexEntry *ie)
diff --git a/libs/rs/rsProgramFragment.cpp b/libs/rs/rsProgramFragment.cpp
index 05672e5c..f7394a6 100644
--- a/libs/rs/rsProgramFragment.cpp
+++ b/libs/rs/rsProgramFragment.cpp
@@ -213,9 +213,9 @@
 
         if (mTextureEnableMask) {
             if (mPointSpriteEnable) {
-                mShader.append("  vec2 tex0 = gl_PointCoord;\n");
+                mShader.append("  vec2 t0 = gl_PointCoord;\n");
             } else {
-                mShader.append("  vec2 tex0 = varTex0.xy;\n");
+                mShader.append("  vec2 t0 = varTex0.xy;\n");
             }
         }
 
@@ -228,13 +228,39 @@
                     rsAssert(0);
                     break;
                 case RS_TEX_ENV_MODE_REPLACE:
-                    mShader.append("  col = texture2D(uni_Tex0, tex0);\n");
+                    switch(mTextureFormats[texNum]) {
+                    case 1:
+                        mShader.append("  col.a = texture2D(uni_Tex0, t0).a;\n");
+                        break;
+                    case 2:
+                        mShader.append("  col.rgba = texture2D(uni_Tex0, t0).rgba;\n");
+                        break;
+                    case 3:
+                        mShader.append("  col.rgb = texture2D(uni_Tex0, t0).rgb;\n");
+                        break;
+                    case 4:
+                        mShader.append("  col.rgba = texture2D(uni_Tex0, t0).rgba;\n");
+                        break;
+                    }
                     break;
                 case RS_TEX_ENV_MODE_MODULATE:
-                    mShader.append("  col *= texture2D(uni_Tex0, tex0);\n");
+                    switch(mTextureFormats[texNum]) {
+                    case 1:
+                        mShader.append("  col.a *= texture2D(uni_Tex0, t0).a;\n");
+                        break;
+                    case 2:
+                        mShader.append("  col.rgba *= texture2D(uni_Tex0, t0).rgba;\n");
+                        break;
+                    case 3:
+                        mShader.append("  col.rgb *= texture2D(uni_Tex0, t0).rgb;\n");
+                        break;
+                    case 4:
+                        mShader.append("  col.rgba *= texture2D(uni_Tex0, t0).rgba;\n");
+                        break;
+                    }
                     break;
                 case RS_TEX_ENV_MODE_DECAL:
-                    mShader.append("  col = texture2D(uni_Tex0, tex0);\n");
+                    mShader.append("  col = texture2D(uni_Tex0, t0);\n");
                     break;
                 }
 
diff --git a/libs/rs/rsProgramVertex.cpp b/libs/rs/rsProgramVertex.cpp
index 153e2d6..fe628ca 100644
--- a/libs/rs/rsProgramVertex.cpp
+++ b/libs/rs/rsProgramVertex.cpp
@@ -246,9 +246,7 @@
 
 void ProgramVertexState::init(Context *rsc, int32_t w, int32_t h)
 {
-    rsi_ElementBegin(rsc);
-    rsi_ElementAdd(rsc, RS_KIND_USER, RS_TYPE_FLOAT, false, 32, NULL);
-    RsElement e = rsi_ElementCreate(rsc);
+    RsElement e = Element::create(rsc, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1);
 
     rsi_TypeBegin(rsc, e);
     rsi_TypeAdd(rsc, RS_DIMENSION_X, 48);
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index 3fa9813..9db3127 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -311,9 +311,15 @@
     char buf[256];
     String8 tmp;
 
-    str->append("struct vec2_s {float x; float y;};");
-    str->append("struct vec3_s {float x; float y; float z;};");
-    str->append("struct vec4_s {float x; float y; float z; float w;};");
+    str->append("struct vecF32_2_s {float x; float y;};\n");
+    str->append("struct vecF32_3_s {float x; float y; float z;};\n");
+    str->append("struct vecF32_4_s {float x; float y; float z; float w;};\n");
+    str->append("struct vecU8_4_s {char r; char g; char b; char a;};\n");
+    str->append("#define vecF32_2_t struct vecF32_2_s\n");
+    str->append("#define vecF32_3_t struct vecF32_3_s\n");
+    str->append("#define vecF32_4_t struct vecF32_4_s\n");
+    str->append("#define vecU8_4_t struct vecU8_4_s\n");
+    str->append("#define vecI8_4_t struct vecU8_4_s\n");
 
     for (size_t ct=0; ct < MAX_SCRIPT_BANKS; ct++) {
         const Type *t = mConstantBufferTypes[ct].get();
@@ -324,8 +330,9 @@
         if (e->getName() && (e->getFieldCount() > 1)) {
             String8 s("struct struct_");
             s.append(e->getName());
-            appendElementBody(&s, e);
+            s.append(e->getCStructBody());
             s.append(";\n");
+
             s.append("#define ");
             s.append(e->getName());
             s.append("_t struct struct_");
@@ -337,45 +344,25 @@
             str->append(s);
         }
 
-        if (t->getName()) {
-            for (size_t ct2=0; ct2 < e->getFieldCount(); ct2++) {
-                const Element *c = e->getField(ct2);
-                tmp.setTo("#define OFFSETOF_");
-                tmp.append(t->getName());
-                tmp.append("_");
-                tmp.append(e->getFieldName(ct2));
-                sprintf(buf, " %i\n", ct2);
-                tmp.append(buf);
-                if (rsc->props.mLogScripts) {
-                    LOGV(tmp);
-                }
-                str->append(tmp);
-            }
-        }
-
         if (mSlotNames[ct].length() > 0) {
             String8 s;
-            if (e->getFieldCount() > 1) {
-                if (e->getName()) {
-                    // Use the named struct
-                    s.setTo(e->getName());
-                    s.append("_t *");
-                } else {
-                    // create an struct named from the slot.
-                    s.setTo("struct ");
-                    s.append(mSlotNames[ct]);
-                    s.append("_s");
-                    appendElementBody(&s, e);
-                    s.append(";\n");
-                    s.append("struct ");
-                    s.append(mSlotNames[ct]);
-                    s.append("_s * ");
-                }
+            if (e->getName()) {
+                // Use the named struct
+                s.setTo(e->getName());
             } else {
-                // Just make an array
-                s.setTo(e->getField(0)->getCType());
-                s.append("_t *");
+                // create an struct named from the slot.
+                s.setTo("struct ");
+                s.append(mSlotNames[ct]);
+                s.append("_s");
+                s.append(e->getCStructBody());
+                //appendElementBody(&s, e);
+                s.append(";\n");
+                s.append("struct ");
+                s.append(mSlotNames[ct]);
+                s.append("_s");
             }
+
+            s.append(" * ");
             s.append(mSlotNames[ct]);
             s.append(";\n");
             if (rsc->props.mLogScripts) {
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
index e9f47d6..917f294 100644
--- a/libs/rs/rsScriptC_Lib.cpp
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -689,9 +689,9 @@
     VertexArray va;
     va.setPosition(2, GL_FLOAT, 12, (uint32_t)&vtx);
     if (rsc->checkVersion2_0()) {
-        va.setupGL2(&rsc->mStateVertexArray, &rsc->mShaderCache);
+        va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache);
     } else {
-        va.setupGL(&rsc->mStateVertexArray);
+        va.setupGL(rsc, &rsc->mStateVertexArray);
     }
 
     glDrawArrays(GL_LINES, 0, 2);
@@ -707,9 +707,9 @@
     VertexArray va;
     va.setPosition(1, GL_FLOAT, 12, (uint32_t)&vtx);
     if (rsc->checkVersion2_0()) {
-        va.setupGL2(&rsc->mStateVertexArray, &rsc->mShaderCache);
+        va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache);
     } else {
-        va.setupGL(&rsc->mStateVertexArray);
+        va.setupGL(rsc, &rsc->mStateVertexArray);
     }
 
     glDrawArrays(GL_POINTS, 0, 1);
@@ -742,9 +742,9 @@
     //va.setTexture(2, GL_FLOAT, 8, (uint32_t)&tex, 1);
     //
     if (rsc->checkVersion2_0()) {
-        va.setupGL2(&rsc->mStateVertexArray, &rsc->mShaderCache);
+        va.setupGL2(rsc, &rsc->mStateVertexArray, &rsc->mShaderCache);
     } else {
-        va.setupGL(&rsc->mStateVertexArray);
+        va.setupGL(rsc, &rsc->mStateVertexArray);
     }
 
 
@@ -1223,33 +1223,33 @@
 
     // vec3
     { "vec3Norm", (void *)&SC_vec3Norm,
-        "void", "(struct vec3_s *)" },
+        "void", "(struct vecF32_3_s *)" },
     { "vec3Length", (void *)&SC_vec3Length,
-        "float", "(struct vec3_s *)" },
+        "float", "(struct vecF32_3_s *)" },
     { "vec3Add", (void *)&SC_vec3Add,
-        "void", "(struct vec3_s *dest, struct vec3_s *lhs, struct vec3_s *rhs)" },
+        "void", "(struct vecF32_3_s *dest, struct vecF32_3_s *lhs, struct vecF32_3_s *rhs)" },
     { "vec3Sub", (void *)&SC_vec3Sub,
-        "void", "(struct vec3_s *dest, struct vec3_s *lhs, struct vec3_s *rhs)" },
+        "void", "(struct vecF32_3_s *dest, struct vecF32_3_s *lhs, struct vecF32_3_s *rhs)" },
     { "vec3Cross", (void *)&SC_vec3Cross,
-        "void", "(struct vec3_s *dest, struct vec3_s *lhs, struct vec3_s *rhs)" },
+        "void", "(struct vecF32_3_s *dest, struct vecF32_3_s *lhs, struct vecF32_3_s *rhs)" },
     { "vec3Dot", (void *)&SC_vec3Dot,
-        "float", "(struct vec3_s *lhs, struct vec3_s *rhs)" },
+        "float", "(struct vecF32_3_s *lhs, struct vecF32_3_s *rhs)" },
     { "vec3Scale", (void *)&SC_vec3Scale,
-        "void", "(struct vec3_s *lhs, float scale)" },
+        "void", "(struct vecF32_3_s *lhs, float scale)" },
 
     // vec4
     { "vec4Norm", (void *)&SC_vec4Norm,
-        "void", "(struct vec4_s *)" },
+        "void", "(struct vecF32_4_s *)" },
     { "vec4Length", (void *)&SC_vec4Length,
-        "float", "(struct vec4_s *)" },
+        "float", "(struct vecF32_4_s *)" },
     { "vec4Add", (void *)&SC_vec4Add,
-        "void", "(struct vec4_s *dest, struct vec4_s *lhs, struct vec4_s *rhs)" },
+        "void", "(struct vecF32_4_s *dest, struct vecF32_4_s *lhs, struct vecF32_4_s *rhs)" },
     { "vec4Sub", (void *)&SC_vec4Sub,
-        "void", "(struct vec4_s *dest, struct vec4_s *lhs, struct vec4_s *rhs)" },
+        "void", "(struct vecF32_4_s *dest, struct vecF32_4_s *lhs, struct vecF32_4_s *rhs)" },
     { "vec4Dot", (void *)&SC_vec4Dot,
-        "float", "(struct vec4_s *lhs, struct vec4_s *rhs)" },
+        "float", "(struct vecF32_4_s *lhs, struct vecF32_4_s *rhs)" },
     { "vec4Scale", (void *)&SC_vec4Scale,
-        "void", "(struct vec4_s *lhs, float scale)" },
+        "void", "(struct vecF32_4_s *lhs, float scale)" },
 
     // context
     { "bindProgramFragment", (void *)&SC_bindProgramFragment,
diff --git a/libs/rs/rsShaderCache.cpp b/libs/rs/rsShaderCache.cpp
index 8e2af34..311e3f5 100644
--- a/libs/rs/rsShaderCache.cpp
+++ b/libs/rs/rsShaderCache.cpp
@@ -93,7 +93,10 @@
 
         glBindAttribLocation(pgm, VertexArray::POSITION, "attrib_Position");
         glBindAttribLocation(pgm, VertexArray::COLOR, "attrib_Color");
-
+        //glBindAttribLocation(pgm, VertexArray::NORMAL, "attrib_Normal");
+        //glBindAttribLocation(pgm, VertexArray::POINT_SIZE, "attrib_PointSize");
+        //glBindAttribLocation(pgm, VertexArray::TEXTURE_0, "attrib_T0");
+        //glBindAttribLocation(pgm, VertexArray::TEXTURE_1, "attrib_T1");
 
         //LOGE("e2 %x", glGetError());
         glLinkProgram(pgm);
diff --git a/libs/rs/rsSimpleMesh.cpp b/libs/rs/rsSimpleMesh.cpp
index f7d14a5..5f5622d 100644
--- a/libs/rs/rsSimpleMesh.cpp
+++ b/libs/rs/rsSimpleMesh.cpp
@@ -62,9 +62,9 @@
         mVertexTypes[ct]->enableGLVertexBuffer(&va);
     }
     if (rsc->checkVersion2_0()) {
-        va.setupGL2(0, &rsc->mShaderCache);
+        va.setupGL2(rsc, 0, &rsc->mShaderCache);
     } else {
-        va.setupGL(0);
+        va.setupGL(rsc, 0);
     }
 
     if (mIndexType.get()) {
@@ -74,6 +74,8 @@
     } else {
         glDrawArrays(mGLPrimitive, start, len);
     }
+
+    rsc->checkError("SimpleMesh::renderRange");
 }
 
 void SimpleMesh::uploadAll(Context *rsc)
@@ -89,6 +91,7 @@
     if (mPrimitiveBuffer.get()) {
         mPrimitiveBuffer->deferedUploadToBufferObject(rsc);
     }
+    rsc->checkError("SimpleMesh::uploadAll");
 }
 
 
diff --git a/libs/rs/rsType.cpp b/libs/rs/rsType.cpp
index 5eac0b5..e7bcb08 100644
--- a/libs/rs/rsType.cpp
+++ b/libs/rs/rsType.cpp
@@ -137,106 +137,44 @@
     memset(&mGL, 0, sizeof(mGL));
 
     for (uint32_t ct=0; ct < getElement()->getFieldCount(); ct++) {
-        const Element *c = getElement()->getField(ct);
+        const Component &c = getElement()->getField(ct)->getComponent();
 
-        switch(c->getKind()) {
-        case RS_KIND_X:
+        switch(c.getKind()) {
+        case RS_KIND_POSITION:
             rsAssert(mGL.mVtx.size == 0);
-            mGL.mVtx.size = 1;
+            mGL.mVtx.size = c.getVectorSize();
             mGL.mVtx.offset = mElement->getFieldOffsetBytes(ct);
-            mGL.mVtx.type = c->getGLType();
+            mGL.mVtx.type = c.getGLType();
             break;
-        case RS_KIND_Y:
-            rsAssert(mGL.mVtx.size == 1);
-            rsAssert(mGL.mVtx.type == c->getGLType());
-            mGL.mVtx.size = 2;
-            break;
-        case RS_KIND_Z:
-            rsAssert(mGL.mVtx.size == 2);
-            rsAssert(mGL.mVtx.type == c->getGLType());
-            mGL.mVtx.size = 3;
-            break;
-        case RS_KIND_W:
-            rsAssert(mGL.mVtx.size == 4);
-            rsAssert(mGL.mVtx.type == c->getGLType());
-            mGL.mVtx.size = 4;
-        break;
 
-        case RS_KIND_RED:
+        case RS_KIND_COLOR:
             rsAssert(mGL.mColor.size == 0);
-            mGL.mColor.size = 1;
+            mGL.mColor.size = c.getVectorSize();
             mGL.mColor.offset = mElement->getFieldOffsetBytes(ct);
-            mGL.mColor.type = c->getGLType();
+            mGL.mColor.type = c.getGLType();
             break;
-        case RS_KIND_GREEN:
-            rsAssert(mGL.mColor.size == 1);
-            rsAssert(mGL.mColor.type == c->getGLType());
-            mGL.mColor.size = 2;
-            break;
-        case RS_KIND_BLUE:
-            rsAssert(mGL.mColor.size == 2);
-            rsAssert(mGL.mColor.type == c->getGLType());
-            mGL.mColor.size = 3;
-            break;
-        case RS_KIND_ALPHA:
-            // Can be RGBA or A at this point
-            if (mGL.mColor.size > 0) {
-                rsAssert(mGL.mColor.size == 3);
-                rsAssert(mGL.mColor.type == c->getGLType());
-                mGL.mColor.size = 4;
-            } else {
-                mGL.mColor.size = 1;
-                mGL.mColor.offset = mElement->getFieldOffsetBytes(ct);
-                mGL.mColor.type = c->getGLType();
-            }
-        break;
 
-        case RS_KIND_NX:
+        case RS_KIND_NORMAL:
             rsAssert(mGL.mNorm.size == 0);
-            mGL.mNorm.size = 1;
+            mGL.mNorm.size = c.getVectorSize();
             mGL.mNorm.offset = mElement->getFieldOffsetBytes(ct);
-            mGL.mNorm.type = c->getGLType();
-        break;
-        case RS_KIND_NY:
-            rsAssert(mGL.mNorm.size == 1);
-            rsAssert(mGL.mNorm.type == c->getGLType());
-            mGL.mNorm.size = 2;
-        break;
-        case RS_KIND_NZ:
-            rsAssert(mGL.mNorm.size == 2);
-            rsAssert(mGL.mNorm.type == c->getGLType());
-            mGL.mNorm.size = 3;
-        break;
+            mGL.mNorm.type = c.getGLType();
+            break;
 
-        case RS_KIND_S:
+        case RS_KIND_TEXTURE:
             if (mGL.mTex[texNum].size) {
                 texNum++;
             }
-            mGL.mTex[texNum].size = 1;
+            mGL.mTex[texNum].size = c.getVectorSize();
             mGL.mTex[texNum].offset = mElement->getFieldOffsetBytes(ct);
-            mGL.mTex[texNum].type = c->getGLType();
-        break;
-        case RS_KIND_T:
-            rsAssert(mGL.mTex[texNum].size == 1);
-            rsAssert(mGL.mTex[texNum].type == c->getGLType());
-            mGL.mTex[texNum].size = 2;
-        break;
-        case RS_KIND_R:
-            rsAssert(mGL.mTex[texNum].size == 2);
-            rsAssert(mGL.mTex[texNum].type == c->getGLType());
-            mGL.mTex[texNum].size = 3;
-        break;
-        case RS_KIND_Q:
-            rsAssert(mGL.mTex[texNum].size == 3);
-            rsAssert(mGL.mTex[texNum].type == c->getGLType());
-            mGL.mTex[texNum].size = 4;
-        break;
+            mGL.mTex[texNum].type = c.getGLType();
+            break;
 
         case RS_KIND_POINT_SIZE:
             rsAssert(!mGL.mPointSize.size);
-            mGL.mPointSize.size = 1;
+            mGL.mPointSize.size = c.getVectorSize();
             mGL.mPointSize.offset = mElement->getFieldOffsetBytes(ct);
-            mGL.mPointSize.type = c->getGLType();
+            mGL.mPointSize.type = c.getGLType();
         break;
 
         default:
diff --git a/libs/rs/rsVertexArray.cpp b/libs/rs/rsVertexArray.cpp
index 34d42ed..2ba0ef9 100644
--- a/libs/rs/rsVertexArray.cpp
+++ b/libs/rs/rsVertexArray.cpp
@@ -96,15 +96,16 @@
 }
 
 void VertexArray::logAttrib(uint32_t idx) const {
-    LOGE("va %i: buf=%i  size=%i  type=0x%x  stride=0x%x  offset=0x%x", idx,
+    LOGE("va %i: buf=%i  size=%i  type=0x%x  stride=0x%x  norm=%i  offset=0x%x", idx,
          mAttribs[idx].buffer,
          mAttribs[idx].size,
          mAttribs[idx].type,
          mAttribs[idx].stride,
+         mAttribs[idx].normalized,
          mAttribs[idx].offset);
 }
 
-void VertexArray::setupGL(class VertexArrayState *state) const
+void VertexArray::setupGL(const Context *rsc, class VertexArrayState *state) const
 {
     if (mAttribs[POSITION].size) {
         //logAttrib(POSITION);
@@ -168,9 +169,10 @@
     } else {
         glDisableClientState(GL_POINT_SIZE_ARRAY_OES);
     }
+    rsc->checkError("VertexArray::setupGL");
 }
 
-void VertexArray::setupGL2(class VertexArrayState *state, ShaderCache *sc) const
+void VertexArray::setupGL2(const Context *rsc, class VertexArrayState *state, ShaderCache *sc) const
 {
     for (int ct=1; ct < _LAST; ct++) {
         glDisableVertexAttribArray(ct);
@@ -194,6 +196,7 @@
             rsAssert(ct);
         }
     }
+    rsc->checkError("VertexArray::setupGL2");
 }
 ////////////////////////////////////////////
 
diff --git a/libs/rs/rsVertexArray.h b/libs/rs/rsVertexArray.h
index 235ffef..f97813f 100644
--- a/libs/rs/rsVertexArray.h
+++ b/libs/rs/rsVertexArray.h
@@ -64,8 +64,8 @@
     void setPointSize(uint32_t type, uint32_t stride, uint32_t offset);
     void setTexture(uint32_t size, uint32_t type, uint32_t stride, uint32_t offset, uint32_t num);
 
-    void setupGL(class VertexArrayState *) const;
-    void setupGL2(class VertexArrayState *, ShaderCache *) const;
+    void setupGL(const Context *rsc, class VertexArrayState *) const;
+    void setupGL2(const Context *rsc, class VertexArrayState *, ShaderCache *) const;
     void logAttrib(uint32_t idx) const;
 
 protected:
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index e5837ee..9edb05e 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -112,7 +112,7 @@
     private boolean mMediaServerOk;
 
     /** cached value of the BT dock address to recognize undocking events */
-    private static String sBtDockAddress;
+    private static String sBtDockAddress = "";
 
     private SoundPool mSoundPool;
     private Object mSoundEffectsLock = new Object();
@@ -231,6 +231,7 @@
     // Forced device usage for communications
     private int mForcedUseForComm;
 
+
     ///////////////////////////////////////////////////////////////////////////
     // Construction
     ///////////////////////////////////////////////////////////////////////////
@@ -1414,9 +1415,25 @@
                              (state == BluetoothA2dp.STATE_CONNECTED ||
                               state == BluetoothA2dp.STATE_PLAYING)) {
                     if (btDevice.isBluetoothDock()) {
-                        Log.v(TAG, "Recognized docking to BT dock");
+                        Log.v(TAG, "Recognized connection to BT dock");
                         sBtDockAddress = address;
-                        AudioSystem.setForceUse(AudioSystem.FOR_DOCK, AudioSystem.FORCE_BT_DOCK);
+                        Intent i = context.registerReceiver(null, new IntentFilter(Intent.ACTION_DOCK_EVENT));
+                        if (i != null) {
+                            int dockState = i.getIntExtra(Intent.EXTRA_DOCK_STATE, Intent.EXTRA_DOCK_STATE_UNDOCKED);
+                            int config;
+                            switch (dockState) {
+                                case Intent.EXTRA_DOCK_STATE_DESK:
+                                    config = AudioSystem.FORCE_BT_DESK_DOCK;
+                                    break;
+                                case Intent.EXTRA_DOCK_STATE_CAR:
+                                    config = AudioSystem.FORCE_BT_CAR_DOCK;
+                                    break;
+                                case Intent.EXTRA_DOCK_STATE_UNDOCKED:
+                                default:
+                                    config = AudioSystem.FORCE_NONE;
+                            }
+                            AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
+                        }
                     }
                     AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
                                                          AudioSystem.DEVICE_STATE_AVAILABLE,
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 9e9b259..137b919 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -271,7 +271,8 @@
     public static final int FORCE_BT_SCO = 3;
     public static final int FORCE_BT_A2DP = 4;
     public static final int FORCE_WIRED_ACCESSORY = 5;
-    public static final int FORCE_BT_DOCK = 6;
+    public static final int FORCE_BT_CAR_DOCK = 6;
+    public static final int FORCE_BT_DESK_DOCK = 7;
     public static final int FORCE_DEFAULT = FORCE_NONE;
 
     // usage for serForceUse
diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java
index 3803d9d..df21aa4 100644
--- a/media/java/android/media/SoundPool.java
+++ b/media/java/android/media/SoundPool.java
@@ -26,6 +26,10 @@
 import android.content.res.AssetFileDescriptor;
 import java.io.IOException;
 
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+
 /**
  * The SoundPool class manages and plays audio resources for applications.
  *
@@ -103,9 +107,20 @@
     static { System.loadLibrary("soundpool"); }
 
     private final static String TAG = "SoundPool";
+    private final static boolean DEBUG = false;
 
     private int mNativeContext; // accessed by native methods
 
+    private EventHandler mEventHandler;
+    private OnLoadCompleteListener mOnLoadCompleteListener;
+
+    private final Object mLock;
+
+    // SoundPool messages
+    //
+    // must match SoundPool.h
+    private static final int SAMPLE_LOADED = 1;
+
     /**
      * Constructor. Constructs a SoundPool object with the following
      * characteristics:
@@ -120,7 +135,23 @@
      * @return a SoundPool object, or null if creation failed
      */
     public SoundPool(int maxStreams, int streamType, int srcQuality) {
-        native_setup(new WeakReference<SoundPool>(this), maxStreams, streamType, srcQuality);
+
+        // do native setup
+        if (native_setup(new WeakReference(this), maxStreams, streamType, srcQuality) != 0) {
+            throw new RuntimeException("Native setup failed");
+        }
+        mLock = new Object();
+
+        // setup message handler
+        Looper looper;
+        if ((looper = Looper.myLooper()) != null) {
+            mEventHandler = new EventHandler(this, looper);
+        } else if ((looper = Looper.getMainLooper()) != null) {
+            mEventHandler = new EventHandler(this, looper);
+        } else {
+            mEventHandler = null;
+        }
+
     }
 
     /**
@@ -145,12 +176,11 @@
                 ParcelFileDescriptor fd = ParcelFileDescriptor.open(f, ParcelFileDescriptor.MODE_READ_ONLY);
                 if (fd != null) {
                     id = _load(fd.getFileDescriptor(), 0, f.length(), priority);
-                    //Log.v(TAG, "close fd");
                     fd.close();
                 }
             }
         } catch (java.io.IOException e) {
-            Log.d(TAG, "error loading " + path);
+            Log.e(TAG, "error loading " + path);
         }
         return id;
     }
@@ -176,7 +206,6 @@
         if (afd != null) {
             id = _load(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength(), priority);
             try {
-                //Log.v(TAG, "close fd");
                 afd.close();
             } catch (java.io.IOException ex) {
                 //Log.d(TAG, "close failed:", ex);
@@ -359,6 +388,76 @@
     public native final void setRate(int streamID, float rate);
 
     /**
+     * Interface definition for a callback to be invoked when all the
+     * sounds are loaded.
+     *
+     * @hide
+     */
+    public interface OnLoadCompleteListener
+    {
+        /**
+         * Called when a sound has completed loading.
+         *
+         * @param soundPool SoundPool object from the load() method
+         * @param soundPool the sample ID of the sound loaded.
+         * @param status the status of the load operation (0 = success)
+         */
+        public void onLoadComplete(SoundPool soundPool, int sampleId, int status);
+    }
+
+    /**
+     * Sets the callback hook for the OnLoadCompleteListener.
+     *
+     * @hide
+     */
+    public void setOnLoadCompleteListener(OnLoadCompleteListener listener)
+    {
+        synchronized(mLock) {
+            mOnLoadCompleteListener = listener;
+        }
+    }
+
+    private class EventHandler extends Handler
+    {
+        private SoundPool mSoundPool;
+
+        public EventHandler(SoundPool soundPool, Looper looper) {
+            super(looper);
+            mSoundPool = soundPool;
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch(msg.what) {
+            case SAMPLE_LOADED:
+                if (DEBUG) Log.d(TAG, "Sample " + msg.arg1 + " loaded");
+                synchronized(mLock) {
+                    if (mOnLoadCompleteListener != null) {
+                        mOnLoadCompleteListener.onLoadComplete(mSoundPool, msg.arg1, msg.arg2);
+                    }
+                }
+                break;
+            default:
+                Log.e(TAG, "Unknown message type " + msg.what);
+                return;
+            }
+        }
+    }
+
+    // post event from native code to message handler
+    private static void postEventFromNative(Object weakRef, int msg, int arg1, int arg2, Object obj)
+    {
+        SoundPool soundPool = (SoundPool)((WeakReference)weakRef).get();
+        if (soundPool == null)
+            return;
+
+        if (soundPool.mEventHandler != null) {
+            Message m = soundPool.mEventHandler.obtainMessage(msg, arg1, arg2, obj);
+            soundPool.mEventHandler.sendMessage(m);
+        }
+    }
+
+    /**
      * Release the SoundPool resources.
      *
      * Release all memory and native resources used by the SoundPool
@@ -367,8 +466,7 @@
      */
     public native final void release();
 
-    private native final void native_setup(Object mediaplayer_this,
-            int maxStreams, int streamType, int srcQuality);
+    private native final int native_setup(Object weakRef, int maxStreams, int streamType, int srcQuality);
 
     protected void finalize() { release(); }
 }
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index 70fba7e..e57f4a4 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -61,6 +61,9 @@
     mNextSampleID = 0;
     mNextChannelID = 0;
 
+    mCallback = 0;
+    mUserData = 0;
+
     mChannelPool = new SoundChannel[mMaxChannels];
     for (int i = 0; i < mMaxChannels; ++i) {
         mChannelPool[i].init(this);
@@ -141,7 +144,7 @@
 
 bool SoundPool::startThreads()
 {
-    createThread(beginThread, this);
+    createThreadEtc(beginThread, this, "SoundPoolThread");
     if (mDecodeThread == NULL)
         mDecodeThread = new SoundPoolThread(this);
     return mDecodeThread != NULL;
@@ -372,6 +375,21 @@
     }
 }
 
+void SoundPool::setCallback(SoundPoolCallback* callback, void* user)
+{
+    Mutex::Autolock lock(&mCallbackLock);
+    mCallback = callback;
+    mUserData = user;
+}
+
+void SoundPool::notify(SoundPoolEvent event)
+{
+    Mutex::Autolock lock(&mCallbackLock);
+    if (mCallback != NULL) {
+        mCallback(event, this, mUserData);
+    }
+}
+
 void SoundPool::dump()
 {
     for (int i = 0; i < mMaxChannels; ++i) {
@@ -422,7 +440,7 @@
     delete mUrl;
 }
 
-void Sample::doLoad()
+status_t Sample::doLoad()
 {
     uint32_t sampleRate;
     int numChannels;
@@ -439,19 +457,19 @@
     }
     if (p == 0) {
         LOGE("Unable to load sample: %s", mUrl);
-        return;
+        return -1;
     }
     LOGV("pointer = %p, size = %u, sampleRate = %u, numChannels = %d",
             p->pointer(), p->size(), sampleRate, numChannels);
 
     if (sampleRate > kMaxSampleRate) {
        LOGE("Sample rate (%u) out of range", sampleRate);
-       return;
+       return - 1;
     }
 
     if ((numChannels < 1) || (numChannels > 2)) {
         LOGE("Sample channel count (%d) out of range", numChannels);
-        return;
+        return - 1;
     }
 
     //_dumpBuffer(p->pointer(), p->size());
@@ -464,6 +482,7 @@
     mNumChannels = numChannels;
     mFormat = format;
     mState = READY;
+    return 0;
 }
 
 
diff --git a/media/jni/soundpool/SoundPool.h b/media/jni/soundpool/SoundPool.h
index 94cd978..7a2d631 100644
--- a/media/jni/soundpool/SoundPool.h
+++ b/media/jni/soundpool/SoundPool.h
@@ -24,8 +24,6 @@
 #include <media/AudioTrack.h>
 #include <cutils/atomic.h>
 
-#include <nativehelper/jni.h>
-
 namespace android {
 
 static const int IDLE_PRIORITY = -1;
@@ -43,10 +41,11 @@
     int         mMsg;
     int         mArg1;
     int         mArg2;
+    enum MessageType { INVALID, SAMPLE_LOADED };
 };
 
-// JNI for calling back Java SoundPool object
-extern void android_soundpool_SoundPool_notify(jobject ref, const SoundPoolEvent *event);
+// callback function prototype
+typedef void SoundPoolCallback(SoundPoolEvent event, SoundPool* soundPool, void* user);
 
 // tracks samples used by application
 class Sample  : public RefBase {
@@ -62,7 +61,7 @@
     size_t size() { return mSize; }
     int state() { return mState; }
     uint8_t* data() { return static_cast<uint8_t*>(mData->pointer()); }
-    void doLoad();
+    status_t doLoad();
     void startLoad() { mState = LOADING; }
     sp<IMemory> getIMemory() { return mData; }
 
@@ -182,6 +181,10 @@
     // called from AudioTrack thread
     void done(SoundChannel* channel);
 
+    // callback function
+    void setCallback(SoundPoolCallback* callback, void* user);
+    void* getUserData() { return mUserData; }
+
 private:
     SoundPool() {} // no default constructor
     bool startThreads();
@@ -191,6 +194,7 @@
     SoundChannel* findNextChannel (int channelID);
     SoundChannel* allocateChannel(int priority);
     void moveToFront(SoundChannel* channel);
+    void notify(SoundPoolEvent event);
     void dump();
 
     // restart thread
@@ -214,6 +218,11 @@
     int                     mNextSampleID;
     int                     mNextChannelID;
     bool                    mQuit;
+
+    // callback
+    Mutex                   mCallbackLock;
+    SoundPoolCallback*      mCallback;
+    void*                   mUserData;
 };
 
 } // end namespace android
diff --git a/media/jni/soundpool/SoundPoolThread.cpp b/media/jni/soundpool/SoundPoolThread.cpp
index 4e6798d..e32c794 100644
--- a/media/jni/soundpool/SoundPoolThread.cpp
+++ b/media/jni/soundpool/SoundPoolThread.cpp
@@ -22,50 +22,54 @@
 
 namespace android {
 
-void SoundPoolThread::MessageQueue::write(SoundPoolMsg msg) {
-    LOGV("MessageQueue::write - acquiring lock\n");
+void SoundPoolThread::write(SoundPoolMsg msg) {
     Mutex::Autolock lock(&mLock);
-    while (mQueue.size() >= maxMessages) {
-        LOGV("MessageQueue::write - wait\n");
+    while (mMsgQueue.size() >= maxMessages) {
         mCondition.wait(mLock);
     }
-    LOGV("MessageQueue::write - push message\n");
-    mQueue.push(msg);
-    mCondition.signal();
+
+    // if thread is quitting, don't add to queue
+    if (mRunning) {
+        mMsgQueue.push(msg);
+        mCondition.signal();
+    }
 }
 
-const SoundPoolMsg SoundPoolThread::MessageQueue::read() {
-    LOGV("MessageQueue::read - acquiring lock\n");
+const SoundPoolMsg SoundPoolThread::read() {
     Mutex::Autolock lock(&mLock);
-    while (mQueue.size() == 0) {
-        LOGV("MessageQueue::read - wait\n");
+    while (mMsgQueue.size() == 0) {
         mCondition.wait(mLock);
     }
-    SoundPoolMsg msg = mQueue[0];
-    LOGV("MessageQueue::read - retrieve message\n");
-    mQueue.removeAt(0);
+    SoundPoolMsg msg = mMsgQueue[0];
+    mMsgQueue.removeAt(0);
     mCondition.signal();
     return msg;
 }
 
-void SoundPoolThread::MessageQueue::quit() {
+void SoundPoolThread::quit() {
     Mutex::Autolock lock(&mLock);
-    mQueue.clear();
-    mQueue.push(SoundPoolMsg(SoundPoolMsg::KILL, 0));
-    mCondition.signal();
-    mCondition.wait(mLock);
+    if (mRunning) {
+        mRunning = false;
+        mMsgQueue.clear();
+        mMsgQueue.push(SoundPoolMsg(SoundPoolMsg::KILL, 0));
+        mCondition.signal();
+        mCondition.wait(mLock);
+    }
     LOGV("return from quit");
 }
 
 SoundPoolThread::SoundPoolThread(SoundPool* soundPool) :
     mSoundPool(soundPool)
 {
-    mMessages.setCapacity(maxMessages);
-    createThread(beginThread, this);
+    mMsgQueue.setCapacity(maxMessages);
+    if (createThread(beginThread, this)) {
+        mRunning = true;
+    }
 }
 
 SoundPoolThread::~SoundPoolThread()
 {
+    quit();
 }
 
 int SoundPoolThread::beginThread(void* arg) {
@@ -77,7 +81,7 @@
 int SoundPoolThread::run() {
     LOGV("run");
     for (;;) {
-        SoundPoolMsg msg = mMessages.read();
+        SoundPoolMsg msg = read();
         LOGV("Got message m=%d, mData=%d", msg.mMessageType, msg.mData);
         switch (msg.mMessageType) {
         case SoundPoolMsg::KILL:
@@ -95,14 +99,16 @@
 }
 
 void SoundPoolThread::loadSample(int sampleID) {
-    mMessages.write(SoundPoolMsg(SoundPoolMsg::LOAD_SAMPLE, sampleID));
+    write(SoundPoolMsg(SoundPoolMsg::LOAD_SAMPLE, sampleID));
 }
 
 void SoundPoolThread::doLoadSample(int sampleID) {
     sp <Sample> sample = mSoundPool->findSample(sampleID);
+    status_t status = -1;
     if (sample != 0) {
-        sample->doLoad();
+        status = sample->doLoad();
     }
+    mSoundPool->notify(SoundPoolEvent(SoundPoolEvent::SAMPLE_LOADED, sampleID, status));
 }
 
 } // end namespace android
diff --git a/media/jni/soundpool/SoundPoolThread.h b/media/jni/soundpool/SoundPoolThread.h
index 459a764..bbd35e0 100644
--- a/media/jni/soundpool/SoundPoolThread.h
+++ b/media/jni/soundpool/SoundPoolThread.h
@@ -27,7 +27,7 @@
 
 class SoundPoolMsg {
 public:
-    enum MessageType { INVALID, KILL, LOAD_SAMPLE, PLAY_SAMPLE, SAMPLE_DONE };
+    enum MessageType { INVALID, KILL, LOAD_SAMPLE };
     SoundPoolMsg() : mMessageType(INVALID), mData(0) {}
     SoundPoolMsg(MessageType MessageType, int data) :
         mMessageType(MessageType), mData(data) {}
@@ -45,29 +45,22 @@
     SoundPoolThread(SoundPool* SoundPool);
     ~SoundPoolThread();
     void loadSample(int sampleID);
-    void quit() { mMessages.quit(); }
+    void quit();
+    void write(SoundPoolMsg msg);
 
 private:
     static const size_t maxMessages = 5;
 
-    class MessageQueue {
-    public:
-        void write(SoundPoolMsg msg);
-        const SoundPoolMsg read();
-        void setCapacity(size_t size) { mQueue.setCapacity(size); }
-        void quit();
-    private:
-        Vector<SoundPoolMsg>    mQueue;
-        Mutex                   mLock;
-        Condition               mCondition;
-    };
-
     static int beginThread(void* arg);
     int run();
     void doLoadSample(int sampleID);
+    const SoundPoolMsg read();
 
-    SoundPool*                  mSoundPool;
-    MessageQueue                mMessages;
+    Mutex                   mLock;
+    Condition               mCondition;
+    Vector<SoundPoolMsg>    mMsgQueue;
+    SoundPool*              mSoundPool;
+    bool                    mRunning;
 };
 
 } // end namespace android
diff --git a/media/jni/soundpool/android_media_SoundPool.cpp b/media/jni/soundpool/android_media_SoundPool.cpp
index 1381db3..f6ea916 100644
--- a/media/jni/soundpool/android_media_SoundPool.cpp
+++ b/media/jni/soundpool/android_media_SoundPool.cpp
@@ -17,7 +17,7 @@
 #include <stdio.h>
 
 //#define LOG_NDEBUG 0
-#define LOG_TAG "SoundPool"
+#define LOG_TAG "SoundPool-JNI"
 
 #include <utils/Log.h>
 #include <nativehelper/jni.h>
@@ -29,6 +29,7 @@
 
 static struct fields_t {
     jfieldID    mNativeContext;
+    jmethodID   mPostEvent;
     jclass      mSoundPoolClass;
 } fields;
 
@@ -149,19 +150,29 @@
     ap->setRate(channelID, rate);
 }
 
-static void
-android_media_SoundPool_native_setup(JNIEnv *env, jobject thiz,
-        jobject weak_this, jint maxChannels, jint streamType, jint srcQuality)
+static void android_media_callback(SoundPoolEvent event, SoundPool* soundPool, void* user)
+{
+    LOGV("callback: (%d, %d, %d, %p, %p)", event.mMsg, event.mArg1, event.mArg2, soundPool, user);
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+    env->CallStaticVoidMethod(fields.mSoundPoolClass, fields.mPostEvent, user, event.mMsg, event.mArg1, event.mArg2, NULL);
+}
+
+static jint
+android_media_SoundPool_native_setup(JNIEnv *env, jobject thiz, jobject weakRef, jint maxChannels, jint streamType, jint srcQuality)
 {
     LOGV("android_media_SoundPool_native_setup");
     SoundPool *ap = new SoundPool(maxChannels, streamType, srcQuality);
     if (ap == NULL) {
-        jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
-        return;
+        return -1;
     }
 
     // save pointer to SoundPool C++ object in opaque field in Java object
     env->SetIntField(thiz, fields.mNativeContext, (int)ap);
+
+    // set callback with weak reference
+    jobject globalWeakRef = env->NewGlobalRef(weakRef);
+    ap->setCallback(android_media_callback, globalWeakRef);
+    return 0;
 }
 
 static void
@@ -170,6 +181,15 @@
     LOGV("android_media_SoundPool_release");
     SoundPool *ap = MusterSoundPool(env, thiz);
     if (ap != NULL) {
+
+        // release weak reference
+        jobject weakRef = (jobject) ap->getUserData();
+        if (weakRef != NULL) {
+            env->DeleteGlobalRef(weakRef);
+        }
+
+        // clear callback and native context
+        ap->setCallback(NULL, NULL);
         env->SetIntField(thiz, fields.mNativeContext, 0);
         delete ap;
     }
@@ -224,7 +244,7 @@
         (void *)android_media_SoundPool_setRate
     },
     {   "native_setup",
-        "(Ljava/lang/Object;III)V",
+        "(Ljava/lang/Object;III)I",
         (void*)android_media_SoundPool_native_setup
     },
     {   "release",
@@ -259,6 +279,13 @@
         goto bail;
     }
 
+    fields.mPostEvent = env->GetStaticMethodID(clazz, "postEventFromNative",
+                                               "(Ljava/lang/Object;IIILjava/lang/Object;)V");
+    if (fields.mPostEvent == NULL) {
+        LOGE("Can't find android/media/SoundPool.postEventFromNative");
+        return -1;
+    }
+
     if (AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods)) < 0)
         goto bail;
 
diff --git a/media/libstagefright/omx/tests/Android.mk b/media/libstagefright/omx/tests/Android.mk
index cd654510..ee117e5 100644
--- a/media/libstagefright/omx/tests/Android.mk
+++ b/media/libstagefright/omx/tests/Android.mk
@@ -7,7 +7,7 @@
 	OMXHarness.cpp  \
 
 LOCAL_SHARED_LIBRARIES := \
-	libstagefright
+	libstagefright libbinder libmedia libutils
 
 LOCAL_C_INCLUDES:= \
 	$(JNI_H_INCLUDE) \
diff --git a/media/tests/SoundPoolTest/Android.mk b/media/tests/SoundPoolTest/Android.mk
new file mode 100644
index 0000000..7f947c0
--- /dev/null
+++ b/media/tests/SoundPoolTest/Android.mk
@@ -0,0 +1,10 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := SoundPoolTest
+
+include $(BUILD_PACKAGE)
diff --git a/media/tests/SoundPoolTest/AndroidManifest.xml b/media/tests/SoundPoolTest/AndroidManifest.xml
new file mode 100644
index 0000000..126276c
--- /dev/null
+++ b/media/tests/SoundPoolTest/AndroidManifest.xml
@@ -0,0 +1,11 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
+package="com.android.soundpooltest">
+    <application>
+        <activity  android:name="SoundPoolTest" android:label="Sound Pool Test">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/media/tests/SoundPoolTest/res/raw/organ441.ogg b/media/tests/SoundPoolTest/res/raw/organ441.ogg
new file mode 100644
index 0000000..130cb37
--- /dev/null
+++ b/media/tests/SoundPoolTest/res/raw/organ441.ogg
Binary files differ
diff --git a/media/tests/SoundPoolTest/res/raw/sine441.ogg b/media/tests/SoundPoolTest/res/raw/sine441.ogg
new file mode 100644
index 0000000..cdf1eaa
--- /dev/null
+++ b/media/tests/SoundPoolTest/res/raw/sine441.ogg
Binary files differ
diff --git a/media/tests/SoundPoolTest/res/raw/test1.mp3 b/media/tests/SoundPoolTest/res/raw/test1.mp3
new file mode 100644
index 0000000..c1b2fdf
--- /dev/null
+++ b/media/tests/SoundPoolTest/res/raw/test1.mp3
Binary files differ
diff --git a/media/tests/SoundPoolTest/res/raw/test2.ogg b/media/tests/SoundPoolTest/res/raw/test2.ogg
new file mode 100644
index 0000000..396d78f
--- /dev/null
+++ b/media/tests/SoundPoolTest/res/raw/test2.ogg
Binary files differ
diff --git a/media/tests/SoundPoolTest/res/raw/test3.ogg b/media/tests/SoundPoolTest/res/raw/test3.ogg
new file mode 100644
index 0000000..c56f68b
--- /dev/null
+++ b/media/tests/SoundPoolTest/res/raw/test3.ogg
Binary files differ
diff --git a/media/tests/SoundPoolTest/res/raw/test4.ogg b/media/tests/SoundPoolTest/res/raw/test4.ogg
new file mode 100644
index 0000000..d3cbdfc
--- /dev/null
+++ b/media/tests/SoundPoolTest/res/raw/test4.ogg
Binary files differ
diff --git a/media/tests/SoundPoolTest/res/raw/test5.ogg b/media/tests/SoundPoolTest/res/raw/test5.ogg
new file mode 100644
index 0000000..1c6851d
--- /dev/null
+++ b/media/tests/SoundPoolTest/res/raw/test5.ogg
Binary files differ
diff --git a/media/tests/SoundPoolTest/src/com/android/SoundPoolTest.java b/media/tests/SoundPoolTest/src/com/android/SoundPoolTest.java
new file mode 100644
index 0000000..6b3093f
--- /dev/null
+++ b/media/tests/SoundPoolTest/src/com/android/SoundPoolTest.java
@@ -0,0 +1,384 @@
+/*
+ * Copyright (c) 2009, Google Inc.
+ *
+ * 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.soundpooltest;
+
+import android.app.Activity;
+import android.widget.LinearLayout;
+import android.os.Bundle;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.KeyEvent;
+import android.media.AudioSystem;
+import android.media.AudioManager;
+import android.media.SoundPool;
+import android.media.SoundPool.OnLoadCompleteListener;
+import android.util.Config;
+import android.util.Log;
+import java.util.HashMap;
+import java.lang.Math;
+
+import com.android.soundpooltest.R;
+
+public class SoundPoolTest extends Activity
+{
+    private static final String LOG_TAG = "SoundPoolTest";
+    private static final boolean DEBUG = true;
+    private static final boolean VERBOSE = false;
+    private TestThread mThread;
+
+    private static final int[] mTestFiles = new int[] {
+        // FIXME: Restore when Stagefright bug is fixed
+        R.raw.organ441,
+        R.raw.sine441,
+        //R.raw.test1,
+        R.raw.test2,
+        R.raw.test3,
+        R.raw.test4,
+        R.raw.test5
+    };
+
+    private final static int MAX_STREAMS = 1;
+    private final static float SEMITONE = 1.059463094f;
+    private final static float DEFAULT_VOLUME = 0.707f;
+    private final static float MAX_VOLUME = 1.0f;
+    private final static float MIN_VOLUME = 0.01f;
+    private final static int LOW_PRIORITY = 1000;
+    private final static int NORMAL_PRIORITY = 2000;
+    private final static int HIGH_PRIORITY = 3000;
+    private final static int DEFAULT_LOOP = -1;
+    private final static int DEFAULT_SRC_QUALITY = 0;
+    private final static double PI_OVER_2 = Math.PI / 2.0;
+
+    public SoundPoolTest() {}
+
+    private final class TestThread extends java.lang.Thread {
+        private boolean mRunning;
+        private SoundPool mSoundPool = null;
+        private int mLastSample;
+        private int mLoadStatus;
+        private int[] mSounds;
+        private float mScale[];
+
+        TestThread() {
+            super("SoundPool.TestThread");
+        }
+
+        private final class LoadCompleteCallback implements
+            android.media.SoundPool.OnLoadCompleteListener {
+            public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
+                synchronized(mSoundPool) {
+                    if (DEBUG) Log.d(LOG_TAG, "Sample " + sampleId + " load status = " + status);
+                    if (status != 0) {
+                        mLoadStatus = status;
+                    }
+                    if (sampleId == mLastSample) {
+                        mSoundPool.notify();
+                    }
+                }
+            }
+        }
+
+        private int loadSound(int resId, int priority) {
+            int id = mSoundPool.load(getApplicationContext(), resId, priority);
+            if (id == 0) {
+                Log.e(LOG_TAG, "Unable to open resource");
+            }
+            return id;
+        }
+
+        private int initSoundPool() throws java.lang.InterruptedException {
+
+            if (mSoundPool != null) {
+                if (mLoadStatus == 0) return mLoadStatus;
+                mSoundPool.release();
+                mSoundPool = null;
+            }
+
+            // create sound pool
+            mLoadStatus = 0;
+            mSoundPool = new SoundPool(MAX_STREAMS, AudioSystem.STREAM_MUSIC, 0);
+            mSoundPool.setOnLoadCompleteListener(new LoadCompleteCallback());
+            int numSounds = mTestFiles.length;
+            mSounds = new int[numSounds];
+
+            // load sounds
+            synchronized(mSoundPool) {
+                for (int index = 0; index < numSounds; index++) {
+                    mSounds[index] = loadSound(mTestFiles[index], NORMAL_PRIORITY);
+                    mLastSample = mSounds[index];
+                }
+                mSoundPool.wait();
+            }
+            return mLoadStatus;
+        }
+
+        private boolean TestSounds() throws java.lang.InterruptedException {
+            if (DEBUG) Log.d(LOG_TAG, "Begin sounds test");
+            int count = mSounds.length;
+            for (int index = 0; index < count; index++) {
+                int id = mSoundPool.play(mSounds[index], DEFAULT_VOLUME, DEFAULT_VOLUME,
+                        NORMAL_PRIORITY, DEFAULT_LOOP, 1.0f);
+                if (DEBUG) Log.d(LOG_TAG, "Start note " + id);
+                if (id == 0) {
+                    Log.e(LOG_TAG, "Error occurred starting note");
+                    return false;
+                }
+                sleep(450);
+                mSoundPool.stop(id);
+                if (DEBUG) Log.d(LOG_TAG, "Stop note " + id);
+                sleep(50);
+            }
+            if (DEBUG) Log.d(LOG_TAG, "End scale test");
+            return true;
+        }
+
+        private boolean TestScales() throws java.lang.InterruptedException {
+            if (DEBUG) Log.d(LOG_TAG, "Begin scale test");
+
+            // interate through pitch table
+            int count = mScale.length;
+            for (int step = 0; step < count; step++) {
+                int id = mSoundPool.play(mSounds[0], DEFAULT_VOLUME, DEFAULT_VOLUME,
+                        NORMAL_PRIORITY, DEFAULT_LOOP, mScale[step]);
+                if (DEBUG) Log.d(LOG_TAG, "Start note " + id);
+                if (id == 0) {
+                    Log.e(LOG_TAG, "Error occurred starting note");
+                    return false;
+                }
+                sleep(450);
+                mSoundPool.stop(id);
+                if (DEBUG) Log.d(LOG_TAG, "Stop note " + id);
+                sleep(50);
+            }
+            if (DEBUG) Log.d(LOG_TAG, "End sounds test");
+            return true;
+        }
+
+        private boolean TestRates() throws java.lang.InterruptedException {
+            if (DEBUG) Log.d(LOG_TAG, "Begin rate test");
+
+            // start the note
+            int count = mScale.length;
+            int id = mSoundPool.play(mSounds[0], DEFAULT_VOLUME, DEFAULT_VOLUME,
+                    NORMAL_PRIORITY, DEFAULT_LOOP, mScale[0]);
+            if (DEBUG) Log.d(LOG_TAG, "Start note " + id);
+            if (id == 0) {
+                Log.e(LOG_TAG, "Test failed - exiting");
+                return false;
+            }
+
+            // modify the pitch
+            for (int step = 1; step < count; step++) {
+                sleep(250);
+                mSoundPool.setRate(id, mScale[step]);
+                if (DEBUG) Log.d(LOG_TAG, "Change rate " + mScale[step]);
+            }
+            mSoundPool.stop(id);
+            if (DEBUG) Log.d(LOG_TAG, "End rate test");
+            return true;
+        }
+
+        private boolean TestPriority() throws java.lang.InterruptedException {
+            if (DEBUG) Log.d(LOG_TAG, "Begin priority test");
+            boolean result = true;
+
+            // play a normal priority looping sound
+            int normalId = mSoundPool.play(mSounds[0], DEFAULT_VOLUME, DEFAULT_VOLUME,
+                    NORMAL_PRIORITY, DEFAULT_LOOP, 1.0f);
+            if (DEBUG) Log.d(LOG_TAG, "Start note " + normalId);
+            if (normalId == 0) {
+                Log.e(LOG_TAG, "Error occurred starting note");
+                return false;
+            }
+            sleep(250);
+
+            // play a low priority sound
+            int id = mSoundPool.play(mSounds[0], DEFAULT_VOLUME, DEFAULT_VOLUME,
+                    LOW_PRIORITY, DEFAULT_LOOP, 1.0f);
+            if (id > 0) {
+                Log.e(LOG_TAG, "Normal > Low priority test failed");
+                result = false;
+                mSoundPool.stop(id);
+            } else {
+                Log.e(LOG_TAG, "Normal > Low priority test passed");
+            }
+            sleep(250);
+
+            // play a high priority sound
+            id = mSoundPool.play(mSounds[0], DEFAULT_VOLUME, DEFAULT_VOLUME,
+                    HIGH_PRIORITY, DEFAULT_LOOP, 1.0f);
+            if (id == 0) {
+                Log.e(LOG_TAG, "High > Normal priority test failed");
+                result = false;
+            } else {
+                Log.e(LOG_TAG, "High > Normal priority test passed");
+            }
+            sleep(250);
+            mSoundPool.stop(id);
+
+            // stop normal note
+            mSoundPool.stop(normalId);
+
+            if (DEBUG) Log.d(LOG_TAG, "End priority test");
+            return result;
+        }
+
+        private boolean TestPauseResume() throws java.lang.InterruptedException {
+            if (DEBUG) Log.d(LOG_TAG, "Begin pause/resume test");
+            boolean result = true;
+
+            // play a normal priority looping sound
+            int id = mSoundPool.play(mSounds[0], DEFAULT_VOLUME, DEFAULT_VOLUME,
+                    NORMAL_PRIORITY, DEFAULT_LOOP, 1.0f);
+            if (DEBUG) Log.d(LOG_TAG, "Start note " + id);
+            if (id == 0) {
+                Log.e(LOG_TAG, "Error occurred starting note");
+                return false;
+            }
+            sleep(250);
+
+            // pause and resume sound a few times
+            for (int count = 0; count < 5; count++) {
+                mSoundPool.pause(id);
+                sleep(250);
+                mSoundPool.resume(id);
+                sleep(250);
+            }
+
+            mSoundPool.stop(id);
+
+            if (DEBUG) Log.d(LOG_TAG, "End pause/resume test");
+            return result;
+        }
+
+        private boolean TestVolume() throws java.lang.InterruptedException {
+            if (DEBUG) Log.d(LOG_TAG, "Begin volume test");
+
+            // start the note
+            int id = mSoundPool.play(mSounds[0], 0.0f, 1.0f, NORMAL_PRIORITY, DEFAULT_LOOP, mScale[0]);
+            if (DEBUG) Log.d(LOG_TAG, "Start note " + id);
+            if (id == 0) {
+                Log.e(LOG_TAG, "Test failed - exiting");
+                return false;
+            }
+
+            // pan from left to right
+            for (int count = 0; count < 101; count++) {
+                sleep(20);
+                double radians = PI_OVER_2 * count / 100.0;
+                float leftVolume = (float) Math.sin(radians);
+                float rightVolume = (float) Math.cos(radians);
+                mSoundPool.setVolume(id, leftVolume, rightVolume);
+                if (DEBUG) Log.d(LOG_TAG, "Change volume (" + leftVolume + "," + rightVolume + ")");
+            }
+
+            mSoundPool.stop(id);
+            if (DEBUG) Log.d(LOG_TAG, "End volume test");
+            return true;
+        }
+
+        public void run() {
+            if (DEBUG) Log.d(LOG_TAG, "Test thread running");
+
+            // initialize
+            mRunning = true;
+            int failures = 0;
+
+            // initialize pitch table
+            float pitch = 0.5f;
+            mScale = new float[13];
+            for (int i = 0; i < 13; ++i) {
+                mScale[i] = pitch;
+                pitch *= SEMITONE;
+            }
+
+            try {
+
+                // load sound pool
+                initSoundPool();
+
+                // do tests
+                if (!TestSounds()) failures = failures + 1;
+                if (!TestScales()) failures = failures + 1;
+                if (!TestRates()) failures = failures + 1;
+                if (!TestPriority()) failures = failures + 1;
+                if (!TestPauseResume()) failures = failures + 1;
+                if (!TestVolume()) failures = failures + 1;
+
+            } catch (java.lang.InterruptedException e) {
+                if (DEBUG) Log.d(LOG_TAG, "Test interrupted");
+                failures = failures + 1;
+            } finally {
+                mRunning = false;
+            }
+
+            // release sound pool
+            if (mSoundPool != null) {
+                mSoundPool.release();
+                mSoundPool = null;
+            }
+
+            // output stats
+            if (DEBUG) Log.d(LOG_TAG, "Test thread exit");
+            if (failures == 0) {
+                Log.i(LOG_TAG, "All tests passed");
+            } else {
+                Log.i(LOG_TAG, failures + " tests failed");
+            }
+        }
+
+        public void quit() {
+            if (DEBUG) Log.d(LOG_TAG, "interrupt");
+            interrupt();
+            while (mRunning) {
+                try {
+                    sleep(20);
+                } catch (java.lang.InterruptedException e) { }
+            }
+            if (DEBUG) Log.d(LOG_TAG, "quit");
+        }
+    }
+
+    private void startTests() {
+        mThread = new TestThread();
+        mThread.start();
+    }
+
+    protected void onPause()
+    {
+        Log.v(LOG_TAG, "onPause");
+        super.onPause();
+        mThread.quit();
+        mThread = null;
+    }
+
+    protected void onResume()
+    {
+        Log.v(LOG_TAG, "onResume");
+        super.onResume();
+        startTests();
+    }
+
+    public void onCreate(Bundle icicle)
+    {
+        super.onCreate(icicle);
+        setVolumeControlStream(AudioManager.STREAM_MUSIC);
+    }
+}
+
diff --git a/media/tests/omxjpegdecoder/Android.mk b/media/tests/omxjpegdecoder/Android.mk
index e989078..f679f19 100644
--- a/media/tests/omxjpegdecoder/Android.mk
+++ b/media/tests/omxjpegdecoder/Android.mk
@@ -31,7 +31,9 @@
 LOCAL_SHARED_LIBRARIES := \
     libcutils \
     libskia \
-    libstagefright
+    libstagefright \
+    libbinder \
+    libutils
 
 LOCAL_C_INCLUDES := \
     $(JNI_H_INCLUDE) \
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index ad0fb0c..2e45512 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -497,11 +497,21 @@
         }
     }
 
-    // Add a transport to our set of available backends
+    // Add a transport to our set of available backends.  If 'transport' is null, this
+    // is an unregistration, and the transport's entry is removed from our bookkeeping.
     private void registerTransport(String name, IBackupTransport transport) {
         synchronized (mTransports) {
             if (DEBUG) Log.v(TAG, "Registering transport " + name + " = " + transport);
-            mTransports.put(name, transport);
+            if (transport != null) {
+                mTransports.put(name, transport);
+            } else {
+                mTransports.remove(name);
+                if (mCurrentTransport.equals(name)) {
+                    mCurrentTransport = null;
+                }
+                // Nothing further to do in the unregistration case
+                return;
+            }
         }
 
         // If the init sentinel file exists, we need to be sure to perform the init
diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java
index 7809fed..99d5520 100644
--- a/telephony/java/com/android/internal/telephony/DataConnection.java
+++ b/telephony/java/com/android/internal/telephony/DataConnection.java
@@ -16,43 +16,137 @@
 
 package com.android.internal.telephony;
 
+import com.android.internal.telephony.gsm.ApnSetting;
+
+import com.android.internal.util.HierarchicalState;
+import com.android.internal.util.HierarchicalStateMachine;
+
 import android.os.AsyncResult;
-import android.os.Handler;
 import android.os.Message;
-import android.util.Log;
+import android.os.SystemProperties;
+import android.util.EventLog;
 
 /**
  * {@hide}
+ *
+ * DataConnection HierarchicalStateMachine.
+ *
+ * This is an abstract base class for representing a single data connection.
+ * Instances of this class such as <code>CdmaDataConnection</code> and
+ * <code>GsmDataConnection</code>, * represent a connection via the cellular network.
+ * There may be multiple data connections and all of them are managed by the
+ * <code>DataConnectionTracker</code>.
+ *
+ * Instances are asynchronous state machines and have two primary entry points
+ * <code>connect()</code> and <code>disconnect</code>. The message a parameter will be returned
+ * hen the operation completes. The <code>msg.obj</code> will contain an AsyncResult
+ * object and <code>AsyncResult.userObj</code> is the original <code>msg.obj</code>. if successful
+ * with the <code>AsyncResult.result == null</code> and <code>AsyncResult.exception == null</code>.
+ * If an error <code>AsyncResult.result = FailCause</code> and
+ * <code>AsyncResult.exception = new Exception()</code>.
+ *
+ * The other public methods are provided for debugging.
+ *
+ * Below is the state machine description for this class.
+ *
+ * DataConnection {
+ *   + mDefaultState {
+ *        EVENT_RESET { clearSettings, >mInactiveState }.
+ *        EVENT_CONNECT {  notifyConnectCompleted(FailCause.UNKNOWN) }.
+ *        EVENT_DISCONNECT { notifyDisconnectCompleted }.
+ *
+ *        // Ignored messages
+ *        EVENT_SETUP_DATA_CONNECTION_DONE,
+ *        EVENT_GET_LAST_FAIL_DONE,
+ *        EVENT_DEACTIVATE_DONE.
+ *     }
+ *   ++ # mInactiveState {
+ *            EVENT_RESET.
+ *            EVENT_CONNECT {startConnecting, >mActivatingState }.
+ *        }
+ *   ++   mActivatingState {
+ *            EVENT_DISCONNECT { %EVENT_DISCONNECT }.
+ *            EVENT_SETUP_DATA_CONNECTION_DONE {
+ *                  if (SUCCESS) { notifyConnectCompleted(FailCause.NONE), >mActiveState }.
+ *                  if (ERR_BadCommand) {
+ *                         notifyConnectCompleted(FailCause.UNKNOWN), >mInactiveState }.
+ *                  if (ERR_BadDns) { tearDownData($DEACTIVATE_DONE), >mDisconnectingBadDnsState }.
+ *                  if (ERR_Other) { getLastDataCallFailCause($EVENT_GET_LAST_FAIL_DONE) }.
+ *                  if (ERR_Stale) {}.
+ *            }
+ *            EVENT_GET_LAST_FAIL_DONE { notifyConnectCompleted(result), >mInactive }.
+ *        }
+ *   ++   mActiveState {
+ *            EVENT_DISCONNECT { tearDownData($EVENT_DEACTIVATE_DONE), >mDisconnecting }.
+ *        }
+ *   ++   mDisconnectingState {
+ *            EVENT_DEACTIVATE_DONE { notifyDisconnectCompleted, >mInactiveState }.
+ *        }
+ *   ++   mDisconnectingBadDnsState {
+ *            EVENT_DEACTIVATE_DONE { notifyConnectComplete(FailCause.UNKNOWN), >mInactiveState }.
+ *        }
+ *  }
  */
-public abstract class DataConnection extends Handler {
+public abstract class DataConnection extends HierarchicalStateMachine {
+    protected static final boolean DBG = true;
 
-    // the inherited class
+    protected static Object mCountLock = new Object();
+    protected static int mCount;
 
-    public enum State {
-        ACTIVE, /* has active data connection */
-        ACTIVATING, /* during connecting process */
-        INACTIVE; /* has empty data connection */
+    /**
+     * Class returned by onSetupConnectionCompleted.
+     */
+    protected enum SetupResult {
+        ERR_BadCommand,
+        ERR_BadDns,
+        ERR_Other,
+        ERR_Stale,
+        SUCCESS;
 
+        public FailCause mFailCause;
+
+        @Override
         public String toString() {
             switch (this) {
-            case ACTIVE:
-                return "active";
-            case ACTIVATING:
-                return "setting up";
-            default:
-                return "inactive";
+                case ERR_BadCommand: return "Bad Command";
+                case ERR_BadDns: return "Bad DNS";
+                case ERR_Other: return "Other error";
+                case ERR_Stale: return "Stale command";
+                case SUCCESS: return "SUCCESS";
+                default: return "unknown";
             }
         }
-
-        public boolean isActive() {
-            return this == ACTIVE;
-        }
-
-        public boolean isInactive() {
-            return this == INACTIVE;
-        }
     }
 
+    /**
+     * Used internally for saving connecting parameters.
+     */
+    protected static class ConnectionParams {
+        public ConnectionParams(ApnSetting apn, Message onCompletedMsg) {
+            this.apn = apn;
+            this.onCompletedMsg = onCompletedMsg;
+        }
+
+        public int tag;
+        public ApnSetting apn;
+        public Message onCompletedMsg;
+    }
+
+    /**
+     * Used internally for saving disconnecting parameters.
+     */
+    protected static class DisconnectParams {
+        public DisconnectParams(Message onCompletedMsg) {
+            this.onCompletedMsg = onCompletedMsg;
+        }
+
+        public int tag;
+        public Message onCompletedMsg;
+    }
+
+    /**
+     * Returned as the reason for a connection failure.
+     */
     public enum FailCause {
         NONE,
         OPERATOR_BARRED,
@@ -71,8 +165,7 @@
         GPRS_REGISTRATION_FAIL,
         UNKNOWN,
 
-        RADIO_NOT_AVAILABLE,
-        RADIO_ERROR_RETRY;
+        RADIO_NOT_AVAILABLE;
 
         public boolean isPermanentFail() {
             return (this == OPERATOR_BARRED) || (this == MISSING_UKNOWN_APN) ||
@@ -128,117 +221,139 @@
                 return "Data Network Registration Failure";
             case RADIO_NOT_AVAILABLE:
                 return "Radio Not Available";
-            case RADIO_ERROR_RETRY:
-                return "Transient Radio Rrror";
             default:
                 return "Unknown Data Error";
             }
         }
     }
 
-    // ***** Event codes
-    protected static final int EVENT_SETUP_DATA_CONNECTION_DONE = 1;
-    protected static final int EVENT_GET_LAST_FAIL_DONE = 2;
-    protected static final int EVENT_LINK_STATE_CHANGED = 3;
-    protected static final int EVENT_DEACTIVATE_DONE = 4;
-    protected static final int EVENT_FORCE_RETRY = 5;
+    // ***** Event codes for driving the state machine
+    protected static final int EVENT_RESET = 1;
+    protected static final int EVENT_CONNECT = 2;
+    protected static final int EVENT_SETUP_DATA_CONNECTION_DONE = 3;
+    protected static final int EVENT_GET_LAST_FAIL_DONE = 4;
+    protected static final int EVENT_DEACTIVATE_DONE = 5;
+    protected static final int EVENT_DISCONNECT = 6;
 
     //***** Tag IDs for EventLog
     protected static final int EVENT_LOG_BAD_DNS_ADDRESS = 50100;
 
-
     //***** Member Variables
+    protected int mTag;
     protected PhoneBase phone;
-    protected Message onConnectCompleted;
-    protected Message onDisconnect;
     protected int cid;
     protected String interfaceName;
     protected String ipAddress;
     protected String gatewayAddress;
     protected String[] dnsServers;
-    protected State state;
     protected long createTime;
     protected long lastFailTime;
     protected FailCause lastFailCause;
     protected static final String NULL_IP = "0.0.0.0";
     Object userData;
 
-    // receivedDisconnectReq is set when disconnect during activation
-    protected boolean receivedDisconnectReq;
+    //***** Abstract methods
+    public abstract String toString();
 
-    /* Instance Methods */
-    protected abstract void onSetupConnectionCompleted(AsyncResult ar);
-
-    protected abstract void onDeactivated(AsyncResult ar);
-
-    protected abstract void disconnect(Message msg);
-
-    protected abstract void notifyFail(FailCause cause, Message onCompleted);
-
-    protected abstract void notifyDisconnect(Message msg);
-
-    protected abstract void onLinkStateChanged(DataLink.LinkState linkState);
+    protected abstract void onConnect(ConnectionParams cp);
 
     protected abstract FailCause getFailCauseFromRequest(int rilCause);
 
-    public abstract String toString();
+    protected abstract boolean isDnsOk(String[] domainNameServers);
 
     protected abstract void log(String s);
 
 
    //***** Constructor
-    protected DataConnection(PhoneBase phone) {
-        super();
+    protected DataConnection(PhoneBase phone, String name) {
+        super(name);
+        if (DBG) log("DataConnection constructor E");
         this.phone = phone;
-        onConnectCompleted = null;
-        onDisconnect = null;
         this.cid = -1;
-        receivedDisconnectReq = false;
         this.dnsServers = new String[2];
 
         clearSettings();
+
+        setDbg(true);
+        addState(mDefaultState);
+            addState(mInactiveState, mDefaultState);
+            addState(mActivatingState, mDefaultState);
+            addState(mActiveState, mDefaultState);
+            addState(mDisconnectingState, mDefaultState);
+            addState(mDisconnectingBadDnsState, mDefaultState);
+        setInitialState(mInactiveState);
+        if (DBG) log("DataConnection constructor X");
+    }
+
+    /**
+     * TearDown the data connection.
+     *
+     * @param o will be returned in AsyncResult.userObj
+     *          and is either a DisconnectParams or ConnectionParams.
+     */
+    private void tearDownData(Object o) {
+        if (phone.mCM.getRadioState().isOn()) {
+            if (DBG) log("tearDownData radio is on, call deactivateDataCall");
+            phone.mCM.deactivateDataCall(cid, obtainMessage(EVENT_DEACTIVATE_DONE, o));
+        } else {
+            if (DBG) log("tearDownData radio is off sendMessage EVENT_DEACTIVATE_DONE immediately");
+            sendMessage(obtainMessage(EVENT_DEACTIVATE_DONE, o));
+        }
+    }
+
+    /**
+     * Send the connectionCompletedMsg.
+     *
+     * @param cp is the ConnectionParams
+     * @param cause
+     */
+    private void notifyConnectCompleted(ConnectionParams cp, FailCause cause) {
+        Message connectionCompletedMsg = cp.onCompletedMsg;
+        if (connectionCompletedMsg == null) {
+            return;
+        }
+
+        long timeStamp = System.currentTimeMillis();
+        connectionCompletedMsg.arg1 = cid;
+
+        if (cause == FailCause.NONE) {
+            createTime = timeStamp;
+            AsyncResult.forMessage(connectionCompletedMsg);
+        } else {
+            lastFailCause = cause;
+            lastFailTime = timeStamp;
+            AsyncResult.forMessage(connectionCompletedMsg, cause, new Exception());
+        }
+        if (DBG) log("notifyConnection at " + timeStamp + " cause=" + cause);
+
+        connectionCompletedMsg.sendToTarget();
+    }
+
+    /**
+     * Send ar.userObj if its a message, which is should be back to originator.
+     *
+     * @param dp is the DisconnectParams.
+     */
+    private void notifyDisconnectCompleted(DisconnectParams dp) {
+        if (DBG) log("NotifyDisconnectCompleted");
+
+        Message msg = dp.onCompletedMsg;
+        AsyncResult.forMessage(msg);
+        msg.sendToTarget();
+
+        clearSettings();
     }
 
-    protected void setHttpProxy(String httpProxy, String httpPort) {
-        if (httpProxy == null || httpProxy.length() == 0) {
-            phone.setSystemProperty("net.gprs.http-proxy", null);
-            return;
-        }
+    /**
+     * Clear all settings called when entering mInactiveState.
+     */
+    protected void clearSettings() {
+        if (DBG) log("clearSettings");
 
-        if (httpPort == null || httpPort.length() == 0) {
-            httpPort = "8080";     // Default to port 8080
-        }
-
-        phone.setSystemProperty("net.gprs.http-proxy",
-                "http://" + httpProxy + ":" + httpPort + "/");
-    }
-
-    public String getInterface() {
-        return interfaceName;
-    }
-
-    public String getIpAddress() {
-        return ipAddress;
-    }
-
-    public String getGatewayAddress() {
-        return gatewayAddress;
-    }
-
-    public String[] getDnsServers() {
-        return dnsServers;
-    }
-
-    public void clearSettings() {
-        log("DataConnection.clearSettings()");
-
-        this.state = State.INACTIVE;
         this.createTime = -1;
         this.lastFailTime = -1;
         this.lastFailCause = FailCause.NONE;
 
-        receivedDisconnectReq = false;
-        onConnectCompleted = null;
         interfaceName = null;
         ipAddress = null;
         gatewayAddress = null;
@@ -246,80 +361,433 @@
         dnsServers[1] = null;
     }
 
-    protected void onGetLastFailCompleted(AsyncResult ar) {
-        if (receivedDisconnectReq) {
-            // Don't bother reporting the error if there's already a
-            // pending disconnect request, since DataConnectionTracker
-            // has already updated its state.
-            notifyDisconnect(onDisconnect);
-        } else {
-            FailCause cause = FailCause.UNKNOWN;
+    /**
+     * Process setup completion.
+     *
+     * @param ar is the result
+     * @return SetupResult.
+     */
+    private SetupResult onSetupConnectionCompleted(AsyncResult ar) {
+        SetupResult result;
+        String[] response = ((String[]) ar.result);
+        ConnectionParams cp = (ConnectionParams) ar.userObj;
 
-            if (ar.exception == null) {
-                int rilFailCause = ((int[]) (ar.result))[0];
-                cause = getFailCauseFromRequest(rilFailCause);
+        if (ar.exception != null) {
+            if (DBG) log("DataConnection Init failed " + ar.exception);
+
+            if (ar.exception instanceof CommandException
+                    && ((CommandException) (ar.exception)).getCommandError()
+                    == CommandException.Error.RADIO_NOT_AVAILABLE) {
+                result = SetupResult.ERR_BadCommand;
+                result.mFailCause = FailCause.RADIO_NOT_AVAILABLE;
+            } else {
+                result = SetupResult.ERR_Other;
             }
-            notifyFail(cause, onConnectCompleted);
-        }
-    }
-
-    protected void onForceRetry() {
-        if (receivedDisconnectReq) {
-            notifyDisconnect(onDisconnect);
+        } else if (cp.tag != mTag) {
+            if (DBG) {
+                log("BUG: onSetupConnectionCompleted is stale cp.tag=" + cp.tag + ", mtag=" + mTag);
+            }
+            result = SetupResult.ERR_Stale;
         } else {
-            notifyFail(FailCause.RADIO_ERROR_RETRY, onConnectCompleted);
+            cid = Integer.parseInt(response[0]);
+            if (response.length > 2) {
+                interfaceName = response[1];
+                ipAddress = response[2];
+                String prefix = "net." + interfaceName + ".";
+                gatewayAddress = SystemProperties.get(prefix + "gw");
+                dnsServers[0] = SystemProperties.get(prefix + "dns1");
+                dnsServers[1] = SystemProperties.get(prefix + "dns2");
+                if (DBG) {
+                    log("interface=" + interfaceName + " ipAddress=" + ipAddress
+                        + " gateway=" + gatewayAddress + " DNS1=" + dnsServers[0]
+                        + " DNS2=" + dnsServers[1]);
+                }
+
+                if (isDnsOk(dnsServers)) {
+                    result = SetupResult.SUCCESS;
+                } else {
+                    result = SetupResult.ERR_BadDns;
+                }
+            } else {
+                result = SetupResult.ERR_Other;
+            }
+        }
+
+        if (DBG) log("DataConnection setup result=" + result + " on cid = " + cid);
+        return result;
+    }
+
+    /**
+     * The parent state for all other states.
+     */
+    private class DcDefaultState extends HierarchicalState {
+        @Override
+        protected boolean processMessage(Message msg) {
+            AsyncResult ar;
+
+            switch (msg.what) {
+                case EVENT_RESET:
+                    if (DBG) log("DcDefaultState: msg.what=EVENT_RESET");
+                    clearSettings();
+                    transitionTo(mInactiveState);
+                    break;
+
+                case EVENT_CONNECT:
+                    if (DBG) log("DcDefaultState: msg.what=EVENT_CONNECT, fail not expected");
+                    ConnectionParams cp = (ConnectionParams) msg.obj;
+                    notifyConnectCompleted(cp, FailCause.UNKNOWN);
+                    break;
+
+                case EVENT_DISCONNECT:
+                    if (DBG) log("DcDefaultState: msg.what=EVENT_DISCONNECT");
+                    notifyDisconnectCompleted((DisconnectParams) msg.obj);
+                    break;
+
+                default:
+                    if (DBG) {
+                        log("DcDefaultState: shouldn't happen but ignore msg.what=" + msg.what);
+                    }
+                    break;
+            }
+
+            return true;
         }
     }
+    private DcDefaultState mDefaultState = new DcDefaultState();
 
-    @Override
-    public void handleMessage(Message msg) {
-        AsyncResult ar;
+    /**
+     * The state machine is inactive and expects a EVENT_CONNECT.
+     */
+    private class DcInactiveState extends HierarchicalState {
+        @Override protected void enter() {
+            mTag += 1;
+        }
+        @Override protected boolean processMessage(Message msg) {
+            boolean retVal;
 
-        log("DataConnection.handleMessage()");
+            switch (msg.what) {
+                case EVENT_RESET:
+                    if (DBG) {
+                        log("DcInactiveState: msg.what=EVENT_RESET, ignore we're already reset");
+                    }
+                    retVal = true;
+                    break;
 
-        switch (msg.what) {
+                case EVENT_CONNECT:
+                    if (DBG) log("DcInactiveState msg.what=EVENT_CONNECT");
+                    ConnectionParams cp = (ConnectionParams) msg.obj;
+                    cp.tag = mTag;
+                    onConnect(cp);
+                    transitionTo(mActivatingState);
+                    retVal = true;
+                    break;
 
-        case EVENT_SETUP_DATA_CONNECTION_DONE:
-            onSetupConnectionCompleted((AsyncResult) msg.obj);
-            break;
-
-        case EVENT_FORCE_RETRY:
-            onForceRetry();
-            break;
-
-        case EVENT_GET_LAST_FAIL_DONE:
-            onGetLastFailCompleted((AsyncResult) msg.obj);
-            break;
-
-        case EVENT_LINK_STATE_CHANGED:
-            ar = (AsyncResult) msg.obj;
-            DataLink.LinkState ls  = (DataLink.LinkState) ar.result;
-            onLinkStateChanged(ls);
-            break;
-
-        case EVENT_DEACTIVATE_DONE:
-            onDeactivated((AsyncResult) msg.obj);
-            break;
+                default:
+                    if (DBG) log("DcInactiveState nothandled msg.what=" + msg.what);
+                    retVal = false;
+                    break;
+            }
+            return retVal;
         }
     }
+    private DcInactiveState mInactiveState = new DcInactiveState();
 
-    public State getState() {
-        log("DataConnection.getState()");
-        return state;
+    /**
+     * The state machine is activating a connection.
+     */
+    private class DcActivatingState extends HierarchicalState {
+        @Override protected boolean processMessage(Message msg) {
+            boolean retVal;
+            AsyncResult ar;
+            ConnectionParams cp;
+
+            switch (msg.what) {
+                case EVENT_DISCONNECT:
+                    if (DBG) log("DcActivatingState deferring msg.what=EVENT_DISCONNECT");
+                    deferMessage(msg);
+                    retVal = true;
+                    break;
+
+                case EVENT_SETUP_DATA_CONNECTION_DONE:
+                    if (DBG) log("DcActivatingState msg.what=EVENT_SETUP_DATA_CONNECTION_DONE");
+
+                    ar = (AsyncResult) msg.obj;
+                    cp = (ConnectionParams) ar.userObj;
+
+                    SetupResult result = onSetupConnectionCompleted(ar);
+                    switch (result) {
+                        case SUCCESS:
+                            // All is well
+                            notifyConnectCompleted(cp, FailCause.NONE);
+                            transitionTo(mActiveState);
+                            break;
+                        case ERR_BadCommand:
+                            // Vendor ril rejected the command and didn't connect.
+                            notifyConnectCompleted(cp, result.mFailCause);
+                            transitionTo(mInactiveState);
+                            break;
+                        case ERR_BadDns:
+                            // Connection succeeded but DNS info is bad so disconnect
+                            EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_BAD_DNS_ADDRESS,
+                                    dnsServers[0]);
+                            tearDownData(cp);
+                            transitionTo(mDisconnectingBadDnsState);
+                            break;
+                        case ERR_Other:
+                            // Request the failure cause and process in this state
+                            phone.mCM.getLastDataCallFailCause(
+                                    obtainMessage(EVENT_GET_LAST_FAIL_DONE, cp));
+                            break;
+                        case ERR_Stale:
+                            // Request is stale, ignore.
+                            break;
+                        default:
+                            throw new RuntimeException("Unkown SetupResult, should not happen");
+                    }
+                    retVal = true;
+                    break;
+
+                case EVENT_GET_LAST_FAIL_DONE:
+                    ar = (AsyncResult) msg.obj;
+                    cp = (ConnectionParams) ar.userObj;
+                    FailCause cause = FailCause.UNKNOWN;
+
+                    if (cp.tag == mTag) {
+                        if (DBG) log("DcActivatingState msg.what=EVENT_GET_LAST_FAIL_DONE");
+                        if (ar.exception == null) {
+                            int rilFailCause = ((int[]) (ar.result))[0];
+                            cause = getFailCauseFromRequest(rilFailCause);
+                        }
+                         notifyConnectCompleted(cp, cause);
+                         transitionTo(mInactiveState);
+                    } else {
+                        if (DBG) {
+                            log("DcActivatingState EVENT_GET_LAST_FAIL_DONE is stale cp.tag="
+                                + cp.tag + ", mTag=" + mTag);
+                        }
+                    }
+
+                    retVal = true;
+                    break;
+
+                default:
+                    if (DBG) log("DcActivatingState not handled msg.what=" + msg.what);
+                    retVal = false;
+                    break;
+            }
+            return retVal;
+        }
+    }
+    private DcActivatingState mActivatingState = new DcActivatingState();
+
+    /**
+     * The state machine is connected, expecting an EVENT_DISCONNECT.
+     */
+    private class DcActiveState extends HierarchicalState {
+        @Override protected boolean processMessage(Message msg) {
+            boolean retVal;
+
+            switch (msg.what) {
+                case EVENT_DISCONNECT:
+                    if (DBG) log("DcActiveState msg.what=EVENT_DISCONNECT");
+                    DisconnectParams dp = (DisconnectParams) msg.obj;
+                    dp.tag = mTag;
+                    tearDownData(dp);
+                    transitionTo(mDisconnectingState);
+                    retVal = true;
+                    break;
+
+                default:
+                    if (DBG) log("DcActiveState nothandled msg.what=" + msg.what);
+                    retVal = false;
+                    break;
+            }
+            return retVal;
+        }
+    }
+    private DcActiveState mActiveState = new DcActiveState();
+
+    /**
+     * The state machine is disconnecting.
+     */
+    private class DcDisconnectingState extends HierarchicalState {
+        @Override protected boolean processMessage(Message msg) {
+            boolean retVal;
+
+            switch (msg.what) {
+                case EVENT_DEACTIVATE_DONE:
+                    if (DBG) log("DcDisconnectingState msg.what=EVENT_DEACTIVATE_DONE");
+                    AsyncResult ar = (AsyncResult) msg.obj;
+                    DisconnectParams dp = (DisconnectParams) ar.userObj;
+                    if (dp.tag == mTag) {
+                        notifyDisconnectCompleted((DisconnectParams) ar.userObj);
+                        transitionTo(mInactiveState);
+                    } else {
+                        if (DBG) log("DcDisconnectState EVENT_DEACTIVATE_DONE stale dp.tag="
+                                + dp.tag + " mTag=" + mTag);
+                    }
+                    retVal = true;
+                    break;
+
+                default:
+                    if (DBG) log("DcDisconnectingState not handled msg.what=" + msg.what);
+                    retVal = false;
+                    break;
+            }
+            return retVal;
+        }
+    }
+    private DcDisconnectingState mDisconnectingState = new DcDisconnectingState();
+
+    /**
+     * The state machine is disconnecting after a bad dns setup
+     * was found in mInactivatingState.
+     */
+    private class DcDisconnectingBadDnsState extends HierarchicalState {
+        @Override protected boolean processMessage(Message msg) {
+            boolean retVal;
+
+            switch (msg.what) {
+                case EVENT_DEACTIVATE_DONE:
+                    AsyncResult ar = (AsyncResult) msg.obj;
+                    ConnectionParams cp = (ConnectionParams) ar.userObj;
+                    if (cp.tag == mTag) {
+                        if (DBG) log("DcDisconnectingBadDnsState msg.what=EVENT_DEACTIVATE_DONE");
+                        notifyConnectCompleted(cp, FailCause.UNKNOWN);
+                        transitionTo(mInactiveState);
+                    } else {
+                        if (DBG) log("DcDisconnectingBadDnsState EVENT_DEACTIVE_DONE stale dp.tag="
+                                + cp.tag + ", mTag=" + mTag);
+                    }
+                    retVal = true;
+                    break;
+
+                default:
+                    if (DBG) log("DcDisconnectingBadDnsState not handled msg.what=" + msg.what);
+                    retVal = false;
+                    break;
+            }
+            return retVal;
+        }
+    }
+    private DcDisconnectingBadDnsState mDisconnectingBadDnsState = new DcDisconnectingBadDnsState();
+
+    // ******* public interface
+
+    /**
+     * Disconnect from the network.
+     */
+    public void reset() {
+        sendMessage(obtainMessage(EVENT_RESET));
     }
 
+    /**
+     * Connect to the apn and return an AsyncResult in onCompletedMsg.
+     * Used for cellular networks that use Acess Point Names (APN) such
+     * as GSM networks.
+     *
+     * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
+     *        With AsyncResult.userObj set to the original msg.obj,
+     *        AsyncResult.result = FailCause and AsyncResult.exception = Exception().
+     * @param apn is the Acces Point Name to connect to
+     */
+    public void connect(Message onCompletedMsg, ApnSetting apn) {
+        sendMessage(obtainMessage(EVENT_CONNECT, new ConnectionParams(apn, onCompletedMsg)));
+    }
+
+    /**
+     * Connect to the apn and return an AsyncResult in onCompletedMsg.
+     *
+     * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
+     *        With AsyncResult.userObj set to the original msg.obj,
+     *        AsyncResult.result = FailCause and AsyncResult.exception = Exception().
+     */
+    public void connect(Message onCompletedMsg) {
+        sendMessage(obtainMessage(EVENT_CONNECT, new ConnectionParams(null, onCompletedMsg)));
+    }
+
+    /**
+     * Disconnect from the network.
+     *
+     * @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)));
+    }
+
+    // ****** The following are used for debugging.
+
+    /**
+     * @return true if the state machine is in the inactive state.
+     */
+    public boolean isInactive() {
+        boolean retVal = getCurrentState() == mInactiveState;
+        return retVal;
+    }
+
+    /**
+     * @return true if the state machine is in the inactive state.
+     */
+    public boolean isActive() {
+        boolean retVal = getCurrentState() == mActiveState;
+        return retVal;
+    }
+
+    /**
+     * @return the interface name as a string.
+     */
+    public String getInterface() {
+        return interfaceName;
+    }
+
+    /**
+     * @return the ip address as a string.
+     */
+    public String getIpAddress() {
+        return ipAddress;
+    }
+
+    /**
+     * @return the gateway address as a string.
+     */
+    public String getGatewayAddress() {
+        return gatewayAddress;
+    }
+
+    /**
+     * @return an array of associated DNS addresses.
+     */
+    public String[] getDnsServers() {
+        return dnsServers;
+    }
+
+    /**
+     * @return the current state as a string.
+     */
+    public String getStateAsString() {
+        String retVal = getCurrentState().getName();
+        return retVal;
+    }
+
+    /**
+     * @return the time of when this connection was created.
+     */
     public long getConnectionTime() {
-        log("DataConnection.getConnectionTime()");
         return createTime;
     }
 
+    /**
+     * @return the time of the last failure.
+     */
     public long getLastFailTime() {
-        log("DataConnection.getLastFailTime()");
         return lastFailTime;
     }
 
+    /**
+     * @return the last cause of failure.
+     */
     public FailCause getLastFailCause() {
-        log("DataConnection.getLastFailCause()");
         return lastFailCause;
     }
 }
diff --git a/telephony/java/com/android/internal/telephony/DataLink.java b/telephony/java/com/android/internal/telephony/DataLink.java
deleted file mode 100644
index 8132d91..0000000
--- a/telephony/java/com/android/internal/telephony/DataLink.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2006 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.internal.telephony;
-
-import android.os.Handler;
-import android.os.Registrant;
-
-/**
- * Base class representing the data link layer (eg, PPP).
- *
- * {@hide}
- */
-public abstract class DataLink extends Handler implements DataLinkInterface {
-
-    /** Registrant for link status change notifications. */
-    protected Registrant mLinkChangeRegistrant;
-    protected DataConnectionTracker dataConnection;
-
-    protected DataLink(DataConnectionTracker dc) {
-        dataConnection = dc;
-    }
-
-    public void setOnLinkChange(Handler h, int what, Object obj) {
-        mLinkChangeRegistrant = new Registrant(h, what, obj);
-    }
-}
diff --git a/telephony/java/com/android/internal/telephony/DataLinkInterface.java b/telephony/java/com/android/internal/telephony/DataLinkInterface.java
deleted file mode 100644
index e8148a8..0000000
--- a/telephony/java/com/android/internal/telephony/DataLinkInterface.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2006 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.internal.telephony;
-
-import android.database.Cursor;
-import android.os.Handler;
-
-/**
- * Data link interface.
- *
- * {@hide}
- */
-public interface DataLinkInterface {
-    /**
-     * Link state enumeration.
-     *
-     */
-    enum LinkState {
-        LINK_UNKNOWN,
-        LINK_UP,
-        LINK_DOWN,
-        LINK_EXITED
-    }
-
-    /** Normal exit */
-    final static int EXIT_OK = 0;
-    /** Open failed */
-    final static int EXIT_OPEN_FAILED = 7;
-
-    /**
-     * Sets the handler for link state change events.
-     *
-     * @param h Handler
-     * @param what User-defined message code
-     * @param obj User object
-     */
-    void setOnLinkChange(Handler h, int what, Object obj);
-
-    /**
-     * Sets up the data link.
-     */
-    void connect();
-
-    /**
-     * Tears down the data link.
-     */
-    void disconnect();
-
-    /**
-     * Returns the exit code for a data link failure.
-     *
-     * @return exit code
-     */
-    int getLastLinkExitCode();
-
-    /**
-     * Sets password information that may be required by the data link
-     * (eg, PAP secrets).
-     *
-     * @param cursor cursor to carriers table
-     */
-    void setPasswordInfo(Cursor cursor);
-}
diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java
index c113581..a8ad80e 100644
--- a/telephony/java/com/android/internal/telephony/Phone.java
+++ b/telephony/java/com/android/internal/telephony/Phone.java
@@ -28,7 +28,7 @@
 
 import com.android.internal.telephony.DataConnection;
 import com.android.internal.telephony.gsm.NetworkInfo;
-import com.android.internal.telephony.gsm.PdpConnection;
+import com.android.internal.telephony.gsm.GsmDataConnection;
 import com.android.internal.telephony.test.SimulatedRadioControl;
 
 import java.util.List;
@@ -1176,21 +1176,7 @@
     void invokeOemRilRequestStrings(String[] strings, Message response);
 
     /**
-     * Get the current active PDP context list
-     *
-     * @deprecated
-     * @param response <strong>On success</strong>, "response" bytes is
-     * made available as:
-     * (String[])(((AsyncResult)response.obj).result).
-     * <strong>On failure</strong>,
-     * (((AsyncResult)response.obj).result) == null and
-     * (((AsyncResult)response.obj).exception) being an instance of
-     * com.android.internal.telephony.gsm.CommandException
-     */
-    void getPdpContextList(Message response);
-
-    /**
-     * Get the current active Data Call list, substitutes getPdpContextList
+     * Get the current active Data Call list
      *
      * @param response <strong>On success</strong>, "response" bytes is
      * made available as:
@@ -1203,19 +1189,11 @@
     void getDataCallList(Message response);
 
     /**
-     * Get current mutiple PDP link status
-     *
-     * @deprecated
-     * @return list of pdp link connections
-     */
-    List<PdpConnection> getCurrentPdpList ();
-
-    /**
      * Get current mutiple data connection status
      *
      * @return list of data connections
      */
-    List<DataConnection> getCurrentDataConnectionList ();
+    List<DataConnection> getCurrentDataConnectionList();
 
     /**
      * Update the ServiceState CellLocation for current network registration.
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index 50dd76a..bad9ab3 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -35,7 +35,7 @@
 import android.util.Log;
 
 import com.android.internal.R;
-import com.android.internal.telephony.gsm.PdpConnection;
+import com.android.internal.telephony.gsm.GsmDataConnection;
 import com.android.internal.telephony.test.SimulatedRadioControl;
 
 import java.util.List;
@@ -692,16 +692,6 @@
         Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
     }
 
-    /**
-     * This should only be called in GSM mode.
-     * Only here for some backward compatibility
-     * issues concerning the GSMPhone class.
-     * @deprecated Always returns null.
-     */
-    public List<PdpConnection> getCurrentPdpList() {
-        return null;
-    }
-
     public void enableEnhancedVoicePrivacy(boolean enable, Message onComplete) {
         // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
         Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
diff --git a/telephony/java/com/android/internal/telephony/PhoneProxy.java b/telephony/java/com/android/internal/telephony/PhoneProxy.java
index 3eadd81..d56d99f 100644
--- a/telephony/java/com/android/internal/telephony/PhoneProxy.java
+++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java
@@ -34,7 +34,7 @@
 import com.android.internal.telephony.cdma.CDMAPhone;
 import com.android.internal.telephony.gsm.GSMPhone;
 import com.android.internal.telephony.gsm.NetworkInfo;
-import com.android.internal.telephony.gsm.PdpConnection;
+import com.android.internal.telephony.gsm.GsmDataConnection;
 import com.android.internal.telephony.test.SimulatedRadioControl;
 
 import java.util.List;
@@ -564,24 +564,10 @@
         mActivePhone.invokeOemRilRequestStrings(strings, response);
     }
 
-    /**
-     * @deprecated
-     */
-    public void getPdpContextList(Message response) {
-        mActivePhone.getPdpContextList(response);
-    }
-
     public void getDataCallList(Message response) {
         mActivePhone.getDataCallList(response);
     }
 
-    /**
-     * @deprecated
-     */
-    public List<PdpConnection> getCurrentPdpList() {
-        return mActivePhone.getCurrentPdpList();
-    }
-
     public List<DataConnection> getCurrentDataConnectionList() {
         return mActivePhone.getCurrentDataConnectionList();
     }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index 75e8b65..d4b1652 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -657,13 +657,6 @@
         mSST.disableLocationUpdates();
     }
 
-    /**
-     * @deprecated
-     */
-    public void getPdpContextList(Message response) {
-        getDataCallList(response);
-    }
-
     public void getDataCallList(Message response) {
         mCM.getDataCallList(response);
     }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
index 4588f36..6c20204 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
@@ -16,221 +16,77 @@
 
 package com.android.internal.telephony.cdma;
 
-import android.os.*;
-import android.util.EventLog;
+import android.os.Message;
 import android.util.Log;
 
-import com.android.internal.telephony.CommandException;
-import com.android.internal.telephony.CommandsInterface;
 import com.android.internal.telephony.DataConnection;
-import com.android.internal.telephony.DataLink;
 import com.android.internal.telephony.RILConstants;
-import com.android.internal.telephony.TelephonyEventLog;
 
 /**
  * {@hide}
- *
  */
 public class CdmaDataConnection extends DataConnection {
 
     private static final String LOG_TAG = "CDMA";
-    private static final boolean DBG = true;
 
     /** Fail cause of last Data Call activate from RIL_LastDataCallActivateFailCause */
     private final static int PS_NET_DOWN_REASON_OPERATOR_DETERMINED_BARRING         = 8;
-    private final static int PS_NET_DOWN_REASON_UNKNOWN_APN                         = 27;
     private final static int PS_NET_DOWN_REASON_AUTH_FAILED                         = 29;
     private final static int PS_NET_DOWN_REASON_OPTION_NOT_SUPPORTED                = 32;
     private final static int PS_NET_DOWN_REASON_OPTION_UNSUBSCRIBED                 = 33;
 
-/** It is likely that the number of error codes listed below will be removed
- * in the foreseeable future.  They have been added, but not agreed upon.
- *
- */
-    private final static int PS_NET_DOWN_REASON_NOT_SPECIFIED                       = 0;
-    private final static int PS_NET_DOWN_REASON_CLOSE_IN_PROGRESS                   = 1;
-    private final static int PS_NET_DOWN_REASON_NW_INITIATED_TERMINATION            = 2;
-    private final static int PS_NET_DOWN_REASON_APP_PREEMPTED                       = 3;
-    private final static int PS_NET_DOWN_REASON_LLC_SNDCP_FAILURE                   = 25;
-    private final static int PS_NET_DOWN_REASON_INSUFFICIENT_RESOURCES              = 26;
-    private final static int PS_NET_DOWN_REASON_UNKNOWN_PDP                         = 28;
-    private final static int PS_NET_DOWN_REASON_GGSN_REJECT                         = 30;
-    private final static int PS_NET_DOWN_REASON_ACTIVATION_REJECT                   = 31;
-    private final static int PS_NET_DOWN_REASON_OPTION_TEMP_OOO                     = 34;
-    private final static int PS_NET_DOWN_REASON_NSAPI_ALREADY_USED                  = 35;
-    private final static int PS_NET_DOWN_REASON_REGULAR_DEACTIVATION                = 36;
-    private final static int PS_NET_DOWN_REASON_QOS_NOT_ACCEPTED                    = 37;
-    private final static int PS_NET_DOWN_REASON_NETWORK_FAILURE                     = 38;
-    private final static int PS_NET_DOWN_REASON_UMTS_REATTACH_REQ                   = 39;
-    private final static int PS_NET_DOWN_REASON_TFT_SEMANTIC_ERROR                  = 41;
-    private final static int PS_NET_DOWN_REASON_TFT_SYNTAX_ERROR                    = 42;
-    private final static int PS_NET_DOWN_REASON_UNKNOWN_PDP_CONTEXT                 = 43;
-    private final static int PS_NET_DOWN_REASON_FILTER_SEMANTIC_ERROR               = 44;
-    private final static int PS_NET_DOWN_REASON_FILTER_SYNTAX_ERROR                 = 45;
-    private final static int PS_NET_DOWN_REASON_PDP_WITHOUT_ACTIVE_TFT              = 46;
-    private final static int PS_NET_DOWN_REASON_INVALID_TRANSACTION_ID              = 81;
-    private final static int PS_NET_DOWN_REASON_MESSAGE_INCORRECT_SEMANTIC          = 95;
-    private final static int PS_NET_DOWN_REASON_INVALID_MANDATORY_INFO              = 96;
-    private final static int PS_NET_DOWN_REASON_MESSAGE_TYPE_UNSUPPORTED            = 97;
-    private final static int PS_NET_DOWN_REASON_MSG_TYPE_NONCOMPATIBLE_STATE        = 98;
-    private final static int PS_NET_DOWN_REASON_UNKNOWN_INFO_ELEMENT                = 99;
-    private final static int PS_NET_DOWN_REASON_CONDITIONAL_IE_ERROR                = 100;
-    private final static int PS_NET_DOWN_REASON_MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE = 101;
-    private final static int PS_NET_DOWN_REASON_PROTOCOL_ERROR                      = 111;
-    private final static int PS_NET_DOWN_REASON_APN_TYPE_CONFLICT                   = 112;
-    private final static int PS_NET_DOWN_REASON_UNKNOWN_CAUSE_CODE                  = 113;
-    private final static int PS_NET_DOWN_REASON_INTERNAL_MIN                        = 200;
-    private final static int PS_NET_DOWN_REASON_INTERNAL_ERROR                      = 201;
-    private final static int PS_NET_DOWN_REASON_INTERNAL_CALL_ENDED                 = 202;
-    private final static int PS_NET_DOWN_REASON_INTERNAL_UNKNOWN_CAUSE_CODE         = 203;
-    private final static int PS_NET_DOWN_REASON_INTERNAL_MAX                        = 204;
-    private final static int PS_NET_DOWN_REASON_CDMA_LOCK                           = 500;
-    private final static int PS_NET_DOWN_REASON_INTERCEPT                           = 501;
-    private final static int PS_NET_DOWN_REASON_REORDER                             = 502;
-    private final static int PS_NET_DOWN_REASON_REL_SO_REJ                          = 503;
-    private final static int PS_NET_DOWN_REASON_INCOM_CALL                          = 504;
-    private final static int PS_NET_DOWN_REASON_ALERT_STOP                          = 505;
-    private final static int PS_NET_DOWN_REASON_ACTIVATION                          = 506;
-    private final static int PS_NET_DOWN_REASON_MAX_ACCESS_PROBE                    = 507;
-    private final static int PS_NET_DOWN_REASON_CCS_NOT_SUPPORTED_BY_BS             = 508;
-    private final static int PS_NET_DOWN_REASON_NO_RESPONSE_FROM_BS                 = 509;
-    private final static int PS_NET_DOWN_REASON_REJECTED_BY_BS                      = 510;
-    private final static int PS_NET_DOWN_REASON_INCOMPATIBLE                        = 511;
-    private final static int PS_NET_DOWN_REASON_ALREADY_IN_TC                       = 512;
-    private final static int PS_NET_DOWN_REASON_USER_CALL_ORIG_DURING_GPS           = 513;
-    private final static int PS_NET_DOWN_REASON_USER_CALL_ORIG_DURING_SMS           = 514;
-    private final static int PS_NET_DOWN_REASON_NO_CDMA_SRV                         = 515;
-    private final static int PS_NET_DOWN_REASON_CONF_FAILED                         = 1000;
-    private final static int PS_NET_DOWN_REASON_INCOM_REJ                           = 1001;
-    private final static int PS_NET_DOWN_REASON_NO_GW_SRV                           = 1002;
-    private final static int PS_NET_DOWN_REASON_CD_GEN_OR_BUSY                      = 1500;
-    private final static int PS_NET_DOWN_REASON_CD_BILL_OR_AUTH                     = 1501;
-    private final static int PS_NET_DOWN_REASON_CHG_HDR                             = 1502;
-    private final static int PS_NET_DOWN_REASON_EXIT_HDR                            = 1503;
-    private final static int PS_NET_DOWN_REASON_HDR_NO_SESSION                      = 1504;
-    private final static int PS_NET_DOWN_REASON_HDR_ORIG_DURING_GPS_FIX             = 1505;
-    private final static int PS_NET_DOWN_REASON_HDR_CS_TIMEOUT                      = 1506;
-    private final static int PS_NET_DOWN_REASON_HDR_RELEASED_BY_CM                  = 1507;
-    private final static int PS_NET_DOWN_REASON_CLIENT_END                          = 2000;
-    private final static int PS_NET_DOWN_REASON_NO_SRV                              = 2001;
-    private final static int PS_NET_DOWN_REASON_FADE                                = 2002;
-    private final static int PS_NET_DOWN_REASON_REL_NORMAL                          = 2003;
-    private final static int PS_NET_DOWN_REASON_ACC_IN_PROG                         = 2004;
-    private final static int PS_NET_DOWN_REASON_ACC_FAIL                            = 2005;
-    private final static int PS_NET_DOWN_REASON_REDIR_OR_HANDOFF                    = 2006;
-
-    // ***** Instance Variables
 
     // ***** Constructor
-    CdmaDataConnection(CDMAPhone phone) {
-        super(phone);
-
-        if (DBG) log("CdmaDataConnection <constructor>");
+    private CdmaDataConnection(CDMAPhone phone, String name) {
+        super(phone, name);
     }
 
     /**
-     * Setup a data connection
+     * Create the connection object
      *
-     * @param onCompleted
-     *            notify success or not after down
+     * @param phone
+     * @return CdmaDataConnection that was created.
      */
-    void connect(Message onCompleted) {
+    static CdmaDataConnection makeDataConnection(CDMAPhone phone) {
+        synchronized (mCountLock) {
+            mCount += 1;
+        }
+        CdmaDataConnection cdmaDc = new CdmaDataConnection(phone, "CdmaDataConnection-" + mCount);
+        cdmaDc.start();
+        if (DBG) cdmaDc.log("Made " + cdmaDc.getName());
+        return cdmaDc;
+    }
+
+    /**
+     * Begin setting up a data connection, calls setupDataCall
+     * and the ConnectionParams will be returned with the
+     * EVENT_SETUP_DATA_CONNECTION_DONE AsyncResul.userObj.
+     *
+     * @param cp is the connection parameters
+     */
+    @Override
+    protected void onConnect(ConnectionParams cp) {
         if (DBG) log("CdmaDataConnection Connecting...");
 
-        state = State.ACTIVATING;
-        onConnectCompleted = onCompleted;
         createTime = -1;
         lastFailTime = -1;
         lastFailCause = FailCause.NONE;
-        receivedDisconnectReq = false;
+
+        // msg.obj will be returned in AsyncResult.userObj;
+        Message msg = obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE, cp);
+        msg.obj = cp;
         phone.mCM.setupDataCall(Integer.toString(RILConstants.SETUP_DATA_TECH_CDMA),
                 Integer.toString(RILConstants.DATA_PROFILE_DEFAULT), null, null,
-                null, Integer.toString(RILConstants.SETUP_DATA_AUTH_PAP_CHAP),
-                obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE));
+                null, Integer.toString(RILConstants.SETUP_DATA_AUTH_PAP_CHAP), msg);
     }
 
-    private void tearDownData(Message msg) {
-        if (phone.mCM.getRadioState().isOn()) {
-            phone.mCM.deactivateDataCall(cid, obtainMessage(EVENT_DEACTIVATE_DONE, msg));
-        }
-    }
-
-    protected void disconnect(Message msg) {
-        onDisconnect = msg;
-        if (state == State.ACTIVE) {
-            tearDownData(msg);
-        } else if (state == State.ACTIVATING) {
-            receivedDisconnectReq = true;
-        } else {
-            // state == INACTIVE.  Nothing to do, so notify immediately.
-            notifyDisconnect(msg);
-        }
-    }
-
-
+    @Override
     public String toString() {
-        return "State=" + state + " create=" + createTime + " lastFail="
-                + lastFailTime + " lastFailCause=" + lastFailCause;
+        return "State=" + getCurrentState().getName() + " create=" + createTime + " lastFail="
+                + lastFailTime + " lastFasilCause=" + lastFailCause;
     }
 
-
-    protected void notifyFail(FailCause cause, Message onCompleted) {
-        if (onCompleted == null) {
-            return;
-        }
-        state = State.INACTIVE;
-        lastFailCause = cause;
-        lastFailTime = System.currentTimeMillis();
-        onConnectCompleted = null;
-
-        if(DBG) {
-            log("Notify data connection fail at " + lastFailTime +
-                    " due to " + lastFailCause);
-        }
-
-        AsyncResult.forMessage(onCompleted, cause, new Exception());
-        onCompleted.sendToTarget();
-    }
-
-    protected void notifySuccess(Message onCompleted) {
-        if (onCompleted == null) {
-            return;
-        }
-
-        state = State.ACTIVE;
-        createTime = System.currentTimeMillis();
-        onConnectCompleted = null;
-        onCompleted.arg1 = cid;
-
-        if (DBG) log("Notify data connection success at " + createTime);
-
-        AsyncResult.forMessage(onCompleted);
-        onCompleted.sendToTarget();
-    }
-
-    protected void notifyDisconnect(Message msg) {
-        if (DBG) log("Notify data connection disconnect");
-
-        if (msg != null) {
-            AsyncResult.forMessage(msg);
-            msg.sendToTarget();
-        }
-        clearSettings();
-    }
-
-    protected void onLinkStateChanged(DataLink.LinkState linkState) {
-        switch (linkState) {
-            case LINK_UP:
-                notifySuccess(onConnectCompleted);
-                break;
-
-            case LINK_DOWN:
-            case LINK_EXITED:
-                phone.mCM.getLastDataCallFailCause(obtainMessage(EVENT_GET_LAST_FAIL_DONE));
-                break;
-        }
-    }
-
+    @Override
     protected FailCause getFailCauseFromRequest(int rilCause) {
         FailCause cause;
 
@@ -253,73 +109,19 @@
         return cause;
     }
 
-    protected void log(String s) {
-        Log.d(LOG_TAG, "[CdmaDataConnection] " + s);
-    }
-
     @Override
-    protected void onDeactivated(AsyncResult ar) {
-        notifyDisconnect((Message) ar.userObj);
-        if (DBG) log("CDMA Connection Deactivated");
-    }
-
-    @Override
-    protected void onSetupConnectionCompleted(AsyncResult ar) {
-        if (ar.exception != null) {
-            Log.e(LOG_TAG, "CdmaDataConnection Init failed " + ar.exception);
-
-            if (receivedDisconnectReq) {
-                // Don't bother reporting the error if there's already a
-                // pending disconnect request, since DataConnectionTracker
-                // has already updated its state.
-                notifyDisconnect(onDisconnect);
-            } else {
-                if (ar.exception instanceof CommandException
-                        && ((CommandException) (ar.exception)).getCommandError()
-                        == CommandException.Error.RADIO_NOT_AVAILABLE) {
-                    notifyFail(FailCause.RADIO_NOT_AVAILABLE, onConnectCompleted);
-                } else {
-                    phone.mCM.getLastDataCallFailCause(obtainMessage(EVENT_GET_LAST_FAIL_DONE));
-                }
-            }
+    protected boolean isDnsOk(String[] domainNameServers) {
+        if ((NULL_IP.equals(domainNameServers[0])
+                && NULL_IP.equals(domainNameServers[1])
+                && !((CDMAPhone) phone).isDnsCheckDisabled())) {
+            return false;
         } else {
-            if (receivedDisconnectReq) {
-                // Don't bother reporting success if there's already a
-                // pending disconnect request, since DataConnectionTracker
-                // has already updated its state.
-                tearDownData(onDisconnect);
-            } else {
-                String[] response = ((String[]) ar.result);
-                cid = Integer.parseInt(response[0]);
-
-                if (response.length > 2) {
-                    interfaceName = response[1];
-                    ipAddress = response[2];
-                    String prefix = "net." + interfaceName + ".";
-                    gatewayAddress = SystemProperties.get(prefix + "gw");
-                    dnsServers[0] = SystemProperties.get(prefix + "dns1");
-                    dnsServers[1] = SystemProperties.get(prefix + "dns2");
-                    if (DBG) {
-                        log("interface=" + interfaceName + " ipAddress=" + ipAddress
-                            + " gateway=" + gatewayAddress + " DNS1=" + dnsServers[0]
-                            + " DNS2=" + dnsServers[1]);
-                    }
-
-                    if (NULL_IP.equals(dnsServers[0]) && NULL_IP.equals(dnsServers[1])
-                                        && !((CDMAPhone) phone).isDnsCheckDisabled()) {
-                        // Work around a race condition where QMI does not fill in DNS:
-                        // Deactivate PDP and let DataConnectionTracker retry.
-                        EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_BAD_DNS_ADDRESS,
-                                    dnsServers[0]);
-                        phone.mCM.deactivateDataCall(cid, obtainMessage(EVENT_FORCE_RETRY));
-                        return;
-                    }
-                }
-
-                onLinkStateChanged(DataLink.LinkState.LINK_UP);
-
-                if (DBG) log("CdmaDataConnection setup on cid = " + cid);
-            }
+            return true;
         }
     }
+
+    @Override
+    protected void log(String s) {
+        Log.d(LOG_TAG, "[" + getName() + "] " + s);
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index b63b0c4..ecd3380 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -386,7 +386,7 @@
                     Message msg = obtainMessage(EVENT_DISCONNECT_DONE, reason);
                     conn.disconnect(msg);
                 } else {
-                    conn.clearSettings();
+                    conn.reset();
                 }
             }
         }
@@ -403,7 +403,7 @@
     private CdmaDataConnection findFreeDataConnection() {
         for (DataConnection connBase : dataConnectionList) {
             CdmaDataConnection conn = (CdmaDataConnection) connBase;
-            if (conn.getState() == DataConnection.State.INACTIVE) {
+            if (conn.isInactive()) {
                 return conn;
             }
         }
@@ -801,7 +801,7 @@
         CdmaDataConnection dataConn;
 
        for (int i = 0; i < DATA_CONNECTION_POOL_SIZE; i++) {
-            dataConn = new CdmaDataConnection(mCdmaPhone);
+            dataConn = CdmaDataConnection.makeDataConnection(mCdmaPhone);
             dataConnectionList.add(dataConn);
        }
     }
diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
index 33d150a..2bb7968 100755
--- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
@@ -1050,33 +1050,10 @@
         return mCT.getMute();
     }
 
-    /**
-     * @deprecated Do not use.
-     */
-    @Deprecated
-    public void getPdpContextList(Message response) {
-        getDataCallList(response);
-    }
-
     public void getDataCallList(Message response) {
         mCM.getDataCallList(response);
     }
 
-    /**
-     * @deprecated Do not use.
-     */
-    @Deprecated
-    public List<PdpConnection> getCurrentPdpList() {
-        ArrayList<DataConnection> connections = new ArrayList<DataConnection>();
-        ArrayList<PdpConnection> pdp_list = new ArrayList<PdpConnection>();
-
-        for(int n = 0; n < connections.size(); n++) {
-            pdp_list.add((PdpConnection) connections.get(n));
-        }
-
-        return pdp_list;
-    }
-
     public List<DataConnection> getCurrentDataConnectionList () {
         return mDataConnection.getAllDataConnections();
     }
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
new file mode 100644
index 0000000..905d5e3
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2006 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.internal.telephony.gsm;
+
+import android.os.Message;
+import android.util.Log;
+
+import com.android.common.Patterns;
+import com.android.internal.telephony.DataConnection;
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.RILConstants;
+
+/**
+ * {@hide}
+ */
+public class GsmDataConnection extends DataConnection {
+
+    private static final String LOG_TAG = "GSM";
+
+    /** Fail cause of last PDP activate, from RIL_LastPDPActivateFailCause */
+    private static final int PDP_FAIL_OPERATOR_BARRED = 0x08;
+    private static final int PDP_FAIL_INSUFFICIENT_RESOURCES = 0x1A;
+    private static final int PDP_FAIL_MISSING_UKNOWN_APN = 0x1B;
+    private static final int PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE = 0x1C;
+    private static final int PDP_FAIL_USER_AUTHENTICATION = 0x1D;
+    private static final int PDP_FAIL_ACTIVATION_REJECT_GGSN = 0x1E;
+    private static final int PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED = 0x1F;
+    private static final int PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED = 0x20;
+    private static final int PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED = 0x21;
+    private static final int PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER = 0x22;
+    private static final int PDP_FAIL_NSAPI_IN_USE      = 0x23;
+    private static final int PDP_FAIL_PROTOCOL_ERRORS   = 0x6F;
+    private static final int PDP_FAIL_ERROR_UNSPECIFIED = 0xffff;
+
+    private static final int PDP_FAIL_REGISTRATION_FAIL = -1;
+    private static final int PDP_FAIL_GPRS_REGISTRATION_FAIL = -2;
+
+    //***** Instance Variables
+    private ApnSetting apn;
+
+    //***** Constructor
+    private GsmDataConnection(GSMPhone phone, String name) {
+        super(phone, name);
+    }
+
+    /**
+     * Create the connection object
+     *
+     * @param phone
+     * @return GsmDataConnection that was created.
+     */
+    static GsmDataConnection makeDataConnection(GSMPhone phone) {
+        synchronized (mCountLock) {
+            mCount += 1;
+        }
+        GsmDataConnection gsmDc = new GsmDataConnection(phone, "GsmDataConnection-" + mCount);
+        gsmDc.start();
+        if (DBG) gsmDc.log("Made " + gsmDc.getName());
+        return gsmDc;
+    }
+
+    /**
+     * Begin setting up a data connection, calls setupDataCall
+     * and the ConnectionParams will be returned with the
+     * EVENT_SETUP_DATA_CONNECTION_DONE AsyncResul.userObj.
+     *
+     * @param cp is the connection parameters
+     */
+    @Override
+    protected
+    void onConnect(ConnectionParams cp) {
+        apn = cp.apn;
+
+        if (DBG) log("Connecting to carrier: '" + apn.carrier
+                + "' APN: '" + apn.apn
+                + "' proxy: '" + apn.proxy + "' port: '" + apn.port);
+
+        setHttpProxy (apn.proxy, apn.port);
+
+        createTime = -1;
+        lastFailTime = -1;
+        lastFailCause = FailCause.NONE;
+
+        // msg.obj will be returned in AsyncResult.userObj;
+        Message msg = obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE, cp);
+        msg.obj = cp;
+
+        int authType = apn.authType;
+        if (authType == -1) {
+            authType = (apn.user != null) ? RILConstants.SETUP_DATA_AUTH_PAP_CHAP :
+                RILConstants.SETUP_DATA_AUTH_NONE;
+        }
+        phone.mCM.setupDataCall(Integer.toString(RILConstants.SETUP_DATA_TECH_GSM),
+                Integer.toString(RILConstants.DATA_PROFILE_DEFAULT), apn.apn, apn.user,
+                apn.password, Integer.toString(authType), msg);
+    }
+
+    @Override
+    protected void clearSettings() {
+        super.clearSettings();
+        apn = null;
+    }
+
+    @Override
+    public String toString() {
+        return "State=" + getCurrentState().getName() + " Apn=" + apn +
+               " create=" + createTime + " lastFail=" + lastFailTime +
+               " lastFailCause=" + lastFailCause;
+    }
+
+    @Override
+    protected FailCause getFailCauseFromRequest(int rilCause) {
+        FailCause cause;
+
+        switch (rilCause) {
+            case PDP_FAIL_OPERATOR_BARRED:
+                cause = FailCause.OPERATOR_BARRED;
+                break;
+            case PDP_FAIL_INSUFFICIENT_RESOURCES:
+                cause = FailCause.INSUFFICIENT_RESOURCES;
+                break;
+            case PDP_FAIL_MISSING_UKNOWN_APN:
+                cause = FailCause.MISSING_UKNOWN_APN;
+                break;
+            case PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE:
+                cause = FailCause.UNKNOWN_PDP_ADDRESS;
+                break;
+            case PDP_FAIL_USER_AUTHENTICATION:
+                cause = FailCause.USER_AUTHENTICATION;
+                break;
+            case PDP_FAIL_ACTIVATION_REJECT_GGSN:
+                cause = FailCause.ACTIVATION_REJECT_GGSN;
+                break;
+            case PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED:
+                cause = FailCause.ACTIVATION_REJECT_UNSPECIFIED;
+                break;
+            case PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER:
+                cause = FailCause.SERVICE_OPTION_OUT_OF_ORDER;
+                break;
+            case PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED:
+                cause = FailCause.SERVICE_OPTION_NOT_SUPPORTED;
+                break;
+            case PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED:
+                cause = FailCause.SERVICE_OPTION_NOT_SUBSCRIBED;
+                break;
+            case PDP_FAIL_NSAPI_IN_USE:
+                cause = FailCause.NSAPI_IN_USE;
+                break;
+            case PDP_FAIL_PROTOCOL_ERRORS:
+                cause = FailCause.PROTOCOL_ERRORS;
+                break;
+            case PDP_FAIL_ERROR_UNSPECIFIED:
+                cause = FailCause.UNKNOWN;
+                break;
+            case PDP_FAIL_REGISTRATION_FAIL:
+                cause = FailCause.REGISTRATION_FAIL;
+                break;
+            case PDP_FAIL_GPRS_REGISTRATION_FAIL:
+                cause = FailCause.GPRS_REGISTRATION_FAIL;
+                break;
+            default:
+                cause = FailCause.UNKNOWN;
+        }
+        return cause;
+    }
+
+    @Override
+    protected boolean isDnsOk(String[] domainNameServers) {
+        if (NULL_IP.equals(dnsServers[0]) && NULL_IP.equals(dnsServers[1])
+                    && !((GSMPhone) phone).isDnsCheckDisabled()) {
+            // Work around a race condition where QMI does not fill in DNS:
+            // Deactivate PDP and let DataConnectionTracker retry.
+            // Do not apply the race condition workaround for MMS APN
+            // if Proxy is an IP-address.
+            // Otherwise, the default APN will not be restored anymore.
+            if (!apn.types[0].equals(Phone.APN_TYPE_MMS)
+                || !isIpAddress(apn.mmsProxy)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    protected void log(String s) {
+        Log.d(LOG_TAG, "[" + getName() + "] " + s);
+    }
+
+    public ApnSetting getApn() {
+        return this.apn;
+    }
+
+    private void setHttpProxy(String httpProxy, String httpPort) {
+        if (httpProxy == null || httpProxy.length() == 0) {
+            phone.setSystemProperty("net.gprs.http-proxy", null);
+            return;
+        }
+
+        if (httpPort == null || httpPort.length() == 0) {
+            httpPort = "8080";     // Default to port 8080
+        }
+
+        phone.setSystemProperty("net.gprs.http-proxy",
+                "http://" + httpProxy + ":" + httpPort + "/");
+    }
+
+    private boolean isIpAddress(String address) {
+        if (address == null) return false;
+
+        return Patterns.IP_ADDRESS.matcher(apn.mmsProxy).matches();
+    }
+}
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index fb7aa3d..5c97925 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -126,8 +126,8 @@
      */
     private ArrayList<DataConnection> pdpList;
 
-    /** Currently active PdpConnection */
-    private PdpConnection mActivePdp;
+    /** Currently active DataConnection */
+    private GsmDataConnection mActivePdp;
 
     /** Is packet service restricted by network */
     private boolean mIsPsRestricted = false;
@@ -137,7 +137,7 @@
     // TODO: Increase this to match the max number of simultaneous
     // PDP contexts we plan to support.
     /**
-     * Pool size of PdpConnection objects.
+     * Pool size of DataConnection objects.
      */
     private static final int PDP_CONNECTION_POOL_SIZE = 1;
 
@@ -382,7 +382,7 @@
     }
 
     /**
-     * Formerly this method was ArrayList<PdpConnection> getAllPdps()
+     * Formerly this method was ArrayList<GsmDataConnection> getAllPdps()
      */
     public ArrayList<DataConnection> getAllDataConnections() {
         ArrayList<DataConnection> pdps = (ArrayList<DataConnection>)pdpList.clone();
@@ -452,7 +452,7 @@
                 waitingApns = buildWaitingApns();
                 if (waitingApns.isEmpty()) {
                     if (DBG) log("No APN found");
-                    notifyNoData(PdpConnection.FailCause.MISSING_UKNOWN_APN);
+                    notifyNoData(GsmDataConnection.FailCause.MISSING_UKNOWN_APN);
                     return false;
                 } else {
                     log ("Create from allApns : " + apnListToString(allApns));
@@ -487,7 +487,7 @@
      * there is no mechanism for abandoning an INITING/CONNECTING session,
      * but would likely involve cancelling pending async requests or
      * setting a flag or new state to ignore them when they came in
-     * @param tearDown true if the underlying PdpConnection should be
+     * @param tearDown true if the underlying GsmDataConnection should be
      * disconnected.
      * @param reason reason for the clean up.
      */
@@ -505,12 +505,11 @@
         setState(State.DISCONNECTING);
 
         for (DataConnection conn : pdpList) {
-            PdpConnection pdp = (PdpConnection) conn;
             if (tearDown) {
                 Message msg = obtainMessage(EVENT_DISCONNECT_DONE, reason);
-                pdp.disconnect(msg);
+                conn.disconnect(msg);
             } else {
-                pdp.clearSettings();
+                conn.reset();
             }
         }
         stopNetStatPoll();
@@ -564,10 +563,10 @@
         return result;
     }
 
-    private PdpConnection findFreePdp() {
+    private GsmDataConnection findFreePdp() {
         for (DataConnection conn : pdpList) {
-            PdpConnection pdp = (PdpConnection) conn;
-            if (pdp.getState() == DataConnection.State.INACTIVE) {
+            GsmDataConnection pdp = (GsmDataConnection) conn;
+            if (pdp.isInactive()) {
                 return pdp;
             }
         }
@@ -576,13 +575,13 @@
 
     private boolean setupData(String reason) {
         ApnSetting apn;
-        PdpConnection pdp;
+        GsmDataConnection pdp;
 
         apn = getNextApn();
         if (apn == null) return false;
         pdp = findFreePdp();
         if (pdp == null) {
-            if (DBG) log("setupData: No free PdpConnection found!");
+            if (DBG) log("setupData: No free GsmDataConnection found!");
             return false;
         }
         mActiveApn = apn;
@@ -591,7 +590,7 @@
         Message msg = obtainMessage();
         msg.what = EVENT_DATA_SETUP_COMPLETE;
         msg.obj = reason;
-        pdp.connect(apn, msg);
+        pdp.connect(msg, apn);
 
         setState(State.INITING);
         phone.notifyDataConnection(reason);
@@ -974,13 +973,8 @@
      * seems like it deserves an error notification.
      * Transient errors are ignored
      */
-    private boolean shouldPostNotification(PdpConnection.FailCause  cause) {
-        boolean shouldPost = true;
-        // TODO CHECK
-        // if (dataLink != null) {
-        //    shouldPost = dataLink.getLastLinkExitCode() != DataLink.EXIT_OPEN_FAILED;
-        //}
-        return (shouldPost && cause != PdpConnection.FailCause.UNKNOWN);
+    private boolean shouldPostNotification(GsmDataConnection.FailCause  cause) {
+        return (cause != GsmDataConnection.FailCause.UNKNOWN);
     }
 
     /**
@@ -1046,7 +1040,7 @@
         }
     }
 
-    private void notifyNoData(PdpConnection.FailCause lastFailCauseCode) {
+    private void notifyNoData(GsmDataConnection.FailCause lastFailCauseCode) {
         setState(State.FAILED);
     }
 
@@ -1069,7 +1063,7 @@
         mRetryMgr.resetRetryCount();
 
         // TODO:  To support simultaneous PDP contexts, this should really only call
-        // cleanUpConnection if it needs to free up a PdpConnection.
+        // cleanUpConnection if it needs to free up a GsmDataConnection.
         cleanUpConnection(true, Phone.REASON_APN_SWITCHED);
     }
 
@@ -1149,8 +1143,8 @@
             // that the existing connection may service that type, in which
             // case we should try the next type, etc.
         } else {
-            PdpConnection.FailCause cause;
-            cause = (PdpConnection.FailCause) (ar.result);
+            GsmDataConnection.FailCause cause;
+            cause = (GsmDataConnection.FailCause) (ar.result);
             if(DBG) log("PDP setup failed " + cause);
                     // Log this failure to the Event Logs.
             if (cause.isEventLoggable()) {
@@ -1259,9 +1253,9 @@
                 if (cursor.getCount() > 0) {
                     allApns = createApnList(cursor);
                     // TODO: Figure out where this fits in.  This basically just
-                    // writes the pap-secrets file.  No longer tied to PdpConnection
+                    // writes the pap-secrets file.  No longer tied to GsmDataConnection
                     // object.  Not used on current platform (no ppp).
-                    //PdpConnection pdp = pdpList.get(pdp_name);
+                    //GsmDataConnection pdp = pdpList.get(pdp_name);
                     //if (pdp != null && pdp.dataLink != null) {
                     //    pdp.dataLink.setPasswordInfo(cursor);
                     //}
@@ -1273,7 +1267,7 @@
         if (allApns.isEmpty()) {
             if (DBG) log("No APN found for carrier: " + operator);
             preferredApn = null;
-            notifyNoData(PdpConnection.FailCause.MISSING_UKNOWN_APN);
+            notifyNoData(GsmDataConnection.FailCause.MISSING_UKNOWN_APN);
         } else {
             preferredApn = getPreferredApn();
             Log.d(LOG_TAG, "Get PreferredAPN");
@@ -1289,14 +1283,14 @@
         DataConnection pdp;
 
         for (int i = 0; i < PDP_CONNECTION_POOL_SIZE; i++) {
-            pdp = new PdpConnection(mGsmPhone);
+            pdp = GsmDataConnection.makeDataConnection(mGsmPhone);
             pdpList.add(pdp);
          }
     }
 
     private void destroyAllPdpList() {
         if(pdpList != null) {
-            PdpConnection pdp;
+            GsmDataConnection pdp;
             pdpList.removeAll(pdpList);
         }
     }
@@ -1361,7 +1355,7 @@
         return result.toString();
     }
 
-    private void startDelayedRetry(PdpConnection.FailCause cause, String reason) {
+    private void startDelayedRetry(GsmDataConnection.FailCause cause, String reason) {
         notifyNoData(cause);
         reconnectAfterFail(cause, reason);
     }
diff --git a/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java b/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java
deleted file mode 100644
index 02b061c..0000000
--- a/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
- * Copyright (C) 2006 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.internal.telephony.gsm;
-
-import android.os.*;
-import android.util.EventLog;
-import android.util.Log;
-
-import com.android.common.Patterns;
-import com.android.internal.telephony.CommandException;
-import com.android.internal.telephony.CommandsInterface;
-import com.android.internal.telephony.DataConnection;
-import com.android.internal.telephony.DataLink;
-import com.android.internal.telephony.Phone;
-import com.android.internal.telephony.RILConstants;
-import com.android.internal.telephony.TelephonyEventLog;
-
-/**
- * {@hide}
- */
-public class PdpConnection extends DataConnection {
-
-    private static final String LOG_TAG = "GSM";
-    private static final boolean DBG  = true;
-
-    /** Fail cause of last PDP activate, from RIL_LastPDPActivateFailCause */
-    private static final int PDP_FAIL_OPERATOR_BARRED = 0x08;
-    private static final int PDP_FAIL_INSUFFICIENT_RESOURCES = 0x1A;
-    private static final int PDP_FAIL_MISSING_UKNOWN_APN = 0x1B;
-    private static final int PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE = 0x1C;
-    private static final int PDP_FAIL_USER_AUTHENTICATION = 0x1D;
-    private static final int PDP_FAIL_ACTIVATION_REJECT_GGSN = 0x1E;
-    private static final int PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED = 0x1F;
-    private static final int PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED = 0x20;
-    private static final int PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED = 0x21;
-    private static final int PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER = 0x22;
-    private static final int PDP_FAIL_NSAPI_IN_USE      = 0x23;
-    private static final int PDP_FAIL_PROTOCOL_ERRORS   = 0x6F;
-    private static final int PDP_FAIL_ERROR_UNSPECIFIED = 0xffff;
-
-    private static final int PDP_FAIL_REGISTRATION_FAIL = -1;
-    private static final int PDP_FAIL_GPRS_REGISTRATION_FAIL = -2;
-
-    //***** Instance Variables
-    private String pdp_name;
-    private ApnSetting apn;
-
-    //***** Constructor
-    PdpConnection(GSMPhone phone) {
-        super(phone);
-    }
-
-    /**
-     * Setup PDP connection for provided apn
-     * @param apn for this connection
-     * @param onCompleted notify success or not after down
-     */
-    void connect(ApnSetting apn, Message onCompleted) {
-        if (DBG) log("Connecting to carrier: '" + apn.carrier
-                + "' APN: '" + apn.apn
-                + "' proxy: '" + apn.proxy + "' port: '" + apn.port);
-
-        setHttpProxy (apn.proxy, apn.port);
-
-        state = State.ACTIVATING;
-        this.apn = apn;
-        onConnectCompleted = onCompleted;
-        createTime = -1;
-        lastFailTime = -1;
-        lastFailCause = FailCause.NONE;
-        receivedDisconnectReq = false;
-
-        int authType = apn.authType;
-        if (authType == -1) {
-            authType = (apn.user != null) ? RILConstants.SETUP_DATA_AUTH_PAP_CHAP :
-                RILConstants.SETUP_DATA_AUTH_NONE;
-        }
-        phone.mCM.setupDataCall(Integer.toString(RILConstants.SETUP_DATA_TECH_GSM),
-                Integer.toString(RILConstants.DATA_PROFILE_DEFAULT), apn.apn, apn.user,
-                apn.password, Integer.toString(authType),
-                obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE));
-    }
-
-    private void tearDownData(Message msg) {
-        if (phone.mCM.getRadioState().isOn()) {
-            phone.mCM.deactivateDataCall(cid, obtainMessage(EVENT_DEACTIVATE_DONE, msg));
-        }
-    }
-
-    protected void disconnect(Message msg) {
-        onDisconnect = msg;
-        if (state == State.ACTIVE) {
-            tearDownData(msg);
-        } else if (state == State.ACTIVATING) {
-            receivedDisconnectReq = true;
-        } else {
-            // state == INACTIVE.  Nothing to do, so notify immediately.
-            notifyDisconnect(msg);
-        }
-    }
-
-    public void clearSettings() {
-        super.clearSettings();
-        apn = null;
-    }
-
-    public String toString() {
-        return "State=" + state + " Apn=" + apn +
-               " create=" + createTime + " lastFail=" + lastFailTime +
-               " lastFailCause=" + lastFailCause;
-    }
-
-
-    protected void notifyFail(FailCause cause, Message onCompleted) {
-        if (onCompleted == null) return;
-
-        state = State.INACTIVE;
-        lastFailCause = cause;
-        lastFailTime = System.currentTimeMillis();
-        onConnectCompleted = null;
-
-        if (DBG) {
-            log("Notify PDP fail at " + lastFailTime +
-                    " due to " + lastFailCause);
-        }
-
-        AsyncResult.forMessage(onCompleted, cause, new Exception());
-        onCompleted.sendToTarget();
-    }
-
-    protected void notifySuccess(Message onCompleted) {
-        if (onCompleted == null) {
-            return;
-        }
-
-        state = State.ACTIVE;
-        createTime = System.currentTimeMillis();
-        onConnectCompleted = null;
-        onCompleted.arg1 = cid;
-
-        if (DBG) log("Notify PDP success at " + createTime);
-
-        AsyncResult.forMessage(onCompleted);
-        onCompleted.sendToTarget();
-    }
-
-    protected void notifyDisconnect(Message msg) {
-        if (DBG) log("Notify PDP disconnect");
-
-        if (msg != null) {
-            AsyncResult.forMessage(msg);
-            msg.sendToTarget();
-        }
-        clearSettings();
-    }
-
-    protected void onLinkStateChanged(DataLink.LinkState linkState) {
-        switch (linkState) {
-            case LINK_UP:
-                notifySuccess(onConnectCompleted);
-                break;
-
-            case LINK_DOWN:
-            case LINK_EXITED:
-                phone.mCM.getLastPdpFailCause(
-                        obtainMessage (EVENT_GET_LAST_FAIL_DONE));
-                break;
-        }
-    }
-
-    protected FailCause getFailCauseFromRequest(int rilCause) {
-        FailCause cause;
-
-        switch (rilCause) {
-            case PDP_FAIL_OPERATOR_BARRED:
-                cause = FailCause.OPERATOR_BARRED;
-                break;
-            case PDP_FAIL_INSUFFICIENT_RESOURCES:
-                cause = FailCause.INSUFFICIENT_RESOURCES;
-                break;
-            case PDP_FAIL_MISSING_UKNOWN_APN:
-                cause = FailCause.MISSING_UKNOWN_APN;
-                break;
-            case PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE:
-                cause = FailCause.UNKNOWN_PDP_ADDRESS;
-                break;
-            case PDP_FAIL_USER_AUTHENTICATION:
-                cause = FailCause.USER_AUTHENTICATION;
-                break;
-            case PDP_FAIL_ACTIVATION_REJECT_GGSN:
-                cause = FailCause.ACTIVATION_REJECT_GGSN;
-                break;
-            case PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED:
-                cause = FailCause.ACTIVATION_REJECT_UNSPECIFIED;
-                break;
-            case PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER:
-                cause = FailCause.SERVICE_OPTION_OUT_OF_ORDER;
-                break;
-            case PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED:
-                cause = FailCause.SERVICE_OPTION_NOT_SUPPORTED;
-                break;
-            case PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED:
-                cause = FailCause.SERVICE_OPTION_NOT_SUBSCRIBED;
-                break;
-            case PDP_FAIL_NSAPI_IN_USE:
-                cause = FailCause.NSAPI_IN_USE;
-                break;
-            case PDP_FAIL_PROTOCOL_ERRORS:
-                cause = FailCause.PROTOCOL_ERRORS;
-                break;
-            case PDP_FAIL_ERROR_UNSPECIFIED:
-                cause = FailCause.UNKNOWN;
-                break;
-            case PDP_FAIL_REGISTRATION_FAIL:
-                cause = FailCause.REGISTRATION_FAIL;
-                break;
-            case PDP_FAIL_GPRS_REGISTRATION_FAIL:
-                cause = FailCause.GPRS_REGISTRATION_FAIL;
-                break;
-            default:
-                cause = FailCause.UNKNOWN;
-        }
-        return cause;
-    }
-
-    protected void log(String s) {
-        Log.d(LOG_TAG, "[PdpConnection] " + s);
-    }
-
-    @Override
-    protected void onDeactivated(AsyncResult ar) {
-        notifyDisconnect((Message) ar.userObj);
-        if (DBG) log("PDP Connection Deactivated");
-    }
-
-    @Override
-    protected void onSetupConnectionCompleted(AsyncResult ar) {
-        if (ar.exception != null) {
-            Log.e(LOG_TAG, "PDP Context Init failed " + ar.exception);
-
-            if (receivedDisconnectReq) {
-                // Don't bother reporting the error if there's already a
-                // pending disconnect request, since DataConnectionTracker
-                // has already updated its state.
-                notifyDisconnect(onDisconnect);
-            } else {
-                if ( ar.exception instanceof CommandException &&
-                        ((CommandException) (ar.exception)).getCommandError()
-                        == CommandException.Error.RADIO_NOT_AVAILABLE) {
-                    notifyFail(FailCause.RADIO_NOT_AVAILABLE,
-                            onConnectCompleted);
-                } else {
-                    phone.mCM.getLastPdpFailCause(
-                            obtainMessage(EVENT_GET_LAST_FAIL_DONE));
-                }
-            }
-        } else {
-            if (receivedDisconnectReq) {
-                // Don't bother reporting success if there's already a
-                // pending disconnect request, since DataConnectionTracker
-                // has already updated its state.
-                tearDownData(onDisconnect);
-            } else {
-                String[] response = ((String[]) ar.result);
-                cid = Integer.parseInt(response[0]);
-
-                if (response.length > 2) {
-                    interfaceName = response[1];
-                    ipAddress = response[2];
-                    String prefix = "net." + interfaceName + ".";
-                    gatewayAddress = SystemProperties.get(prefix + "gw");
-                    dnsServers[0] = SystemProperties.get(prefix + "dns1");
-                    dnsServers[1] = SystemProperties.get(prefix + "dns2");
-                    if (DBG) {
-                        log("interface=" + interfaceName + " ipAddress=" + ipAddress
-                            + " gateway=" + gatewayAddress + " DNS1=" + dnsServers[0]
-                            + " DNS2=" + dnsServers[1]);
-                    }
-
-                    if (NULL_IP.equals(dnsServers[0]) && NULL_IP.equals(dnsServers[1])
-                                        && !((GSMPhone) phone).isDnsCheckDisabled()) {
-                        // Work around a race condition where QMI does not fill in DNS:
-                        // Deactivate PDP and let DataConnectionTracker retry.
-                        // Do not apply the race condition workaround for MMS APN
-                        // if Proxy is an IP-address.
-                        // Otherwise, the default APN will not be restored anymore.
-                        if (!apn.types[0].equals(Phone.APN_TYPE_MMS)
-                                || !isIpAddress(apn.mmsProxy)) {
-                            EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_BAD_DNS_ADDRESS,
-                                    dnsServers[0]);
-                            phone.mCM.deactivateDataCall(cid, obtainMessage(EVENT_FORCE_RETRY));
-                            return;
-                        }
-                    }
-                }
-
-                onLinkStateChanged(DataLink.LinkState.LINK_UP);
-
-                if (DBG) log("PDP setup on cid = " + cid);
-            }
-        }
-    }
-
-    private boolean isIpAddress(String address) {
-        if (address == null) return false;
-
-        return Patterns.IP_ADDRESS.matcher(apn.mmsProxy).matches();
-    }
-
-    public ApnSetting getApn() {
-        return this.apn;
-    }
-}