Merge change 20400

* changes:
  Add lighting to animated water ripples.
diff --git a/api/current.xml b/api/current.xml
index 04b7c9a..9a635f6 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -72101,6 +72101,29 @@
 </parameter>
 </method>
 </interface>
+<interface name="GpsStatus.NmeaListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onNmeaReceived"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="timestamp" type="long">
+</parameter>
+<parameter name="nmea" type="java.lang.String">
+</parameter>
+</method>
+</interface>
 <class name="Location"
  extends="java.lang.Object"
  abstract="false"
@@ -72704,6 +72727,19 @@
 <parameter name="listener" type="android.location.GpsStatus.Listener">
 </parameter>
 </method>
+<method name="addNmeaListener"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.location.GpsStatus.NmeaListener">
+</parameter>
+</method>
 <method name="addProximityAlert"
  return="void"
  abstract="false"
@@ -72914,6 +72950,19 @@
 <parameter name="listener" type="android.location.GpsStatus.Listener">
 </parameter>
 </method>
+<method name="removeNmeaListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.location.GpsStatus.NmeaListener">
+</parameter>
+</method>
 <method name="removeProximityAlert"
  return="void"
  abstract="false"
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 008fa36..5b904cb 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -34,6 +34,7 @@
 #include <ui/ISurfaceComposer.h>
 #include <ui/ISurfaceFlingerClient.h>
 #include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
 
 #include <core/SkBitmap.h>
 #include <images/SkImageDecoder.h>
@@ -138,8 +139,10 @@
     sp<Surface> s = control->getSurface();
 
     // initialize opengl and egl
-    const EGLint attribs[] = { EGL_RED_SIZE, 5, EGL_GREEN_SIZE, 6,
-            EGL_BLUE_SIZE, 5, EGL_DEPTH_SIZE, 0, EGL_NONE };
+    const EGLint attribs[] = {
+            EGL_DEPTH_SIZE, 0, 
+            EGL_NONE 
+    };
     EGLint w, h, dummy;
     EGLint numConfigs;
     EGLConfig config;
@@ -149,8 +152,7 @@
     EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
 
     eglInitialize(display, 0, 0);
-    eglChooseConfig(display, attribs, &config, 1, &numConfigs);
-
+    EGLUtils::selectConfigForNativeWindow(display, attribs, s.get(), &config);
     surface = eglCreateWindowSurface(display, config, s.get(), NULL);
     context = eglCreateContext(display, config, NULL, NULL);
     eglQuerySurface(display, surface, EGL_WIDTH, &w);
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 70aceeb..9c20a4b 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -1743,7 +1743,14 @@
                 }
                 // If the drop-down obscures the keyboard, the user wouldn't see anything
                 // happening when pressing back, so we dismiss the entire dialog instead.
-                if (isInputMethodNotNeeded()) {
+                //
+                // also: if there is no text entered, we also want to dismiss the whole dialog,
+                // not just the soft keyboard.  the exception to this is if there are shortcuts
+                // that aren't displayed (e.g are being obscured by the soft keyboard); in that
+                // case we want to dismiss the soft keyboard so the user can see the rest of the
+                // shortcuts.
+                if (isInputMethodNotNeeded() ||
+                        (isEmpty() && getDropDownChildCount() >= getAdapter().getCount())) {
                     mSearchDialog.cancel();
                     return true;
                 }
diff --git a/core/java/android/app/SuggestionsAdapter.java b/core/java/android/app/SuggestionsAdapter.java
index bd4e66e..52e4a1f 100644
--- a/core/java/android/app/SuggestionsAdapter.java
+++ b/core/java/android/app/SuggestionsAdapter.java
@@ -73,6 +73,14 @@
     private int mIconName1Col;
     private int mIconName2Col;
     private int mBackgroundColorCol;
+    
+    // The extra used to tell a cursor to close itself. This is a hack, see the description by
+    // its use later in this file.
+    private static final String EXTRA_CURSOR_RESPOND_CLOSE_CURSOR = "cursor_respond_close_cursor";
+
+    // The bundle which contains {EXTRA_CURSOR_RESPOND_CLOSE_CURSOR=true}, just cached once
+    // so we don't bother recreating it a bunch.
+    private final Bundle mCursorRespondCloseCursorBundle;
 
     // This value is stored in SuggestionsAdapter by the SearchDialog to indicate whether
     // a particular list item should be selected upon the next call to notifyDataSetChanged.
@@ -129,6 +137,10 @@
                 mSearchDialog.setWorking(false);
             }
         };
+        
+        // Create this once because we'll reuse it a bunch.
+        mCursorRespondCloseCursorBundle = new Bundle();
+        mCursorRespondCloseCursorBundle.putBoolean(EXTRA_CURSOR_RESPOND_CLOSE_CURSOR, true);
 
         // delay 500ms when deleting
         getFilter().setDelayer(new Filter.Delayer() {
@@ -195,7 +207,21 @@
         if (DBG) Log.d(LOG_TAG, "changeCursor(" + c + ")");
 
         try {
+            Cursor oldCursor = getCursor();
             super.changeCursor(c);
+            
+            // We send a special respond to the cursor to tell it to close itself directly because
+            // it may not happen correctly for some cursors currently. This was originally
+            // included as a fix to http://b/2036290, in which the search dialog was holding
+            // on to references to the web search provider unnecessarily. This is being caused by
+            // the fact that the cursor is not being correctly closed in
+            // BulkCursorToCursorAdapter#close, which remains unfixed (see http://b/2015069).
+            //
+            // TODO: Remove this hack once http://b/2015069 is fixed.
+            if (oldCursor != null && oldCursor != c) {
+                oldCursor.respond(mCursorRespondCloseCursorBundle);
+            }
+            
             if (c != null) {
                 mFormatCol = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_FORMAT);
                 mText1Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_1);
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 0a354c0..405db83 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -88,7 +88,7 @@
     }
 
     /**
-     * Like {@link #peekWallpaper}, but always returns a valid Drawable.  If
+     * Like {@link #peek}, but always returns a valid Drawable.  If
      * no wallpaper is set, the system default wallpaper is returned.
      *
      * @return Returns a Drawable object that will draw the wallpaper.
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index 62d9267..9799ac4 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -18,11 +18,13 @@
 
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.os.SystemClock;
+import android.util.AttributeSet;
 import android.util.Log;
 import android.view.Gravity;
 import android.view.LayoutInflater;
@@ -31,6 +33,7 @@
 import android.widget.FrameLayout;
 import android.widget.RemoteViews;
 import android.widget.TextView;
+import android.widget.FrameLayout.LayoutParams;
 
 /**
  * Provides the glue to show AppWidget views. This class offers automatic animation
@@ -58,7 +61,8 @@
     };
 
     Context mContext;
-    
+    Context mRemoteContext;
+
     int mAppWidgetId;
     AppWidgetProviderInfo mInfo;
     View mView;
@@ -104,6 +108,16 @@
         return mInfo;
     }
 
+    /** {@inheritDoc} */
+    @Override
+    public LayoutParams generateLayoutParams(AttributeSet attrs) {
+        // We're being asked to inflate parameters, probably by a LayoutInflater
+        // in a remote Context. To help resolve any remote references, we
+        // inflate through our last mRemoteContext when it exists.
+        final Context context = mRemoteContext != null ? mRemoteContext : mContext;
+        return new FrameLayout.LayoutParams(context, attrs);
+    }
+
     /**
      * Process a set of {@link RemoteViews} coming in as an update from the
      * AppWidget provider. Will animate into these new views as needed.
@@ -143,6 +157,9 @@
             mLayoutId = -1;
             mViewMode = VIEW_MODE_DEFAULT;
         } else {
+            // Prepare a local reference to the remote Context so we're ready to
+            // inflate any requested LayoutParams.
+            mRemoteContext = getRemoteContext(remoteViews);
             int layoutId = remoteViews.getLayoutId();
 
             // If our stale view has been prepared to match active, and the new
@@ -203,6 +220,24 @@
         }
     }
 
+    /**
+     * Build a {@link Context} cloned into another package name, usually for the
+     * purposes of reading remote resources.
+     */
+    private Context getRemoteContext(RemoteViews views) {
+        // Bail if missing package name
+        final String packageName = views.getPackage();
+        if (packageName == null) return mContext;
+
+        try {
+            // Return if cloned successfully, otherwise default
+            return mContext.createPackageContext(packageName, Context.CONTEXT_RESTRICTED);
+        } catch (NameNotFoundException e) {
+            Log.e(TAG, "Package name " + packageName + " not found");
+            return mContext;
+        }
+    }
+
     protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
         if (CROSSFADE) {
             int alpha;
@@ -246,17 +281,15 @@
      * {@link FrameLayout.LayoutParams} before inserting.
      */
     protected void prepareView(View view) {
-        // Take requested dimensions from parent, but apply default gravity.
-        ViewGroup.LayoutParams requested = view.getLayoutParams();
+        // Take requested dimensions from child, but apply default gravity.
+        FrameLayout.LayoutParams requested = (FrameLayout.LayoutParams)view.getLayoutParams();
         if (requested == null) {
             requested = new FrameLayout.LayoutParams(LayoutParams.FILL_PARENT,
                     LayoutParams.FILL_PARENT);
         }
-        
-        FrameLayout.LayoutParams params =
-            new FrameLayout.LayoutParams(requested.width, requested.height);
-        params.gravity = Gravity.CENTER;
-        view.setLayoutParams(params);
+
+        requested.gravity = Gravity.CENTER;
+        view.setLayoutParams(requested);
     }
     
     /**
diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java
index c0db01a..70ea5d0 100644
--- a/core/java/android/content/ContentProviderOperation.java
+++ b/core/java/android/content/ContentProviderOperation.java
@@ -301,7 +301,8 @@
                 : mSelectionArgsBackReferences.entrySet()) {
             final Integer selectionArgIndex = selectionArgBackRef.getKey();
             final int backRefIndex = selectionArgBackRef.getValue();
-            newArgs[selectionArgIndex] = backRefToValue(backRefs, numBackRefs, backRefIndex);
+            newArgs[selectionArgIndex] =
+                    String.valueOf(backRefToValue(backRefs, numBackRefs, backRefIndex));
         }
         return newArgs;
     }
@@ -315,18 +316,18 @@
      * the numBackRefs
      * @return the string representation of the requested back reference.
      */
-    private static String backRefToValue(ContentProviderResult[] backRefs, int numBackRefs,
+    private static long backRefToValue(ContentProviderResult[] backRefs, int numBackRefs,
             Integer backRefIndex) {
         if (backRefIndex >= numBackRefs) {
             throw new ArrayIndexOutOfBoundsException("asked for back ref " + backRefIndex
                     + " but there are only " + numBackRefs + " back refs");
         }
         ContentProviderResult backRef = backRefs[backRefIndex];
-        String backRefValue;
+        long backRefValue;
         if (backRef.uri != null) {
-            backRefValue = backRef.uri.getLastPathSegment();
+            backRefValue = ContentUris.parseId(backRef.uri);
         } else {
-            backRefValue = String.valueOf(backRef.count);
+            backRefValue = backRef.count;
         }
         return backRefValue;
     }
diff --git a/core/java/android/inputmethodservice/KeyboardView.java b/core/java/android/inputmethodservice/KeyboardView.java
index 4d6b7be9..dff7cae 100755
--- a/core/java/android/inputmethodservice/KeyboardView.java
+++ b/core/java/android/inputmethodservice/KeyboardView.java
@@ -202,7 +202,12 @@
     private boolean mAbortKey;
     private Key mInvalidatedKey;
     private Rect mClipRegion = new Rect(0, 0, 0, 0);
-    
+
+    // Variables for dealing with multiple pointers
+    private int mOldPointerCount = 1;
+    private float mOldPointerX;
+    private float mOldPointerY;
+
     private Drawable mKeyBackground;
 
     private static final int REPEAT_INTERVAL = 50; // ~20 keys per second
@@ -226,6 +231,8 @@
     private Rect mDirtyRect = new Rect();
     /** The keyboard bitmap for faster updates */
     private Bitmap mBuffer;
+    /** Notes if the keyboard just changed, so that we could possibly reallocate the mBuffer. */
+    private boolean mKeyboardChanged;
     /** The canvas for the above mutable keyboard bitmap */
     private Canvas mCanvas;
     
@@ -339,6 +346,7 @@
         mPaint.setAntiAlias(true);
         mPaint.setTextSize(keyTextSize);
         mPaint.setTextAlign(Align.CENTER);
+        mPaint.setAlpha(255);
 
         mPadding = new Rect(0, 0, 0, 0);
         mMiniKeyboardCache = new HashMap<Key,View>();
@@ -404,9 +412,8 @@
         List<Key> keys = mKeyboard.getKeys();
         mKeys = keys.toArray(new Key[keys.size()]);
         requestLayout();
-        // Release buffer, just in case the new keyboard has a different size. 
-        // It will be reallocated on the next draw.
-        mBuffer = null;
+        // Hint to reallocate the buffer if the size changed
+        mKeyboardChanged = true;
         invalidateAllKeys();
         computeProximityThreshold(keyboard);
         mMiniKeyboardCache.clear(); // Not really necessary to do every time, but will free up views
@@ -566,17 +573,21 @@
     @Override
     public void onDraw(Canvas canvas) {
         super.onDraw(canvas);
-        if (mDrawPending || mBuffer == null) {
+        if (mDrawPending || mBuffer == null || mKeyboardChanged) {
             onBufferDraw();
         }
         canvas.drawBitmap(mBuffer, 0, 0, null);
     }
-    
+
     private void onBufferDraw() {
-        if (mBuffer == null) {
-            mBuffer = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
-            mCanvas = new Canvas(mBuffer);
+        if (mBuffer == null || mKeyboardChanged) {
+            if (mBuffer == null || mKeyboardChanged &&
+                    (mBuffer.getWidth() != getWidth() || mBuffer.getHeight() != getHeight())) {
+                mBuffer = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
+                mCanvas = new Canvas(mBuffer);
+            }
             invalidateAllKeys();
+            mKeyboardChanged = false;
         }
         final Canvas canvas = mCanvas;
         canvas.clipRect(mDirtyRect, Op.REPLACE);
@@ -592,7 +603,6 @@
         final Key[] keys = mKeys;
         final Key invalidKey = mInvalidatedKey;
 
-        paint.setAlpha(255);
         paint.setColor(mKeyTextColor);
         boolean drawSingleKey = false;
         if (invalidKey != null && canvas.getClipBounds(clipRegion)) {
@@ -613,7 +623,7 @@
             }
             int[] drawableState = key.getCurrentDrawableState();
             keyBackground.setState(drawableState);
-            
+
             // Switch the character to uppercase if shift is pressed
             String label = key.label == null? null : adjustCase(key.label).toString();
             
@@ -682,7 +692,6 @@
 
     private int getKeyIndices(int x, int y, int[] allKeys) {
         final Key[] keys = mKeys;
-        final boolean shifted = mKeyboard.isShifted();
         int primaryIndex = NOT_A_KEY;
         int closestKey = NOT_A_KEY;
         int closestKeyDist = mProximityThreshold + 1;
@@ -1013,15 +1022,48 @@
         }
         return false;
     }
-    
+
     @Override
     public boolean onTouchEvent(MotionEvent me) {
+        // Convert multi-pointer up/down events to single up/down events to 
+        // deal with the typical multi-pointer behavior of two-thumb typing
+        int pointerCount = me.getPointerCount();
+        boolean result = false;
+        if (pointerCount != mOldPointerCount) {
+            long now = me.getEventTime();
+            if (pointerCount == 1) {
+                // Send a down event for the latest pointer
+                MotionEvent down = MotionEvent.obtain(now, now, MotionEvent.ACTION_DOWN,
+                        me.getX(), me.getY(), me.getMetaState());
+                result = onModifiedTouchEvent(down);
+                down.recycle();
+            } else {
+                // Send an up event for the last pointer
+                MotionEvent up = MotionEvent.obtain(now, now, MotionEvent.ACTION_UP,
+                        mOldPointerX, mOldPointerY, me.getMetaState());
+                result = onModifiedTouchEvent(up);
+                up.recycle();
+            }
+        } else {
+            if (pointerCount == 1) {
+                mOldPointerX = me.getX();
+                mOldPointerY = me.getY();
+                result = onModifiedTouchEvent(me);
+            } else {
+                // Don't do anything when 2 pointers are down and moving.
+                result = true;
+            }
+        }
+        mOldPointerCount = pointerCount;
+        return result;
+    }
+
+    private boolean onModifiedTouchEvent(MotionEvent me) {
         int touchX = (int) me.getX() - mPaddingLeft;
         int touchY = (int) me.getY() + mVerticalCorrection - mPaddingTop;
         int action = me.getAction();
         long eventTime = me.getEventTime();
         int keyIndex = getKeyIndices(touchX, touchY, null);
-        
         if (mGestureDetector.onTouchEvent(me)) {
             showPreview(NOT_A_KEY);
             mHandler.removeMessages(MSG_REPEAT);
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index b24bab3..b5fa577 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -180,15 +180,33 @@
          * Reference to the row in the data table holding the primary phone number.
          * <P>Type: INTEGER REFERENCES data(_id)</P>
          */
+        @Deprecated
         public static final String PRIMARY_PHONE_ID = "primary_phone_id";
 
         /**
+         * Reference to the row in the data table holding the default phone number.
+         * If the contact has only one phone number, that number is the default one.
+         * Otherwise it is the one explicitly selected by the user as primary.
+         * <P>Type: INTEGER REFERENCES data(_id)</P>
+         */
+        public static final String DEFAULT_PHONE_ID = "default_phone_id";
+
+        /**
          * Reference to the row in the data table holding the primary email address.
          * <P>Type: INTEGER REFERENCES data(_id)</P>
          */
+        @Deprecated
         public static final String PRIMARY_EMAIL_ID = "primary_email_id";
 
         /**
+         * Reference to the row in the data table holding the default email address.
+         * If the contact has only one email address, that address is the default one.
+         * Otherwise it is the one explicitly selected by the user as primary.
+         * <P>Type: INTEGER REFERENCES data(_id)</P>
+         */
+        public static final String DEFAULT_EMAIL_ID = "default_email_id";
+
+        /**
          * Reference to the row in the data table holding the photo.
          * <P>Type: INTEGER REFERENCES data(_id)</P>
          */
@@ -210,19 +228,40 @@
          * The type of data, for example Home or Work.
          * <P>Type: INTEGER</P>
          */
+        @Deprecated
         public static final String PRIMARY_PHONE_TYPE = CommonDataKinds.Phone.TYPE;
 
         /**
+         * The type of data, for example Home or Work.
+         * <P>Type: INTEGER</P>
+         */
+        public static final String DEFAULT_PHONE_TYPE = "default_phone_type";
+
+        /**
          * The user defined label for the primary phone.
          * <P>Type: TEXT</P>
          */
+        @Deprecated
         public static final String PRIMARY_PHONE_LABEL = CommonDataKinds.Phone.LABEL;
 
         /**
+         * The user defined label for the default phone.
+         * <P>Type: TEXT</P>
+         */
+        public static final String DEFAULT_PHONE_LABEL = "default_phone_label";
+
+        /**
          * The primary phone number.
          * <P>Type: TEXT</P>
          */
+        @Deprecated
         public static final String PRIMARY_PHONE_NUMBER = CommonDataKinds.Phone.NUMBER;
+
+        /**
+         * The default phone number.
+         * <P>Type: TEXT</P>
+         */
+        public static final String DEFAULT_PHONE_NUMBER = "default_phone_number";
     }
 
     /**
@@ -292,7 +331,7 @@
          * A sub-directory of a single contact that contains all of the constituent raw contact
          * {@link Data} rows.
          */
-        public static final class Data implements BaseColumns, DataColumns, BaseSyncColumns {
+        public static final class Data implements BaseColumns, DataColumns {
             /**
              * no public constructor since this is a utility class
              */
@@ -523,6 +562,15 @@
         /** Generic data column, the meaning is {@link #MIMETYPE} specific */
         public static final String DATA15 = "data15";
 
+        /** Generic column for use by sync adapters. */
+        public static final String SYNC1 = "data_sync1";
+        /** Generic column for use by sync adapters. */
+        public static final String SYNC2 = "data_sync2";
+        /** Generic column for use by sync adapters. */
+        public static final String SYNC3 = "data_sync3";
+        /** Generic column for use by sync adapters. */
+        public static final String SYNC4 = "data_sync4";
+
         /**
          * An optional update or insert URI parameter that determines if the
          * corresponding raw contact should be marked as dirty. The default
@@ -537,7 +585,7 @@
      * definition and some generic columns. Each data type can define the meaning for each of
      * the generic columns.
      */
-    public static final class Data implements BaseColumns, DataColumns, BaseSyncColumns {
+    public static final class Data implements BaseColumns, DataColumns {
         /**
          * This utility class cannot be instantiated
          */
@@ -905,6 +953,12 @@
             public static final int TYPE_HOME = 1;
             public static final int TYPE_WORK = 2;
             public static final int TYPE_OTHER = 3;
+
+            /**
+             * The display name for the email address
+             * <P>Type: TEXT</P>
+             */
+            public static final String DISPLAY_NAME = "data4";
         }
 
         /**
@@ -1024,9 +1078,9 @@
             public static final String COUNTRY = "data13";
         }
 
-       /**
-        * Common data definition for IM addresses.
-        */
+        /**
+         * Common data definition for IM addresses.
+         */
         public static final class Im implements BaseCommonColumns, CommonColumns {
             private Im() {}
 
@@ -1060,6 +1114,7 @@
             public static final int PROTOCOL_GOOGLE_TALK = 5;
             public static final int PROTOCOL_ICQ = 6;
             public static final int PROTOCOL_JABBER = 7;
+            public static final int PROTOCOL_NETMEETING = 8;
         }
 
         /**
@@ -1085,6 +1140,102 @@
              * <P>Type: TEXT</P>
              */
             public static final String TITLE = "data4";
+
+            /**
+             * The department at this company as the user entered it.
+             * <P>Type: TEXT</P>
+             */
+            public static final String DEPARTMENT = "data5";
+
+            /**
+             * The job description at this company as the user entered it.
+             * <P>Type: TEXT</P>
+             */
+            public static final String JOB_DESCRIPTION = "data6";
+
+            /**
+             * The symbol of this company as the user entered it.
+             * <P>Type: TEXT</P>
+             */
+            public static final String SYMBOL = "data7";
+
+            /**
+             * The phonetic name of this company as the user entered it.
+             * <P>Type: TEXT</P>
+             */
+            public static final String PHONETIC_NAME = "data8";
+        }
+
+        /**
+         * Common data definition for miscellaneous information.
+         */
+        public static final class Miscellaneous implements BaseCommonColumns {
+            private Miscellaneous() {}
+
+            /** MIME type used when storing this in data table. */
+            public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/misc";
+
+            /**
+             * The birthday as the user entered it.
+             * <P>Type: TEXT</P>
+             */
+            public static final String BIRTHDAY = "data1";
+
+            /**
+             * The nickname as the user entered it.
+             * <P>Type: TEXT</P>
+             */
+            public static final String NICKNAME = "data2";
+        }
+
+        /**
+         * Common data definition for relations.
+         */
+        public static final class Relation implements BaseCommonColumns, CommonColumns {
+            private Relation() {}
+
+            /** MIME type used when storing this in data table. */
+            public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/relation";
+
+            public static final int TYPE_ASSISTANT = 1;
+            public static final int TYPE_BROTHER = 2;
+            public static final int TYPE_CHILD = 3;
+            public static final int TYPE_DOMESTIC_PARTNER = 4;
+            public static final int TYPE_FATHER = 5;
+            public static final int TYPE_FRIEND = 6;
+            public static final int TYPE_MANAGER = 7;
+            public static final int TYPE_MOTHER = 8;
+            public static final int TYPE_PARENT = 9;
+            public static final int TYPE_PARTNER = 10;
+            public static final int TYPE_REFERRED_BY = 11;
+            public static final int TYPE_RELATIVE = 12;
+            public static final int TYPE_SISTER = 13;
+            public static final int TYPE_SPOUSE = 14;
+
+            /**
+             * The name of the relative as the user entered it.
+             * <P>Type: TEXT</P>
+             */
+            public static final String NAME = DATA;
+        }
+
+        /**
+         * Common data definition for events.
+         */
+        public static final class Event implements BaseCommonColumns, CommonColumns {
+            private Event() {}
+
+            /** MIME type used when storing this in data table. */
+            public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/event";
+
+            public static final int TYPE_ANNIVERSARY = 1;
+            public static final int TYPE_OTHER = 2;
+            
+            /**
+             * The event start date as the user entered it.
+             * <P>Type: TEXT</P>
+             */
+            public static final String START_DATE = DATA;
         }
 
         /**
@@ -1149,12 +1300,20 @@
         /**
          * Website related to the contact.
          */
-        public static final class Website implements BaseCommonColumns {
+        public static final class Website implements BaseCommonColumns, CommonColumns {
             private Website() {}
 
             /** MIME type used when storing this in data table. */
             public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/website";
 
+            public static final int TYPE_HOMEPAGE = 1;
+            public static final int TYPE_BLOG = 2;
+            public static final int TYPE_PROFILE = 3;
+            public static final int TYPE_HOME = 4;
+            public static final int TYPE_WORK = 5;
+            public static final int TYPE_FTP = 6;
+            public static final int TYPE_OTHER = 7;
+
             /**
              * The website URL string.
              * <P>Type: TEXT</P>
@@ -1412,6 +1571,28 @@
         public static final String EXTRA_TARGET_RECT = "target_rect";
 
         /**
+         * Optional extra used with {@link #SHOW_OR_CREATE_CONTACT} to specify a
+         * desired dialog style, usually a variation on size. One of
+         * {@link #MODE_SMALL}, {@link #MODE_MEDIUM}, or {@link #MODE_LARGE}.
+         */
+        public static final String EXTRA_MODE = "mode";
+
+        /**
+         * Value for {@link #EXTRA_MODE} to show a small-sized dialog.
+         */
+        public static final int MODE_SMALL = 1;
+
+        /**
+         * Value for {@link #EXTRA_MODE} to show a medium-sized dialog.
+         */
+        public static final int MODE_MEDIUM = 2;
+
+        /**
+         * Value for {@link #EXTRA_MODE} to show a large-sized dialog.
+         */
+        public static final int MODE_LARGE = 3;
+
+        /**
          * Intents related to the Contacts app UI.
          */
         public static final class UI {
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index a109db5..e8bfa6a 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -185,7 +185,12 @@
      */
     static public final int NUM_SAMPLE_DATA = 4;
     
-    static private final int BASE_AVAIL_POINTERS = 2;
+    /**
+     * Number of possible pointers.
+     * @hide
+     */
+    static public final int BASE_AVAIL_POINTERS = 5;
+    
     static private final int BASE_AVAIL_SAMPLES = 8;
     
     static private final int MAX_RECYCLED = 10;
@@ -290,8 +295,19 @@
         ev.mNumPointers = pointers;
         ev.mNumSamples = 1;
         
-        System.arraycopy(inPointerIds, 0, ev.mPointerIdentifiers, 0, pointers);
-        System.arraycopy(inData, 0, ev.mDataSamples, 0, pointers * NUM_SAMPLE_DATA);
+        int[] pointerIdentifiers = ev.mPointerIdentifiers;
+        if (pointerIdentifiers.length < pointers) {
+            ev.mPointerIdentifiers = pointerIdentifiers = new int[pointers];
+        }
+        System.arraycopy(inPointerIds, 0, pointerIdentifiers, 0, pointers);
+        
+        final int ND = pointers * NUM_SAMPLE_DATA;
+        float[] dataSamples = ev.mDataSamples;
+        if (dataSamples.length < ND) {
+            ev.mDataSamples = dataSamples = new float[ND];
+        }
+        System.arraycopy(inData, 0, dataSamples, 0, ND);
+        
         ev.mTimeSamples[0] = eventTime;
 
         if (DEBUG_POINTERS) {
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index e5813e6..eeac1d2 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -185,6 +185,7 @@
     private boolean         mSupportZoom = true;
     private boolean         mBuiltInZoomControls = false;
     private boolean         mAllowFileAccess = true;
+    private boolean         mLoadWithOverviewMode = true;
 
     // Class to handle messages before WebCore is ready.
     private class EventHandler {
@@ -427,6 +428,22 @@
     }
 
     /**
+     * Set whether the WebView loads a page with overview mode.
+     * @hide Pending API council approval
+     */
+    public void setLoadWithOverviewMode(boolean overview) {
+        mLoadWithOverviewMode = overview;
+    }
+
+    /**
+     * Returns true if this WebView loads page with overview mode
+     * @hide Pending API council approval
+     */
+    public boolean getLoadWithOverviewMode() {
+        return mLoadWithOverviewMode;
+    }
+
+    /**
      * Store whether the WebView is saving form data.
      */
     public void setSaveFormData(boolean save) {
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 444ef54..2d87dd2 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -508,16 +508,13 @@
         "REQUEST_KEYBOARD" //                = 27;
     };
 
-    // width which view is considered to be fully zoomed out
-    static final int ZOOM_OUT_WIDTH = 1008;
-
     // default scale limit. Depending on the display density
     private static float DEFAULT_MAX_ZOOM_SCALE;
     private static float DEFAULT_MIN_ZOOM_SCALE;
     // scale limit, which can be set through viewport meta tag in the web page
     private float mMaxZoomScale;
     private float mMinZoomScale;
-    private boolean mMinZoomScaleFixed = false;
+    private boolean mMinZoomScaleFixed = true;
 
     // initial scale in percent. 0 means using default.
     private int mInitialScale = 0;
@@ -529,7 +526,7 @@
     boolean mInZoomOverview = false;
     // ideally mZoomOverviewWidth should be mContentWidth. But sites like espn,
     // engadget always have wider mContentWidth no matter what viewport size is.
-    int mZoomOverviewWidth = 0;
+    int mZoomOverviewWidth = WebViewCore.DEFAULT_VIEWPORT_WIDTH;
     float mLastScale;
 
     // default scale. Depending on the display density.
@@ -3686,9 +3683,8 @@
         // update mMinZoomScale if the minimum zoom scale is not fixed
         if (!mMinZoomScaleFixed) {
             mMinZoomScale = (float) getViewWidth()
-                    / Math.max(ZOOM_OUT_WIDTH, mDrawHistory ? mHistoryPicture
-                            .getWidth() : (mZoomOverviewWidth > 0 ?
-                                    mZoomOverviewWidth : mContentWidth));
+                    / (mDrawHistory ? mHistoryPicture.getWidth()
+                            : mZoomOverviewWidth);
         }
 
         // we always force, in case our height changed, in which case we still
@@ -4564,10 +4560,18 @@
     public boolean zoomOut() {
         // TODO: alternatively we can disallow this during draw history mode
         switchOutDrawHistory();
-        // Center zooming to the center of the screen.
-        mZoomCenterX = getViewWidth() * .5f;
-        mZoomCenterY = getViewHeight() * .5f;
-        return zoomWithPreview(mActualScale * 0.8f);
+        float scale = mActualScale * 0.8f;
+        if (scale < (mMinZoomScale + 0.1f) && WebView.ENABLE_DOUBLETAP_ZOOM
+                && mWebViewCore.getSettings().getUseWideViewPort()) {
+            // when zoom out to min scale, switch to overview mode
+            doDoubleTap();
+            return true;
+        } else {
+            // Center zooming to the center of the screen.
+            mZoomCenterX = getViewWidth() * .5f;
+            mZoomCenterY = getViewHeight() * .5f;
+            return zoomWithPreview(scale);
+        }
     }
 
     private void updateSelection() {
@@ -4666,14 +4670,6 @@
         mZoomCenterY = mLastTouchY;
         mInZoomOverview = !mInZoomOverview;
         if (mInZoomOverview) {
-            float newScale = (float) getViewWidth()
-                    / (mZoomOverviewWidth > 0 ? mZoomOverviewWidth
-                            : mContentWidth);
-            if (Math.abs(newScale - mActualScale) < 0.01) {
-                mInZoomOverview = !mInZoomOverview;
-                // as it is already full screen, do nothing.
-                return;
-            }
             if (getSettings().getBuiltInZoomControls()) {
                 if (mZoomButtonsController.isVisible()) {
                     mZoomButtonsController.setVisible(false);
@@ -4686,7 +4682,7 @@
                     mZoomControls.hide();
                 }
             }
-            zoomWithPreview(newScale);
+            zoomWithPreview((float) getViewWidth() / mZoomOverviewWidth);
         } else {
             // mLastTouchX and mLastTouchY are the point in the current viewport
             int contentX = viewToContent((int) mLastTouchX + mScrollX);
@@ -4992,14 +4988,14 @@
                 case SPAWN_SCROLL_TO_MSG_ID:
                     spawnContentScrollTo(msg.arg1, msg.arg2);
                     break;
-                case NEW_PICTURE_MSG_ID:
+                case NEW_PICTURE_MSG_ID: {
+                    WebSettings settings = mWebViewCore.getSettings();
                     // called for new content
                     final int viewWidth = getViewWidth();
                     final WebViewCore.DrawData draw =
                             (WebViewCore.DrawData) msg.obj;
                     final Point viewSize = draw.mViewPoint;
-                    boolean useWideViewport =
-                            mWebViewCore.getSettings().getUseWideViewPort();
+                    boolean useWideViewport = settings.getUseWideViewPort();
                     WebViewCore.RestoreState restoreState = draw.mRestoreState;
                     if (restoreState != null) {
                         mInZoomOverview = false;
@@ -5017,7 +5013,8 @@
                             mMaxZoomScale = restoreState.mMaxScale;
                         }
                         if (useWideViewport && restoreState.mViewScale == 0) {
-                            mInZoomOverview = ENABLE_DOUBLETAP_ZOOM;
+                            mInZoomOverview = ENABLE_DOUBLETAP_ZOOM
+                                    && settings.getLoadWithOverviewMode();
                         }
                         setNewZoomScale(mLastScale, false);
                         setContentScrollTo(restoreState.mScrollX,
@@ -5050,21 +5047,19 @@
                                 draw.mViewPoint.x);
                     }
                     if (!mMinZoomScaleFixed) {
-                        mMinZoomScale = (float) viewWidth
-                                / Math.max(ZOOM_OUT_WIDTH,
-                                mZoomOverviewWidth > 0 ? mZoomOverviewWidth
-                                        : mContentWidth);
+                        mMinZoomScale = (float) viewWidth / mZoomOverviewWidth;
                     }
                     if (!mDrawHistory && mInZoomOverview) {
                         // fit the content width to the current view. Ignore
                         // the rounding error case.
                         if (Math.abs((viewWidth * mInvActualScale)
                                 - mZoomOverviewWidth) > 1) {
-                            zoomWithPreview((float) viewWidth
-                                    / mZoomOverviewWidth);
+                            setNewZoomScale((float) viewWidth
+                                    / mZoomOverviewWidth, false);
                         }
                     }
                     break;
+                }
                 case WEBCORE_INITIALIZED_MSG_ID:
                     // nativeCreate sets mNativeClass to a non-zero value
                     nativeCreate(msg.arg1);
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index ff4e736..86b0843 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -105,6 +105,10 @@
     private int mWebkitScrollX = 0;
     private int mWebkitScrollY = 0;
 
+    // If the site doesn't use viewport meta tag to specify the viewport, use
+    // DEFAULT_VIEWPORT_WIDTH as default viewport width
+    static final int DEFAULT_VIEWPORT_WIDTH = 800;
+
     // The thread name used to identify the WebCore thread and for use in
     // debugging other classes that require operation within the WebCore thread.
     /* package */ static final String THREAD_NAME = "WebViewCoreThread";
@@ -1419,7 +1423,7 @@
             if (mViewportWidth == -1) {
                 if (mSettings.getLayoutAlgorithm() ==
                         WebSettings.LayoutAlgorithm.NORMAL) {
-                    width = WebView.ZOOM_OUT_WIDTH;
+                    width = DEFAULT_VIEWPORT_WIDTH;
                 } else {
                     /*
                      * if a page's minimum preferred width is wider than the
@@ -1433,7 +1437,8 @@
                      * In the worse case, the native width will be adjusted when
                      * next zoom or screen orientation change happens.
                      */
-                    width = Math.max(w, nativeGetContentMinPrefWidth());
+                    width = Math.max(w, Math.max(DEFAULT_VIEWPORT_WIDTH,
+                            nativeGetContentMinPrefWidth()));
                 }
             } else {
                 width = Math.max(w, mViewportWidth);
@@ -1530,7 +1535,8 @@
             // layout.
             draw.mViewPoint = new Point(mCurrentViewWidth, mCurrentViewHeight);
             if (WebView.ENABLE_DOUBLETAP_ZOOM && mSettings.getUseWideViewPort()) {
-                draw.mMinPrefWidth = nativeGetContentMinPrefWidth();
+                draw.mMinPrefWidth = Math.max(DEFAULT_VIEWPORT_WIDTH,
+                        nativeGetContentMinPrefWidth());
             }
             if (mRestoreState != null) {
                 draw.mRestoreState = mRestoreState;
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index ea88b5b..d821a7d 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -848,6 +848,16 @@
         return ListView.INVALID_POSITION;
     }
 
+
+    /**
+     * @hide
+     * @return {@link android.widget.ListView#getChildCount()} of the drop down if it is showing,
+     *         otherwise 0.
+     */
+    protected int getDropDownChildCount() {
+        return mDropDownList == null ? 0 : mDropDownList.getChildCount();
+    }
+
     /**
      * <p>Starts filtering the content of the drop down list. The filtering
      * pattern is the content of the edit box. Subclasses should override this
diff --git a/core/java/com/android/internal/widget/ContactHeaderWidget.java b/core/java/com/android/internal/widget/ContactHeaderWidget.java
index ccb537a..45bd0cf 100644
--- a/core/java/com/android/internal/widget/ContactHeaderWidget.java
+++ b/core/java/com/android/internal/widget/ContactHeaderWidget.java
@@ -21,9 +21,11 @@
 import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Context;
+import android.content.Intent;
 import android.database.Cursor;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
+import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Handler;
 import android.os.Message;
@@ -31,6 +33,7 @@
 import android.provider.SocialContract;
 import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.Intents;
 import android.provider.ContactsContract.PhoneLookup;
 import android.provider.ContactsContract.RawContacts;
 import android.provider.ContactsContract.CommonDataKinds.Photo;
@@ -123,12 +126,14 @@
 
         mDisplayNameView = (TextView) findViewById(R.id.name);
         mPhoneticNameView = (TextView) findViewById(R.id.phonetic_name);
-        mStarredView = (CheckBox) findViewById(R.id.star);
+
+        mStarredView = (CheckBox)findViewById(R.id.star);
         mStarredView.setOnClickListener(this);
-        // Don't show start by default.
-        mStarredView.setVisibility(View.GONE);
-        mPhotoView = (ImageView) findViewById(R.id.photo);
-        mStatusView = (TextView) findViewById(R.id.status);
+
+        mPhotoView = (ImageView)findViewById(R.id.photo);
+        mPhotoView.setOnClickListener(this);
+
+        mStatusView = (TextView)findViewById(R.id.status);
 
         // Set the photo with a random "no contact" image
         long now = SystemClock.elapsedRealtime();
@@ -310,13 +315,38 @@
     }
 
     public void onClick(View view) {
-        if (view.getId() == R.id.star) {
-            ContentValues values = new ContentValues(1);
-            values.put(Contacts.STARRED, mStarredView.isChecked());
-            mContentResolver.update(mContactUri, values, null, null);
+        switch (view.getId()) {
+            case R.id.star: {
+                // Toggle "starred" state
+                final ContentValues values = new ContentValues(1);
+                values.put(Contacts.STARRED, mStarredView.isChecked());
+                mContentResolver.update(mContactUri, values, null, null);
+                break;
+            }
+            case R.id.photo: {
+                // Photo launches contact detail action
+                final Intent intent = new Intent(Intents.SHOW_OR_CREATE_CONTACT, mContactUri);
+                final Rect target = getTargetRect(view);
+                intent.putExtra(Intents.EXTRA_TARGET_RECT, target);
+                intent.putExtra(Intents.EXTRA_MODE, Intents.MODE_SMALL);
+                mContext.startActivity(intent);
+                break;
+            }
         }
     }
 
+    private Rect getTargetRect(View anchor) {
+        final int[] location = new int[2];
+        anchor.getLocationOnScreen(location);
+
+        final Rect rect = new Rect();
+        rect.left = location[0];
+        rect.top = location[1];
+        rect.right = rect.left + anchor.getWidth();
+        rect.bottom = rect.top + anchor.getHeight();
+        return rect;
+    }
+
     private Bitmap loadContactPhoto(long photoId, BitmapFactory.Options options) {
         Cursor photoCursor = null;
         Bitmap photoBm = null;
diff --git a/core/jni/android_location_GpsLocationProvider.cpp b/core/jni/android_location_GpsLocationProvider.cpp
index bf0bd65..90a0487 100755
--- a/core/jni/android_location_GpsLocationProvider.cpp
+++ b/core/jni/android_location_GpsLocationProvider.cpp
@@ -32,6 +32,7 @@
 static jmethodID method_reportStatus;
 static jmethodID method_reportSvStatus;
 static jmethodID method_reportAGpsStatus;
+static jmethodID method_reportNmea;
 static jmethodID method_xtraDownloadRequest;
 
 static const GpsInterface* sGpsInterface = NULL;
@@ -44,12 +45,23 @@
 static GpsSvStatus  sGpsSvStatus;
 static AGpsStatus   sAGpsStatus;
 
+// buffer for NMEA data
+#define NMEA_SENTENCE_LENGTH    100
+#define NMEA_SENTENCE_COUNT     40
+struct NmeaSentence {
+    GpsUtcTime  timestamp;
+    char        nmea[NMEA_SENTENCE_LENGTH];
+};
+static NmeaSentence sNmeaBuffer[NMEA_SENTENCE_LENGTH];
+static int mNmeaSentenceCount = 0;
+
 // a copy of the data shared by android_location_GpsLocationProvider_wait_for_event
 // and android_location_GpsLocationProvider_read_status
 static GpsLocation  sGpsLocationCopy;
 static GpsStatus    sGpsStatusCopy;
 static GpsSvStatus  sGpsSvStatusCopy;
 static AGpsStatus   sAGpsStatusCopy;
+static NmeaSentence sNmeaBufferCopy[NMEA_SENTENCE_LENGTH];
 
 enum CallbackType {
     kLocation = 1,
@@ -58,6 +70,7 @@
     kAGpsStatus = 8,
     kXtraDownloadRequest = 16,
     kDisableRequest = 32,
+    kNmeaAvailable = 64,
 }; 
 static int sPendingCallbacks;
 
@@ -96,6 +109,30 @@
     pthread_mutex_unlock(&sEventMutex);
 }
 
+static void nmea_callback(GpsUtcTime timestamp, const char* nmea, int length)
+{
+    pthread_mutex_lock(&sEventMutex);
+
+    if (length >= NMEA_SENTENCE_LENGTH) {
+        LOGE("NMEA data too long in nmea_callback (length = %d)\n", length);
+        length = NMEA_SENTENCE_LENGTH - 1;
+    }
+    if (mNmeaSentenceCount >= NMEA_SENTENCE_COUNT) {
+        LOGE("NMEA data overflowed buffer\n");
+        pthread_mutex_unlock(&sEventMutex);
+        return;
+    }
+
+    sPendingCallbacks |= kNmeaAvailable;
+    sNmeaBuffer[mNmeaSentenceCount].timestamp = timestamp;
+    memcpy(sNmeaBuffer[mNmeaSentenceCount].nmea, nmea, length);
+    sNmeaBuffer[mNmeaSentenceCount].nmea[length] = 0;
+    mNmeaSentenceCount++;
+
+    pthread_cond_signal(&sEventCond);
+    pthread_mutex_unlock(&sEventMutex);
+}
+
 static void agps_status_callback(AGpsStatus* agps_status)
 {
     pthread_mutex_lock(&sEventMutex);
@@ -111,6 +148,7 @@
     location_callback,
     status_callback,
     sv_status_callback,
+    nmea_callback
 };
 
 static void
@@ -135,6 +173,7 @@
     method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V");
     method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "()V");
     method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(II)V");
+    method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(IJ)V");
     method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V");
 }
 
@@ -200,13 +239,21 @@
     // copy and clear the callback flags
     int pendingCallbacks = sPendingCallbacks;
     sPendingCallbacks = 0;
+    int nmeaSentenceCount = mNmeaSentenceCount;
+    mNmeaSentenceCount = 0;
     
     // copy everything and unlock the mutex before calling into Java code to avoid the possibility
     // of timeouts in the GPS engine.
-    memcpy(&sGpsLocationCopy, &sGpsLocation, sizeof(sGpsLocationCopy));
-    memcpy(&sGpsStatusCopy, &sGpsStatus, sizeof(sGpsStatusCopy));
-    memcpy(&sGpsSvStatusCopy, &sGpsSvStatus, sizeof(sGpsSvStatusCopy));
-    memcpy(&sAGpsStatusCopy, &sAGpsStatus, sizeof(sAGpsStatusCopy));
+    if (pendingCallbacks & kLocation)
+        memcpy(&sGpsLocationCopy, &sGpsLocation, sizeof(sGpsLocationCopy));
+    if (pendingCallbacks & kStatus)
+        memcpy(&sGpsStatusCopy, &sGpsStatus, sizeof(sGpsStatusCopy));
+    if (pendingCallbacks & kSvStatus)
+        memcpy(&sGpsSvStatusCopy, &sGpsSvStatus, sizeof(sGpsSvStatusCopy));
+    if (pendingCallbacks & kAGpsStatus)
+        memcpy(&sAGpsStatusCopy, &sAGpsStatus, sizeof(sAGpsStatusCopy));
+    if (pendingCallbacks & kNmeaAvailable)
+        memcpy(&sNmeaBufferCopy, &sNmeaBuffer, nmeaSentenceCount * sizeof(sNmeaBuffer[0]));
     pthread_mutex_unlock(&sEventMutex);   
 
     if (pendingCallbacks & kLocation) { 
@@ -225,6 +272,11 @@
     if (pendingCallbacks & kAGpsStatus) {
         env->CallVoidMethod(obj, method_reportAGpsStatus, sAGpsStatusCopy.type, sAGpsStatusCopy.status);
     }  
+    if (pendingCallbacks & kNmeaAvailable) {
+        for (int i = 0; i < nmeaSentenceCount; i++) {
+            env->CallVoidMethod(obj, method_reportNmea, i, sNmeaBuffer[i].timestamp);
+        }
+    }
     if (pendingCallbacks & kXtraDownloadRequest) {    
         env->CallVoidMethod(obj, method_xtraDownloadRequest);
     }
@@ -264,6 +316,21 @@
     return num_svs;
 }
 
+static jint android_location_GpsLocationProvider_read_nmea(JNIEnv* env, jobject obj, jint index, jbyteArray nmeaArray, jint buffer_size)
+{
+    // this should only be called from within a call to reportStatus, so we don't need to lock here
+
+    jbyte* nmea = env->GetByteArrayElements(nmeaArray, 0);
+
+    int length = strlen(sNmeaBuffer[index].nmea);
+    if (length > buffer_size)
+        length = buffer_size;
+    memcpy(nmea, sNmeaBuffer[index].nmea, length);
+
+    env->ReleaseByteArrayElements(nmeaArray, nmea, 0);
+    return length;
+}
+
 static void android_location_GpsLocationProvider_inject_time(JNIEnv* env, jobject obj, jlong time, 
         jlong timeReference, jint uncertainty)
 {
@@ -360,6 +427,7 @@
     {"native_delete_aiding_data", "(I)V", (void*)android_location_GpsLocationProvider_delete_aiding_data},
     {"native_wait_for_event", "()V", (void*)android_location_GpsLocationProvider_wait_for_event},
     {"native_read_sv_status", "([I[F[F[F[I)I", (void*)android_location_GpsLocationProvider_read_sv_status},
+    {"native_read_nmea", "(I[BI)I", (void*)android_location_GpsLocationProvider_read_nmea},
     {"native_inject_time", "(JJI)V", (void*)android_location_GpsLocationProvider_inject_time},
     {"native_inject_location", "(DDF)V", (void*)android_location_GpsLocationProvider_inject_location},
     {"native_supports_xtra", "()Z", (void*)android_location_GpsLocationProvider_supports_xtra},
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 09a0d70..723fd4b 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -251,10 +251,27 @@
     }
 
     while ((de = readdir(d))) {
+        int t_pid;
+        int t_pri;
+
         if (de->d_name[0] == '.')
             continue;
+        t_pid = atoi(de->d_name);
 
-        if (add_pid_to_cgroup(atoi(de->d_name), grp)) {
+        if (!t_pid) {
+            LOGE("Error getting pid for '%s'\n", de->d_name);
+            continue;
+        }
+
+        t_pri = getpriority(PRIO_PROCESS, t_pid);
+
+        if (grp == ANDROID_TGROUP_DEFAULT &&
+            t_pri >= ANDROID_PRIORITY_BACKGROUND) {
+            // This task wants to stay at background
+            continue;
+        }
+     
+        if (add_pid_to_cgroup(t_pid, grp)) {
             // If the thread exited on us, ignore it and keep going
             if (errno != ESRCH && errno != ENOENT) {
                 signalExceptionForGroupError(env, clazz, errno);
diff --git a/core/res/res/layout/contact_header.xml b/core/res/res/layout/contact_header.xml
index 04b34b8..06cd38c 100644
--- a/core/res/res/layout/contact_header.xml
+++ b/core/res/res/layout/contact_header.xml
@@ -48,9 +48,11 @@
                 
     </LinearLayout>
 
-    <CheckBox android:id="@+id/star"
-        style="?android:attr/starStyle"
+    <CheckBox
+        android:id="@+id/star"
         android:layout_width="wrap_content"
-        android:layout_height="wrap_content"/>
+        android:layout_height="wrap_content"
+        android:visibility="gone"
+        style="?android:attr/starStyle" />
 
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/core/res/res/raw/loaderror.html b/core/res/res/raw/loaderror.html
index 359a1e7..fd3d766 100644
--- a/core/res/res/raw/loaderror.html
+++ b/core/res/res/raw/loaderror.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>Web page not available</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/core/res/res/raw/nodomain.html b/core/res/res/raw/nodomain.html
index 7a107fb..a71dbcd 100644
--- a/core/res/res/raw/nodomain.html
+++ b/core/res/res/raw/nodomain.html
@@ -1,5 +1,6 @@
 <html>
     <head>
+        <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
         <title>Web page not available</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
diff --git a/include/ui/EGLUtils.h b/include/ui/EGLUtils.h
new file mode 100644
index 0000000..48777b6
--- /dev/null
+++ b/include/ui/EGLUtils.h
@@ -0,0 +1,51 @@
+/*
+ * 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_UI_EGLUTILS_H
+#define ANDROID_UI_EGLUTILS_H
+
+#include <utils/Errors.h>
+#include <ui/PixelFormat.h>
+#include <EGL/egl.h>
+
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+class EGLUtils
+{
+public:
+
+    static status_t selectConfigForPixelFormat(
+            EGLDisplay dpy,
+            EGLint const* attrs,
+            PixelFormat format,
+            EGLConfig* outConfig);
+
+    static status_t selectConfigForNativeWindow(
+            EGLDisplay dpy,
+            EGLint const* attrs,
+            EGLNativeWindowType window,
+            EGLConfig* outConfig);
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+#endif /* ANDROID_UI_EGLUTILS_H */
diff --git a/include/ui/EventHub.h b/include/ui/EventHub.h
index bffba07..3b18c77 100644
--- a/include/ui/EventHub.h
+++ b/include/ui/EventHub.h
@@ -119,7 +119,7 @@
         String8         keylayoutFilename;
         device_t*       next;
         
-        device_t(int32_t _id, const char* _path);
+        device_t(int32_t _id, const char* _path, const char* name);
         ~device_t();
     };
 
diff --git a/include/ui/egl/android_natives.h b/include/ui/egl/android_natives.h
index a3a1316..7da69b1 100644
--- a/include/ui/egl/android_natives.h
+++ b/include/ui/egl/android_natives.h
@@ -63,7 +63,8 @@
 /* attributes queriable with query() */
 enum {
     NATIVE_WINDOW_WIDTH     = 0,
-    NATIVE_WINDOW_HEIGHT    = 1
+    NATIVE_WINDOW_HEIGHT    = 1,
+    NATIVE_WINDOW_FORMAT    = 2,
 };
 
 struct android_native_window_t 
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index f0615f0b..002a3ab 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -26,6 +26,7 @@
 
 #include <ui/PixelFormat.h>
 #include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
 
 #include <GLES/gl.h>
 #include <EGL/egl.h>
@@ -144,32 +145,11 @@
     eglInitialize(display, NULL, NULL);
     eglGetConfigs(display, NULL, 0, &numConfigs);
 
-    // Get all the "potential match" configs...
-    EGLConfig* const configs = new EGLConfig[numConfigs];
-    eglChooseConfig(display, attribs, configs, numConfigs, &n);
-    LOGE_IF(n<=0, "no EGLConfig available!");
-    EGLConfig config = configs[0];
-    if (n > 1) {
-        // if there is more than one candidate, go through the list
-        // and pick one that matches our framebuffer format
-        int fbSzA = fbFormatInfo.getSize(PixelFormatInfo::INDEX_ALPHA);
-        int fbSzR = fbFormatInfo.getSize(PixelFormatInfo::INDEX_RED);
-        int fbSzG = fbFormatInfo.getSize(PixelFormatInfo::INDEX_GREEN);
-        int fbSzB = fbFormatInfo.getSize(PixelFormatInfo::INDEX_BLUE); 
-        for (int i=0 ; i<n ; i++) {
-            EGLint r,g,b,a;
-            eglGetConfigAttrib(display, configs[i], EGL_RED_SIZE,   &r);
-            eglGetConfigAttrib(display, configs[i], EGL_GREEN_SIZE, &g);
-            eglGetConfigAttrib(display, configs[i], EGL_BLUE_SIZE,  &b);
-            eglGetConfigAttrib(display, configs[i], EGL_ALPHA_SIZE, &a);
-            if (fbSzA == a && fbSzR == r && fbSzG == g && fbSzB  == b) {
-                config = configs[i];
-                break;
-            }
-        }
-    }
-    delete [] configs;
-
+    EGLConfig config;
+    status_t err = EGLUtils::selectConfigForPixelFormat(
+            display, attribs, fbDev->format, &config);
+    LOGE_IF(err, "couldn't find an EGLConfig matching the screen format");
+    
     /*
      * Gather EGL extensions
      */
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
index 49939ca..93c7263 100644
--- a/libs/ui/Android.mk
+++ b/libs/ui/Android.mk
@@ -5,6 +5,7 @@
 	BufferMapper.cpp \
 	Camera.cpp \
 	CameraParameters.cpp \
+	EGLUtils.cpp \
 	EventHub.cpp \
 	EventRecurrence.cpp \
 	FramebufferNativeWindow.cpp \
@@ -29,6 +30,7 @@
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
 	libutils \
+	libEGL \
 	libbinder \
 	libpixelflinger \
 	libhardware \
diff --git a/libs/ui/EGLUtils.cpp b/libs/ui/EGLUtils.cpp
new file mode 100644
index 0000000..80bfdfd
--- /dev/null
+++ b/libs/ui/EGLUtils.cpp
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+
+
+#define LOG_TAG "EGLUtils"
+
+#include <utils/Errors.h>
+
+#include <ui/EGLUtils.h>
+
+#include <EGL/egl.h>
+
+#include <private/ui/android_natives_priv.h>
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+status_t EGLUtils::selectConfigForPixelFormat(
+        EGLDisplay dpy,
+        EGLint const* attrs,
+        PixelFormat format,
+        EGLConfig* outConfig)
+{
+    EGLint numConfigs = -1, n=0;
+
+    if (outConfig == NULL)
+        return BAD_VALUE;
+    
+    int err;
+    PixelFormatInfo fbFormatInfo;
+    if ((err = getPixelFormatInfo(PixelFormat(format), &fbFormatInfo)) < 0) {
+        return err;
+    }
+
+    // Get all the "potential match" configs...
+    if (eglGetConfigs(dpy, NULL, 0, &numConfigs) == EGL_FALSE)
+        return BAD_VALUE;
+
+    EGLConfig* const configs = (EGLConfig*)malloc(sizeof(EGLConfig)*numConfigs);
+    if (eglChooseConfig(dpy, attrs, configs, numConfigs, &n) == EGL_FALSE) {
+        free(configs);
+        return BAD_VALUE;
+    }
+
+    const int fbSzA = fbFormatInfo.getSize(PixelFormatInfo::INDEX_ALPHA);
+    const int fbSzR = fbFormatInfo.getSize(PixelFormatInfo::INDEX_RED);
+    const int fbSzG = fbFormatInfo.getSize(PixelFormatInfo::INDEX_GREEN);
+    const int fbSzB = fbFormatInfo.getSize(PixelFormatInfo::INDEX_BLUE); 
+    
+    int i;
+    EGLConfig config = NULL;
+    for (i=0 ; i<n ; i++) {
+        EGLint r,g,b,a;
+        eglGetConfigAttrib(dpy, configs[i], EGL_RED_SIZE,   &r);
+        eglGetConfigAttrib(dpy, configs[i], EGL_GREEN_SIZE, &g);
+        eglGetConfigAttrib(dpy, configs[i], EGL_BLUE_SIZE,  &b);
+        eglGetConfigAttrib(dpy, configs[i], EGL_ALPHA_SIZE, &a);
+        if (fbSzA == a && fbSzR == r && fbSzG == g && fbSzB  == b) {
+            config = configs[i];
+            break;
+        }
+    }
+
+    free(configs);
+    
+    if (i<n) {
+        *outConfig = config;
+        return NO_ERROR;
+    }
+
+    return NAME_NOT_FOUND;
+}
+
+status_t EGLUtils::selectConfigForNativeWindow(
+        EGLDisplay dpy,
+        EGLint const* attrs,
+        EGLNativeWindowType window,
+        EGLConfig* outConfig)
+{
+    int err;
+    int format;
+    if ((err = window->query(window, NATIVE_WINDOW_FORMAT, &format)) < 0) {
+        return err;
+    }
+
+    return selectConfigForPixelFormat(dpy, attrs, format, outConfig);
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp
index 27334b7..df713cb 100644
--- a/libs/ui/EventHub.cpp
+++ b/libs/ui/EventHub.cpp
@@ -82,8 +82,8 @@
     return (v1 > v2) ? v1 : v2;
 }
 
-EventHub::device_t::device_t(int32_t _id, const char* _path)
-    : id(_id), path(_path), classes(0)
+EventHub::device_t::device_t(int32_t _id, const char* _path, const char* name)
+    : id(_id), path(_path), name(name), classes(0)
     , keyBitmask(NULL), layoutMap(new KeyLayoutMap()), next(NULL) {
 }
 
@@ -593,7 +593,7 @@
         version >> 16, (version >> 8) & 0xff, version & 0xff);
 #endif
 
-    device_t* device = new device_t(devid|mDevicesById[devid].seq, deviceName);
+    device_t* device = new device_t(devid|mDevicesById[devid].seq, deviceName, name);
     if (device == NULL) {
         LOGE("out of memory");
         return -1;
@@ -678,17 +678,14 @@
 #endif
 
     if ((device->classes&CLASS_KEYBOARD) != 0) {
-        char devname[101];
-        char tmpfn[101];
+        char tmpfn[sizeof(name)];
         char keylayoutFilename[300];
 
         // a more descriptive name
-        ioctl(mFDs[mFDCount].fd, EVIOCGNAME(sizeof(devname)-1), devname);
-        devname[sizeof(devname)-1] = 0;
-        device->name = devname;
+        device->name = name;
 
         // replace all the spaces with underscores
-        strcpy(tmpfn, devname);
+        strcpy(tmpfn, name);
         for (char *p = strchr(tmpfn, ' '); p && *p; p = strchr(tmpfn, ' '))
             *p = '_';
 
@@ -721,7 +718,7 @@
         }
         char propName[100];
         sprintf(propName, "hw.keyboards.%u.devname", publicID);
-        property_set(propName, devname);
+        property_set(propName, name);
 
         // 'Q' key support = cheap test of whether this is an alpha-capable kbd
         if (hasKeycode(device, kKeyCodeQ)) {
@@ -738,7 +735,7 @@
         }
         
         LOGI("New keyboard: publicID=%d device->id=0x%x devname='%s' propName='%s' keylayout='%s'\n",
-                publicID, device->id, devname, propName, keylayoutFilename);
+                publicID, device->id, name, propName, keylayoutFilename);
     }
 
     LOGI("New device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n",
diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp
index 8b7ea21..7b85c7f 100644
--- a/libs/ui/FramebufferNativeWindow.cpp
+++ b/libs/ui/FramebufferNativeWindow.cpp
@@ -212,6 +212,9 @@
         case NATIVE_WINDOW_HEIGHT:
             *value = fb->height;
             return NO_ERROR;
+        case NATIVE_WINDOW_FORMAT:
+            *value = fb->format;
+            return NO_ERROR;
     }
     return BAD_VALUE;
 }
diff --git a/libs/ui/Surface.cpp b/libs/ui/Surface.cpp
index c73909f..4abb7f6 100644
--- a/libs/ui/Surface.cpp
+++ b/libs/ui/Surface.cpp
@@ -620,6 +620,9 @@
         case NATIVE_WINDOW_HEIGHT:
             *value = int(mHeight);
             return NO_ERROR;
+        case NATIVE_WINDOW_FORMAT:
+            *value = int(mFormat);
+            return NO_ERROR;
     }
     return BAD_VALUE;
 }
diff --git a/location/java/android/location/GpsStatus.java b/location/java/android/location/GpsStatus.java
index 2cda7fa..ce69ac1 100644
--- a/location/java/android/location/GpsStatus.java
+++ b/location/java/android/location/GpsStatus.java
@@ -115,6 +115,18 @@
         void onGpsStatusChanged(int event);
     }
 
+    /**
+     * Used for receiving NMEA sentences from the GPS.
+     * NMEA 0183 is a standard for communicating with marine electronic devices
+     * and is a common method for receiving data from a GPS, typically over a serial port.
+     * See <a href="http://en.wikipedia.org/wiki/NMEA_0183">NMEA 0183</a> for more details.
+     * You can implement this interface and call {@link LocationManager#addNmeaListener}
+     * to receive NMEA data from the GPS engine.
+     */
+    public interface NmeaListener {
+        void onNmeaReceived(long timestamp, String nmea);
+    }
+
     GpsStatus() {
         for (int i = 0; i < mSatellites.length; i++) {
             mSatellites[i] = new GpsSatellite(i + 1);
diff --git a/location/java/android/location/IGpsStatusListener.aidl b/location/java/android/location/IGpsStatusListener.aidl
index 5dc0fe8..62b1c6b 100644
--- a/location/java/android/location/IGpsStatusListener.aidl
+++ b/location/java/android/location/IGpsStatusListener.aidl
@@ -29,4 +29,5 @@
     void onSvStatusChanged(int svCount, in int[] prns, in float[] snrs, 
             in float[] elevations, in float[] azimuths, 
             int ephemerisMask, int almanacMask, int usedInFixMask);
+    void onNmeaReceived(long timestamp, String nmea);
 }
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index ca16f19..8f0352d 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -51,6 +51,8 @@
     private ILocationManager mService;
     private final HashMap<GpsStatus.Listener, GpsStatusListenerTransport> mGpsStatusListeners =
             new HashMap<GpsStatus.Listener, GpsStatusListenerTransport>();
+    private final HashMap<GpsStatus.NmeaListener, GpsStatusListenerTransport> mNmeaListeners =
+            new HashMap<GpsStatus.NmeaListener, GpsStatusListenerTransport>();
     private final GpsStatus mGpsStatus = new GpsStatus();
 
     /**
@@ -1123,49 +1125,103 @@
     private class GpsStatusListenerTransport extends IGpsStatusListener.Stub {
 
         private final GpsStatus.Listener mListener;
+        private final GpsStatus.NmeaListener mNmeaListener;
+
+        // This must not equal any of the GpsStatus event IDs
+        private static final int NMEA_RECEIVED = 1000;
+
+        private class Nmea {
+            long mTimestamp;
+            String mNmea;
+
+            Nmea(long timestamp, String nmea) {
+                mTimestamp = timestamp;
+                mNmea = nmea;
+            }
+        }
+        private ArrayList<Nmea> mNmeaBuffer;
 
         GpsStatusListenerTransport(GpsStatus.Listener listener) {
             mListener = listener;
+            mNmeaListener = null;
+        }
+
+        GpsStatusListenerTransport(GpsStatus.NmeaListener listener) {
+            mNmeaListener = listener;
+            mListener = null;
+            mNmeaBuffer = new ArrayList<Nmea>();
         }
 
         public void onGpsStarted() {
-            Message msg = Message.obtain();
-            msg.what = GpsStatus.GPS_EVENT_STARTED;
-            mGpsHandler.sendMessage(msg);
+            if (mListener != null) {
+                Message msg = Message.obtain();
+                msg.what = GpsStatus.GPS_EVENT_STARTED;
+                mGpsHandler.sendMessage(msg);
+            }
         }
 
         public void onGpsStopped() {
-            Message msg = Message.obtain();
-            msg.what = GpsStatus.GPS_EVENT_STOPPED;
-            mGpsHandler.sendMessage(msg);
+            if (mListener != null) {
+                Message msg = Message.obtain();
+                msg.what = GpsStatus.GPS_EVENT_STOPPED;
+                mGpsHandler.sendMessage(msg);
+            }
         }
 
         public void onFirstFix(int ttff) {
-            mGpsStatus.setTimeToFirstFix(ttff);
-            Message msg = Message.obtain();
-            msg.what = GpsStatus.GPS_EVENT_FIRST_FIX;
-            mGpsHandler.sendMessage(msg);
+            if (mListener != null) {
+                mGpsStatus.setTimeToFirstFix(ttff);
+                Message msg = Message.obtain();
+                msg.what = GpsStatus.GPS_EVENT_FIRST_FIX;
+                mGpsHandler.sendMessage(msg);
+            }
         }
 
         public void onSvStatusChanged(int svCount, int[] prns, float[] snrs,
                 float[] elevations, float[] azimuths, int ephemerisMask,
                 int almanacMask, int usedInFixMask) {
-            mGpsStatus.setStatus(svCount, prns, snrs, elevations, azimuths,
-                    ephemerisMask, almanacMask, usedInFixMask);
+            if (mListener != null) {
+                mGpsStatus.setStatus(svCount, prns, snrs, elevations, azimuths,
+                        ephemerisMask, almanacMask, usedInFixMask);
 
-            Message msg = Message.obtain();
-            msg.what = GpsStatus.GPS_EVENT_SATELLITE_STATUS;
-            // remove any SV status messages already in the queue
-            mGpsHandler.removeMessages(GpsStatus.GPS_EVENT_SATELLITE_STATUS);
-            mGpsHandler.sendMessage(msg);
+                Message msg = Message.obtain();
+                msg.what = GpsStatus.GPS_EVENT_SATELLITE_STATUS;
+                // remove any SV status messages already in the queue
+                mGpsHandler.removeMessages(GpsStatus.GPS_EVENT_SATELLITE_STATUS);
+                mGpsHandler.sendMessage(msg);
+            }
+        }
+
+        public void onNmeaReceived(long timestamp, String nmea) {
+            if (mNmeaListener != null) {
+                synchronized (mNmeaBuffer) {
+                    mNmeaBuffer.add(new Nmea(timestamp, nmea));
+                }
+                Message msg = Message.obtain();
+                msg.what = NMEA_RECEIVED;
+                // remove any NMEA_RECEIVED messages already in the queue
+                mGpsHandler.removeMessages(NMEA_RECEIVED);
+                mGpsHandler.sendMessage(msg);
+            }
         }
 
         private final Handler mGpsHandler = new Handler() {
             @Override
             public void handleMessage(Message msg) {
-                // synchronize on mGpsStatus to ensure the data is copied atomically.
-                synchronized(mGpsStatus) {
-                    mListener.onGpsStatusChanged(msg.what);
+                if (msg.what == NMEA_RECEIVED) {
+                    synchronized (mNmeaBuffer) {
+                        int length = mNmeaBuffer.size();
+                        for (int i = 0; i < length; i++) {
+                            Nmea nmea = mNmeaBuffer.get(i);
+                            mNmeaListener.onNmeaReceived(nmea.mTimestamp, nmea.mNmea);
+                        }
+                        mNmeaBuffer.clear();
+                    }
+                } else {
+                    // synchronize on mGpsStatus to ensure the data is copied atomically.
+                    synchronized(mGpsStatus) {
+                        mListener.onGpsStatusChanged(msg.what);
+                    }
                 }
             }
         };
@@ -1217,6 +1273,52 @@
         }
     }
 
+    /**
+     * Adds an NMEA listener.
+     *
+     * @param listener a {#link GpsStatus.NmeaListener} object to register
+     *
+     * @return true if the listener was successfully added
+     *
+     * @throws SecurityException if the ACCESS_FINE_LOCATION permission is not present
+     */
+    public boolean addNmeaListener(GpsStatus.NmeaListener listener) {
+        boolean result;
+
+        if (mNmeaListeners.get(listener) != null) {
+            // listener is already registered
+            return true;
+        }
+        try {
+            GpsStatusListenerTransport transport = new GpsStatusListenerTransport(listener);
+            result = mService.addGpsStatusListener(transport);
+            if (result) {
+                mNmeaListeners.put(listener, transport);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in registerGpsStatusListener: ", e);
+            result = false;
+        }
+
+        return result;
+    }
+
+    /**
+     * Removes an NMEA listener.
+     *
+     * @param listener a {#link GpsStatus.NmeaListener} object to remove
+     */
+    public void removeNmeaListener(GpsStatus.NmeaListener listener) {
+        try {
+            GpsStatusListenerTransport transport = mNmeaListeners.remove(listener);
+            if (transport != null) {
+                mService.removeGpsStatusListener(transport);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException in unregisterGpsStatusListener: ", e);
+        }
+    }
+
      /**
      * Retrieves information about the current status of the GPS engine.
      * This should only be called from the {@link GpsStatus.Listener#onGpsStatusChanged}
diff --git a/location/java/com/android/internal/location/GpsLocationProvider.java b/location/java/com/android/internal/location/GpsLocationProvider.java
index aaac192..bdef01f 100755
--- a/location/java/com/android/internal/location/GpsLocationProvider.java
+++ b/location/java/com/android/internal/location/GpsLocationProvider.java
@@ -1014,6 +1014,32 @@
         }
     }
 
+    /**
+     * called from native code to report NMEA data received
+     */
+    private void reportNmea(int index, long timestamp) {
+        synchronized(mListeners) {
+            int size = mListeners.size();
+            if (size > 0) {
+                // don't bother creating the String if we have no listeners
+                int length = native_read_nmea(index, mNmeaBuffer, mNmeaBuffer.length);
+                String nmea = new String(mNmeaBuffer, 0, length);
+
+                for (int i = 0; i < size; i++) {
+                    Listener listener = mListeners.get(i);
+                    try {
+                        listener.mListener.onNmeaReceived(timestamp, nmea);
+                    } catch (RemoteException e) {
+                        Log.w(TAG, "RemoteException in reportNmea");
+                        mListeners.remove(listener);
+                        // adjust for size of list changing
+                        size--;
+                    }
+                }
+            }
+        }
+    }
+
     private void xtraDownloadRequest() {
         if (Config.LOGD) Log.d(TAG, "xtraDownloadRequest");
         if (mNetworkThread != null) {
@@ -1194,6 +1220,8 @@
     private float mSvAzimuths[] = new float[MAX_SVS];
     private int mSvMasks[] = new int[3];
     private int mSvCount;
+    // preallocated to avoid memory allocation in reportNmea()
+    private byte[] mNmeaBuffer = new byte[120];
 
     static { class_init_native(); }
     private static native void class_init_native();
@@ -1211,6 +1239,7 @@
     // mask[0] is ephemeris mask and mask[1] is almanac mask
     private native int native_read_sv_status(int[] svs, float[] snrs,
             float[] elevations, float[] azimuths, int[] masks);
+    private native int native_read_nmea(int index, byte[] buffer, int bufferSize);
     private native void native_inject_location(double latitude, double longitude, float accuracy);
 
     // XTRA Support    
diff --git a/media/libstagefright/OMXDecoder.cpp b/media/libstagefright/OMXDecoder.cpp
index 3ea3d01..c570278 100644
--- a/media/libstagefright/OMXDecoder.cpp
+++ b/media/libstagefright/OMXDecoder.cpp
@@ -157,9 +157,6 @@
     if (!strncmp(codec, "OMX.qcom.video.", 15)) {
         quirks |= kRequiresLoadedToIdleAfterAllocation;
     }
-    if (!strcmp(codec, "OMX.TI.MP3.decode")) {
-        quirks |= kMeasuresTimeInMilliseconds;
-    }
 
     OMXDecoder *decoder = new OMXDecoder(
             client, node, mime, codec, createEncoder, quirks);
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
index d8867d3..01c0920 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
@@ -310,7 +310,8 @@
     public boolean validateMemoryResult (int startPid, int startMemory, Writer output) throws Exception {
         mEndPid = getMediaserverPid();
         mEndMemory = getMediaserverVsize();
-
+        Log.v(TAG, "End Memory " + mEndMemory);
+        output.write("End Memory :" + mEndMemory + "\n");
         //Write the total memory different into the output file
         output.write("The total diff = " + (mEndMemory - startMemory));
         output.write("\n\n");
@@ -337,13 +338,17 @@
     public void testH263VideoPlaybackMemoryUsage() throws Exception {
         boolean memoryResult = false;
         mStartPid = getMediaserverPid();
-        mStartMemory = getMediaserverVsize();
 
         File h263MemoryOut = new File(MEDIA_MEMORY_OUTPUT);
         Writer output = new BufferedWriter(new FileWriter(h263MemoryOut, true));
         output.write("H263 Video Playback Only\n");
         for (int i = 0; i < NUM_STRESS_LOOP; i++) {
             mediaStressPlayback(MediaNames.VIDEO_HIGHRES_H263);
+            if (i == 0) {
+                mStartMemory = getMediaserverVsize();
+                output.write("Start memory : " + mStartMemory + "\n");
+                Log.v(TAG, "first mem : " + mStartMemory);
+            }
             getMemoryWriteToLog(output);
         }
         output.write("\n");
@@ -357,13 +362,16 @@
     public void testH264VideoPlaybackMemoryUsage() throws Exception {
         boolean memoryResult = false;
         mStartPid = getMediaserverPid();
-        mStartMemory = getMediaserverVsize();
 
         File h264MemoryOut = new File(MEDIA_MEMORY_OUTPUT);
         Writer output = new BufferedWriter(new FileWriter(h264MemoryOut, true));
         output.write("H264 Video Playback only\n");
         for (int i = 0; i < NUM_STRESS_LOOP; i++) {
             mediaStressPlayback(MediaNames.VIDEO_H264_AMR);
+            if (i == 0) {
+              mStartMemory = getMediaserverVsize();
+              output.write("Start memory : " + mStartMemory + "\n");
+            }
             getMemoryWriteToLog(output);
         }
         output.write("\n");
@@ -377,13 +385,16 @@
     public void testWMVVideoPlaybackMemoryUsage() throws Exception {
         boolean memoryResult = false;
         mStartPid = getMediaserverPid();
-        mStartMemory = getMediaserverVsize();
 
         File wmvMemoryOut = new File(MEDIA_MEMORY_OUTPUT);
         Writer output = new BufferedWriter(new FileWriter(wmvMemoryOut, true));
         output.write("WMV video playback only\n");
         for (int i = 0; i < NUM_STRESS_LOOP; i++) {
             mediaStressPlayback(MediaNames.VIDEO_WMV);
+            if (i == 0) {
+              mStartMemory = getMediaserverVsize();
+              output.write("Start memory : " + mStartMemory + "\n");
+            }
             getMemoryWriteToLog(output);
         }
         output.write("\n");
@@ -397,7 +408,6 @@
     public void testH263RecordVideoOnlyMemoryUsage() throws Exception {
         boolean memoryResult = false;
         mStartPid = getMediaserverPid();
-        mStartMemory = getMediaserverVsize();
 
         File videoH263RecordOnlyMemoryOut = new File(MEDIA_MEMORY_OUTPUT);
         Writer output = new BufferedWriter(new FileWriter(videoH263RecordOnlyMemoryOut, true));
@@ -405,6 +415,10 @@
         for (int i = 0; i < NUM_STRESS_LOOP; i++) {
             stressVideoRecord(20, 352, 288, MediaRecorder.VideoEncoder.H263,
                     MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_VIDEO_3GP, true);
+            if (i == 0) {
+              mStartMemory = getMediaserverVsize();
+              output.write("Start memory : " + mStartMemory + "\n");
+            }
             getMemoryWriteToLog(output);
         }
         output.write("\n");
@@ -418,7 +432,6 @@
     public void testMpeg4RecordVideoOnlyMemoryUsage() throws Exception {
         boolean memoryResult = false;
         mStartPid = getMediaserverPid();
-        mStartMemory = getMediaserverVsize();
 
         File videoMp4RecordOnlyMemoryOut = new File(MEDIA_MEMORY_OUTPUT);
         Writer output = new BufferedWriter(new FileWriter(videoMp4RecordOnlyMemoryOut, true));
@@ -426,6 +439,10 @@
         for (int i = 0; i < NUM_STRESS_LOOP; i++) {
             stressVideoRecord(20, 352, 288, MediaRecorder.VideoEncoder.MPEG_4_SP,
                     MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_VIDEO_3GP, true);
+            if (i == 0) {
+              mStartMemory = getMediaserverVsize();
+              output.write("Start memory : " + mStartMemory + "\n");
+            }
             getMemoryWriteToLog(output);
         }
         output.write("\n");
@@ -440,7 +457,6 @@
     public void testRecordVidedAudioMemoryUsage() throws Exception {
         boolean memoryResult = false;
         mStartPid = getMediaserverPid();
-        mStartMemory = getMediaserverVsize();
 
         File videoRecordAudioMemoryOut = new File(MEDIA_MEMORY_OUTPUT);
         Writer output = new BufferedWriter(new FileWriter(videoRecordAudioMemoryOut, true));
@@ -448,6 +464,10 @@
         for (int i = 0; i < NUM_STRESS_LOOP; i++) {
             stressVideoRecord(20, 352, 288, MediaRecorder.VideoEncoder.H263,
                     MediaRecorder.OutputFormat.MPEG_4, MediaNames.RECORDED_VIDEO_3GP, false);
+            if (i == 0) {
+              mStartMemory = getMediaserverVsize();
+              output.write("Start memory : " + mStartMemory + "\n");
+            }
             getMemoryWriteToLog(output);
         }
         output.write("\n");
@@ -461,13 +481,16 @@
     public void testRecordAudioOnlyMemoryUsage() throws Exception {
         boolean memoryResult = false;
         mStartPid = getMediaserverPid();
-        mStartMemory = getMediaserverVsize();
 
         File audioOnlyMemoryOut = new File(MEDIA_MEMORY_OUTPUT);
         Writer output = new BufferedWriter(new FileWriter(audioOnlyMemoryOut, true));
         output.write("Audio record only\n");
         for (int i = 0; i < NUM_STRESS_LOOP; i++) {
             stressAudioRecord(MediaNames.RECORDER_OUTPUT);
+            if (i == 0) {
+              mStartMemory = getMediaserverVsize();
+              output.write("Start memory : " + mStartMemory + "\n");
+            }
             getMemoryWriteToLog(output);
         }
         output.write("\n");
diff --git a/opengl/tests/angeles/Android.mk b/opengl/tests/angeles/Android.mk
index e193483..d0c3221 100644
--- a/opengl/tests/angeles/Android.mk
+++ b/opengl/tests/angeles/Android.mk
@@ -2,7 +2,7 @@
 
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= app-linux.c demo.c.arm
+LOCAL_SRC_FILES:= app-linux.cpp demo.c.arm
 LOCAL_SHARED_LIBRARIES := libEGL libGLESv1_CM libui
 LOCAL_MODULE:= angeles
 LOCAL_MODULE_TAGS := optional
diff --git a/opengl/tests/angeles/app-linux.c b/opengl/tests/angeles/app-linux.cpp
similarity index 74%
rename from opengl/tests/angeles/app-linux.c
rename to opengl/tests/angeles/app-linux.cpp
index 6be4876..9c71693 100644
--- a/opengl/tests/angeles/app-linux.c
+++ b/opengl/tests/angeles/app-linux.cpp
@@ -52,6 +52,11 @@
 #include <EGL/egl.h>
 #include <GLES/gl.h>
 
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
+
+using namespace android;
+
 #include "app.h"
 
 
@@ -115,76 +120,32 @@
 
 static int initGraphics()
 {
-    EGLint s_configAttribs[] = {
-         EGL_RED_SIZE,       5,
-         EGL_GREEN_SIZE,     6,
-         EGL_BLUE_SIZE,      5,
- #if 1
-         EGL_DEPTH_SIZE,     16,
-         EGL_STENCIL_SIZE,   0,
- #else
-         EGL_ALPHA_SIZE,     EGL_DONT_CARE,
-         EGL_DEPTH_SIZE,     EGL_DONT_CARE,
-         EGL_STENCIL_SIZE,   EGL_DONT_CARE,
-         EGL_SURFACE_TYPE,   EGL_DONT_CARE,
- #endif
+    EGLint configAttribs[] = {
+         EGL_DEPTH_SIZE, 16,
          EGL_NONE
      };
      
-     EGLint numConfigs = -1;
-     EGLint n = 0;
      EGLint majorVersion;
      EGLint minorVersion;
-     EGLConfig config;
      EGLContext context;
+     EGLConfig config;
      EGLSurface surface;
-     
+     EGLint w, h;
      EGLDisplay dpy;
 
      dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-     egl_error("eglGetDisplay");
-     fprintf(stderr,"dpy = 0x%08x\n", (unsigned) dpy);
-     
      eglInitialize(dpy, &majorVersion, &minorVersion);
-     egl_error("eglInitialize");
-
-     eglGetConfigs(dpy, NULL, 0, &numConfigs);
-
-     // Get all the "potential match" configs...
-     EGLConfig* const configs = malloc(sizeof(EGLConfig)*numConfigs);
-     eglChooseConfig(dpy, s_configAttribs, configs, numConfigs, &n);
-     config = configs[0];
-     if (n > 1) {
-         // if there is more than one candidate, go through the list
-         // and pick one that matches our framebuffer format
-         int fbSzA = 0; // should not hardcode
-         int fbSzR = 5; // should not hardcode
-         int fbSzG = 6; // should not hardcode
-         int fbSzB = 5; // should not hardcode
-         int i;
-         for (i=0 ; i<n ; i++) {
-             EGLint r,g,b,a;
-             eglGetConfigAttrib(dpy, configs[i], EGL_RED_SIZE,   &r);
-             eglGetConfigAttrib(dpy, configs[i], EGL_GREEN_SIZE, &g);
-             eglGetConfigAttrib(dpy, configs[i], EGL_BLUE_SIZE,  &b);
-             eglGetConfigAttrib(dpy, configs[i], EGL_ALPHA_SIZE, &a);
-             if (fbSzA == a && fbSzR == r && fbSzG == g && fbSzB  == b) {
-                 config = configs[i];
-                 break;
-             }
-         }
+          
+     EGLNativeWindowType window = android_createDisplaySurface();
+     
+     status_t err = EGLUtils::selectConfigForNativeWindow(
+             dpy, configAttribs, window, &config);
+     if (err) {
+         fprintf(stderr, "couldn't find an EGLConfig matching the screen format\n");
+         return 0;
      }
-     free(configs);
-     
-     
-     //eglGetConfigs(dpy, NULL, 0, &numConfigs);
-     //egl_error("eglGetConfigs");
-     //fprintf(stderr,"num configs %d\n", numConfigs);     
-     //eglChooseConfig(dpy, s_configAttribs, &config, 1, &numConfigs);
-     //egl_error("eglChooseConfig");
 
-     surface = eglCreateWindowSurface(dpy, config,
-             android_createDisplaySurface(), NULL);
+     surface = eglCreateWindowSurface(dpy, config, window, NULL);
      egl_error("eglCreateWindowSurface");
 
      fprintf(stderr,"surface = %p\n", surface);
diff --git a/opengl/tests/fillrate/fillrate.cpp b/opengl/tests/fillrate/fillrate.cpp
index 108a87c..4ffbc8b 100644
--- a/opengl/tests/fillrate/fillrate.cpp
+++ b/opengl/tests/fillrate/fillrate.cpp
@@ -26,6 +26,7 @@
 
 #include <utils/StopWatch.h>
 #include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
 
 using namespace android;
 
@@ -36,48 +37,27 @@
          EGL_NONE
      };
      
-     EGLint numConfigs = -1, n=0;
      EGLint majorVersion;
      EGLint minorVersion;
-     EGLConfig config;
      EGLContext context;
+     EGLConfig config;
      EGLSurface surface;
      EGLint w, h;
-     
      EGLDisplay dpy;
 
      dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
      eglInitialize(dpy, &majorVersion, &minorVersion);
+          
+     EGLNativeWindowType window = android_createDisplaySurface();
      
-     // Get all the "potential match" configs...
-     eglGetConfigs(dpy, NULL, 0, &numConfigs);
-     EGLConfig* const configs = (EGLConfig*)malloc(sizeof(EGLConfig)*numConfigs);
-     eglChooseConfig(dpy, configAttribs, configs, numConfigs, &n);
-     config = configs[0];
-     if (n > 1) {
-         // if there is more than one candidate, go through the list
-         // and pick one that matches our framebuffer format
-         int fbSzA = 0; // should not hardcode
-         int fbSzR = 5; // should not hardcode
-         int fbSzG = 6; // should not hardcode
-         int fbSzB = 5; // should not hardcode
-         int i;
-         for (i=0 ; i<n ; i++) {
-             EGLint r,g,b,a;
-             eglGetConfigAttrib(dpy, configs[i], EGL_RED_SIZE,   &r);
-             eglGetConfigAttrib(dpy, configs[i], EGL_GREEN_SIZE, &g);
-             eglGetConfigAttrib(dpy, configs[i], EGL_BLUE_SIZE,  &b);
-             eglGetConfigAttrib(dpy, configs[i], EGL_ALPHA_SIZE, &a);
-             if (fbSzA == a && fbSzR == r && fbSzG == g && fbSzB  == b) {
-                 config = configs[i];
-                 break;
-             }
-         }
+     status_t err = EGLUtils::selectConfigForNativeWindow(
+             dpy, configAttribs, window, &config);
+     if (err) {
+         fprintf(stderr, "couldn't find an EGLConfig matching the screen format\n");
+         return 0;
      }
-     free(configs);
-     
-     surface = eglCreateWindowSurface(dpy, config,
-             android_createDisplaySurface(), NULL);
+
+     surface = eglCreateWindowSurface(dpy, config, window, NULL);
      context = eglCreateContext(dpy, config, NULL, NULL);
      eglMakeCurrent(dpy, surface, surface, context);   
      eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
diff --git a/opengl/tests/filter/Android.mk b/opengl/tests/filter/Android.mk
index 31b7d9a..a254127 100644
--- a/opengl/tests/filter/Android.mk
+++ b/opengl/tests/filter/Android.mk
@@ -2,7 +2,7 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
-	filter.c
+	filter.cpp
 
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
@@ -14,4 +14,6 @@
 
 LOCAL_MODULE_TAGS := optional
 
+LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES
+
 include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/filter/filter.c b/opengl/tests/filter/filter.cpp
similarity index 90%
rename from opengl/tests/filter/filter.c
rename to opengl/tests/filter/filter.cpp
index de97119..e82b12d 100644
--- a/opengl/tests/filter/filter.c
+++ b/opengl/tests/filter/filter.cpp
@@ -5,6 +5,11 @@
 #include <GLES/gl.h>
 #include <GLES/glext.h>
 
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
+
+using namespace android;
+
 int main(int argc, char** argv)
 {
     if (argc!=2 && argc!=3) {
@@ -34,12 +39,14 @@
 
      dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
      eglInitialize(dpy, &majorVersion, &minorVersion);
-     eglChooseConfig(dpy, s_configAttribs, &config, 1, &numConfigs);
      if (!usePbuffer) {
-         surface = eglCreateWindowSurface(dpy, config,
-                 android_createDisplaySurface(), NULL);
+         EGLNativeWindowType window = android_createDisplaySurface();
+         surface = eglCreateWindowSurface(dpy, config, window, NULL);
+         EGLUtils::selectConfigForNativeWindow(
+                 dpy, s_configAttribs, window, &config);
      } else {
          printf("using pbuffer\n");
+         eglChooseConfig(dpy, s_configAttribs, &config, 1, &numConfigs);
          EGLint attribs[] = { EGL_WIDTH, 320, EGL_HEIGHT, 480, EGL_NONE };
          surface = eglCreatePbufferSurface(dpy, config, attribs);
          if (surface == EGL_NO_SURFACE) {
diff --git a/opengl/tests/finish/Android.mk b/opengl/tests/finish/Android.mk
index 8b46cd7..5620814 100644
--- a/opengl/tests/finish/Android.mk
+++ b/opengl/tests/finish/Android.mk
@@ -2,7 +2,7 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
-	finish.c
+	finish.cpp
 
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
@@ -14,4 +14,6 @@
 
 LOCAL_MODULE_TAGS := optional
 
+LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES
+
 include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/finish/finish.c b/opengl/tests/finish/finish.cpp
similarity index 90%
rename from opengl/tests/finish/finish.c
rename to opengl/tests/finish/finish.cpp
index 45fc758..b5b8142 100644
--- a/opengl/tests/finish/finish.c
+++ b/opengl/tests/finish/finish.cpp
@@ -24,39 +24,41 @@
 #include <GLES/gl.h>
 #include <GLES/glext.h>
 
+#include <utils/Timers.h>
 
-long long systemTime()
-{
-    struct timespec t;
-    t.tv_sec = t.tv_nsec = 0;
-    clock_gettime(CLOCK_MONOTONIC, &t);
-    return (long long)(t.tv_sec)*1000000000LL + t.tv_nsec;
-}
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
+
+using namespace android;
 
 int main(int argc, char** argv)
 {
-    EGLint s_configAttribs[] = {
-         EGL_RED_SIZE,       5,
-         EGL_GREEN_SIZE,     6,
-         EGL_BLUE_SIZE,      5,
+    EGLint configAttribs[] = {
+         EGL_DEPTH_SIZE, 0,
          EGL_NONE
      };
      
-     EGLint numConfigs = -1;
      EGLint majorVersion;
      EGLint minorVersion;
-     EGLConfig config;
      EGLContext context;
+     EGLConfig config;
      EGLSurface surface;
      EGLint w, h;
-     
      EGLDisplay dpy;
 
      dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
      eglInitialize(dpy, &majorVersion, &minorVersion);
-     eglChooseConfig(dpy, s_configAttribs, &config, 1, &numConfigs);
-     surface = eglCreateWindowSurface(dpy, config, 
-             android_createDisplaySurface(), NULL);
+          
+     EGLNativeWindowType window = android_createDisplaySurface();
+     
+     status_t err = EGLUtils::selectConfigForNativeWindow(
+             dpy, configAttribs, window, &config);
+     if (err) {
+         fprintf(stderr, "couldn't find an EGLConfig matching the screen format\n");
+         return 0;
+     }
+
+     surface = eglCreateWindowSurface(dpy, config, window, NULL);
      context = eglCreateContext(dpy, config, NULL, NULL);
      eglMakeCurrent(dpy, surface, surface, context);   
      eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
@@ -75,13 +77,13 @@
      long long now, t;
      int i;
 
-     char* texels = malloc(512*512*2);
+     char* texels = (char*)malloc(512*512*2);
      memset(texels,0xFF,512*512*2);
      
      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
              512, 512, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, texels);
 
-     char* dst = malloc(320*480*2);
+     char* dst = (char*)malloc(320*480*2);
      memset(dst, 0, 320*480*2);
      printf("307200 bytes memcpy\n");
      for (i=0 ; i<4 ; i++) {
diff --git a/opengl/tests/swapinterval/swapinterval.cpp b/opengl/tests/swapinterval/swapinterval.cpp
index f51d882..cf908a0 100644
--- a/opengl/tests/swapinterval/swapinterval.cpp
+++ b/opengl/tests/swapinterval/swapinterval.cpp
@@ -26,6 +26,7 @@
 
 #include <utils/StopWatch.h>
 #include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
 
 using namespace android;
 
@@ -36,48 +37,27 @@
          EGL_NONE
      };
      
-     EGLint numConfigs = -1, n=0;
      EGLint majorVersion;
      EGLint minorVersion;
-     EGLConfig config;
      EGLContext context;
+     EGLConfig config;
      EGLSurface surface;
      EGLint w, h;
-     
      EGLDisplay dpy;
 
      dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
      eglInitialize(dpy, &majorVersion, &minorVersion);
+          
+     EGLNativeWindowType window = android_createDisplaySurface();
      
-     // Get all the "potential match" configs...
-     eglGetConfigs(dpy, NULL, 0, &numConfigs);
-     EGLConfig* const configs = (EGLConfig*)malloc(sizeof(EGLConfig)*numConfigs);
-     eglChooseConfig(dpy, configAttribs, configs, numConfigs, &n);
-     config = configs[0];
-     if (n > 1) {
-         // if there is more than one candidate, go through the list
-         // and pick one that matches our framebuffer format
-         int fbSzA = 0; // should not hardcode
-         int fbSzR = 5; // should not hardcode
-         int fbSzG = 6; // should not hardcode
-         int fbSzB = 5; // should not hardcode
-         int i;
-         for (i=0 ; i<n ; i++) {
-             EGLint r,g,b,a;
-             eglGetConfigAttrib(dpy, configs[i], EGL_RED_SIZE,   &r);
-             eglGetConfigAttrib(dpy, configs[i], EGL_GREEN_SIZE, &g);
-             eglGetConfigAttrib(dpy, configs[i], EGL_BLUE_SIZE,  &b);
-             eglGetConfigAttrib(dpy, configs[i], EGL_ALPHA_SIZE, &a);
-             if (fbSzA == a && fbSzR == r && fbSzG == g && fbSzB  == b) {
-                 config = configs[i];
-                 break;
-             }
-         }
+     status_t err = EGLUtils::selectConfigForNativeWindow(
+             dpy, configAttribs, window, &config);
+     if (err) {
+         fprintf(stderr, "couldn't find an EGLConfig matching the screen format\n");
+         return 0;
      }
-     free(configs);
-     
-     surface = eglCreateWindowSurface(dpy, config,
-             android_createDisplaySurface(), NULL);
+
+     surface = eglCreateWindowSurface(dpy, config, window, NULL);
      context = eglCreateContext(dpy, config, NULL, NULL);
      eglMakeCurrent(dpy, surface, surface, context);   
      eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
diff --git a/opengl/tests/textures/Android.mk b/opengl/tests/textures/Android.mk
index 8d5f56d..b2fa185 100644
--- a/opengl/tests/textures/Android.mk
+++ b/opengl/tests/textures/Android.mk
@@ -2,7 +2,7 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
-	textures.c
+	textures.cpp
 
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
@@ -14,4 +14,6 @@
 
 LOCAL_MODULE_TAGS := optional
 
+LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES
+
 include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/textures/textures.c b/opengl/tests/textures/textures.cpp
similarity index 70%
rename from opengl/tests/textures/textures.c
rename to opengl/tests/textures/textures.cpp
index d877e74..ee92e79 100644
--- a/opengl/tests/textures/textures.c
+++ b/opengl/tests/textures/textures.cpp
@@ -22,59 +22,39 @@
 #include <GLES/gl.h>
 #include <GLES/glext.h>
 
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
+
+using namespace android;
+
 int main(int argc, char** argv)
 {
-    EGLint s_configAttribs[] = {
-         EGL_RED_SIZE,       5,
-         EGL_GREEN_SIZE,     6,
-         EGL_BLUE_SIZE,      5,
+    EGLint configAttribs[] = {
+         EGL_DEPTH_SIZE, 0,
          EGL_NONE
      };
      
-     EGLint numConfigs = -1, n=0;
      EGLint majorVersion;
      EGLint minorVersion;
-     EGLConfig config;
      EGLContext context;
+     EGLConfig config;
      EGLSurface surface;
      EGLint w, h;
-     
      EGLDisplay dpy;
 
      dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
      eglInitialize(dpy, &majorVersion, &minorVersion);
+          
+     EGLNativeWindowType window = android_createDisplaySurface();
      
-     // Get all the "potential match" configs...
-     eglGetConfigs(dpy, NULL, 0, &numConfigs);
-     EGLConfig* const configs = malloc(sizeof(EGLConfig)*numConfigs);
-     eglChooseConfig(dpy, s_configAttribs, configs, numConfigs, &n);
-     config = configs[0];
-     if (n > 1) {
-         // if there is more than one candidate, go through the list
-         // and pick one that matches our framebuffer format
-         int fbSzA = 0; // should not hardcode
-         int fbSzR = 5; // should not hardcode
-         int fbSzG = 6; // should not hardcode
-         int fbSzB = 5; // should not hardcode
-         int i;
-         for (i=0 ; i<n ; i++) {
-             EGLint r,g,b,a;
-             eglGetConfigAttrib(dpy, configs[i], EGL_RED_SIZE,   &r);
-             eglGetConfigAttrib(dpy, configs[i], EGL_GREEN_SIZE, &g);
-             eglGetConfigAttrib(dpy, configs[i], EGL_BLUE_SIZE,  &b);
-             eglGetConfigAttrib(dpy, configs[i], EGL_ALPHA_SIZE, &a);
-             if (fbSzA == a && fbSzR == r && fbSzG == g && fbSzB  == b) {
-                 config = configs[i];
-                 break;
-             }
-         }
+     status_t err = EGLUtils::selectConfigForNativeWindow(
+             dpy, configAttribs, window, &config);
+     if (err) {
+         fprintf(stderr, "couldn't find an EGLConfig matching the screen format\n");
+         return 0;
      }
-     free(configs);
-     
-     
-     
-     surface = eglCreateWindowSurface(dpy, config,
-             android_createDisplaySurface(), NULL);
+
+     surface = eglCreateWindowSurface(dpy, config, window, NULL);
      context = eglCreateContext(dpy, config, NULL, NULL);
      eglMakeCurrent(dpy, surface, surface, context);   
      eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index d0e714f..ed16a37 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -792,7 +792,11 @@
 
         synchronized(mClearDataLock) {
             mClearingData = true;
-            mPackageManager.clearApplicationUserData(packageName, observer);
+            try {
+                mActivityManager.clearApplicationUserData(packageName, observer);
+            } catch (RemoteException e) {
+                // can't happen because the activity manager is in this process
+            }
 
             // only wait 10 seconds for the clear data to happen
             long timeoutMark = System.currentTimeMillis() + TIMEOUT_INTERVAL;
diff --git a/services/java/com/android/server/KeyInputQueue.java b/services/java/com/android/server/KeyInputQueue.java
index cfb3e35..dc7d22b 100644
--- a/services/java/com/android/server/KeyInputQueue.java
+++ b/services/java/com/android/server/KeyInputQueue.java
@@ -194,10 +194,10 @@
         }
     }
 
-    private void readVirtualKeys() {
+    private void readVirtualKeys(String deviceName) {
         try {
             FileInputStream fis = new FileInputStream(
-                    "/sys/board_properties/virtualkeys.synaptics-rmi-touchscreen");
+                    "/sys/board_properties/virtualkeys." + deviceName);
             InputStreamReader isr = new InputStreamReader(fis);
             BufferedReader br = new BufferedReader(isr);
             String str = br.readLine();
@@ -276,7 +276,6 @@
 
         mHapticFeedbackCallback = hapticFeedbackCallback;
         
-        readVirtualKeys();
         readExcludedDevices();
         
         PowerManager pm = (PowerManager)context.getSystemService(
@@ -393,6 +392,9 @@
                         synchronized (mFirst) {
                             di = newInputDevice(ev.deviceId);
                             mDevices.put(ev.deviceId, di);
+                            if ((di.classes & RawInputEvent.CLASS_TOUCHSCREEN) != 0) {
+                                readVirtualKeys(di.name);
+                            }
                             configChanged = true;
                         }
                     } else if (ev.type == RawInputEvent.EV_DEVICE_REMOVED) {
diff --git a/services/java/com/android/server/ProcessStats.java b/services/java/com/android/server/ProcessStats.java
index 58f8980..af80e20 100644
--- a/services/java/com/android/server/ProcessStats.java
+++ b/services/java/com/android/server/ProcessStats.java
@@ -46,18 +46,23 @@
         PROC_SPACE_TERM,
         PROC_SPACE_TERM,
         PROC_SPACE_TERM,
+        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 9: minor faults
         PROC_SPACE_TERM,
-        PROC_SPACE_TERM,
-        PROC_SPACE_TERM,
+        PROC_SPACE_TERM|PROC_OUT_LONG,                  // 11: major faults
         PROC_SPACE_TERM,
         PROC_SPACE_TERM|PROC_OUT_LONG,                  // 13: utime
         PROC_SPACE_TERM|PROC_OUT_LONG                   // 14: stime
     };
 
+    static final int PROCESS_STAT_MINOR_FAULTS = 0;
+    static final int PROCESS_STAT_MAJOR_FAULTS = 1;
+    static final int PROCESS_STAT_UTIME = 2;
+    static final int PROCESS_STAT_STIME = 3;
+    
     /** Stores user time and system time in 100ths of a second. */
-    private final long[] mProcessStatsData = new long[2];
+    private final long[] mProcessStatsData = new long[4];
     /** Stores user time and system time in 100ths of a second. */
-    private final long[] mSinglePidStatsData = new long[2];
+    private final long[] mSinglePidStatsData = new long[4];
 
     private static final int[] PROCESS_FULL_STATS_FORMAT = new int[] {
         PROC_SPACE_TERM,
@@ -151,6 +156,11 @@
         public int rel_utime;
         public int rel_stime;
 
+        public long base_minfaults;
+        public long base_majfaults;
+        public int rel_minfaults;
+        public int rel_majfaults;
+        
         public boolean active;
         public boolean added;
         public boolean removed;
@@ -313,12 +323,16 @@
                     continue;
                 }
                 
-                final long utime = procStats[0];
-                final long stime = procStats[1];
+                final long minfaults = procStats[PROCESS_STAT_MINOR_FAULTS];
+                final long majfaults = procStats[PROCESS_STAT_MAJOR_FAULTS];
+                final long utime = procStats[PROCESS_STAT_UTIME];
+                final long stime = procStats[PROCESS_STAT_STIME];
 
                 if (utime == st.base_utime && stime == st.base_stime) {
                     st.rel_utime = 0;
                     st.rel_stime = 0;
+                    st.rel_minfaults = 0;
+                    st.rel_majfaults = 0;
                     if (st.active) {
                         st.active = false;
                     }
@@ -342,6 +356,10 @@
                 st.rel_stime = (int)(stime - st.base_stime);
                 st.base_utime = utime;
                 st.base_stime = stime;
+                st.rel_minfaults = (int)(minfaults - st.base_minfaults);
+                st.rel_majfaults = (int)(majfaults - st.base_majfaults);
+                st.base_minfaults = minfaults;
+                st.base_majfaults = majfaults;
                 //Log.i("Load", "Stats changed " + name + " pid=" + st.pid
                 //      + " name=" + st.name + " utime=" + utime
                 //      + " stime=" + stime);
@@ -364,11 +382,13 @@
                         procStats, null)) {
                     st.baseName = parentPid < 0
                             ? procStatsString[0] : Integer.toString(pid);
-                    st.base_utime = procStats[1];
-                    st.base_stime = procStats[2];
+                    st.base_utime = 0; //procStats[1];
+                    st.base_stime = 0; //procStats[2];
+                    st.base_minfaults = st.base_majfaults = 0;
                 } else {
                     st.baseName = "<unknown>";
                     st.base_utime = st.base_stime = 0;
+                    st.base_minfaults = st.base_majfaults = 0;
                 }
 
                 if (parentPid < 0) {
@@ -386,6 +406,8 @@
                 //Log.i("Load", "New process: " + st.pid + " " + st.name);
                 st.rel_utime = 0;
                 st.rel_stime = 0;
+                st.rel_minfaults = 0;
+                st.rel_majfaults = 0;
                 st.added = true;
                 if (!first) {
                     workingProcs.add(st);
@@ -396,6 +418,8 @@
             // This process has gone away!
             st.rel_utime = 0;
             st.rel_stime = 0;
+            st.rel_minfaults = 0;
+            st.rel_majfaults = 0;
             st.removed = true;
             workingProcs.add(st);
             allProcs.remove(curStatsIndex);
@@ -412,6 +436,8 @@
             final Stats st = allProcs.get(curStatsIndex);
             st.rel_utime = 0;
             st.rel_stime = 0;
+            st.rel_minfaults = 0;
+            st.rel_majfaults = 0;
             st.removed = true;
             workingProcs.add(st);
             allProcs.remove(curStatsIndex);
@@ -427,7 +453,8 @@
         final long[] statsData = mSinglePidStatsData;
         if (Process.readProcFile(statFile, PROCESS_STATS_FORMAT,
                 null, statsData, null)) {
-            long time = statsData[0] + statsData[1];
+            long time = statsData[PROCESS_STAT_UTIME]
+                    + statsData[PROCESS_STAT_STIME];
             return time;
         }
         return 0;
@@ -497,33 +524,35 @@
         pw.print(now-mCurrentSampleTime);
         pw.println("ms ago:");
         
-        final int totalTime = mRelUserTime + mRelSystemTime + mRelIoWaitTime + mRelIrqTime + 
-                mRelSoftIrqTime + mRelIdleTime;
+        final int totalTime = mRelUserTime + mRelSystemTime + mRelIoWaitTime
+                + mRelIrqTime + mRelSoftIrqTime + mRelIdleTime;
         
         int N = mWorkingProcs.size();
         for (int i=0; i<N; i++) {
             Stats st = mWorkingProcs.get(i);
             printProcessCPU(pw, st.added ? " +" : (st.removed ? " -": "  "),
-                    st.name, totalTime, st.rel_utime, st.rel_stime, 0, 0, 0);
+                    st.name, totalTime, st.rel_utime, st.rel_stime, 0, 0, 0,
+                    st.rel_minfaults, st.rel_majfaults);
             if (!st.removed && st.workingThreads != null) {
                 int M = st.workingThreads.size();
                 for (int j=0; j<M; j++) {
                     Stats tst = st.workingThreads.get(j);
                     printProcessCPU(pw,
                             tst.added ? "   +" : (tst.removed ? "   -": "    "),
-                            tst.name, totalTime, tst.rel_utime, tst.rel_stime, 0, 0, 0);
+                            tst.name, totalTime, tst.rel_utime, tst.rel_stime,
+                            0, 0, 0, 0, 0);
                 }
             }
         }
         
-        printProcessCPU(pw, "", "TOTAL", totalTime, mRelUserTime, mRelSystemTime, mRelIoWaitTime,
-                mRelIrqTime, mRelSoftIrqTime);
+        printProcessCPU(pw, "", "TOTAL", totalTime, mRelUserTime, mRelSystemTime,
+                mRelIoWaitTime, mRelIrqTime, mRelSoftIrqTime, 0, 0);
         
         return sw.toString();
     }
     
     private void printProcessCPU(PrintWriter pw, String prefix, String label, int totalTime, 
-            int user, int system, int iowait, int irq, int softIrq) {
+            int user, int system, int iowait, int irq, int softIrq, int minFaults, int majFaults) {
         pw.print(prefix);
         pw.print(label);
         pw.print(": ");
@@ -549,6 +578,19 @@
             pw.print((softIrq*100)/totalTime);
             pw.print("% softirq");
         }
+        if (minFaults > 0 || majFaults > 0) {
+            pw.print(" / faults:");
+            if (minFaults > 0) {
+                pw.print(" ");
+                pw.print(minFaults);
+                pw.print(" minor");
+            }
+            if (majFaults > 0) {
+                pw.print(" ");
+                pw.print(majFaults);
+                pw.print(" major");
+            }
+        }
         pw.println();
     }
     
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 82539fb..598f945 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -54,10 +54,13 @@
      * @param sentIntent if not NULL this <code>PendingIntent</code> is
      *  broadcast when the message is sucessfully sent, or failed.
      *  The result code will be <code>Activity.RESULT_OK<code> for success,
-     *  or one of these errors:
-     *  <code>RESULT_ERROR_GENERIC_FAILURE</code>
-     *  <code>RESULT_ERROR_RADIO_OFF</code>
-     *  <code>RESULT_ERROR_NULL_PDU</code>.
+     *  or one of these errors:<br>
+     *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
+     *  <code>RESULT_ERROR_RADIO_OFF</code><br>
+     *  <code>RESULT_ERROR_NULL_PDU</code><br>
+     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
+     *  the extra "errorCode" containing a radio technology specific value,
+     *  generally only useful for troubleshooting.<br>
      *  The per-application based SMS control checks sentIntent. If sentIntent
      *  is NULL the caller will be checked against all unknown applications,
      *  which cause smaller number of SMS to be sent in checking period.
@@ -109,10 +112,13 @@
      *   <code>PendingIntent</code>s (one for each message part) that is
      *   broadcast when the corresponding message part has been sent.
      *   The result code will be <code>Activity.RESULT_OK<code> for success,
-     *   or one of these errors:
-     *   <code>RESULT_ERROR_GENERIC_FAILURE</code>
-     *   <code>RESULT_ERROR_RADIO_OFF</code>
-     *   <code>RESULT_ERROR_NULL_PDU</code>.
+     *   or one of these errors:<br>
+     *   <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
+     *   <code>RESULT_ERROR_RADIO_OFF</code><br>
+     *   <code>RESULT_ERROR_NULL_PDU</code><br>
+     *   For <code>RESULT_ERROR_GENERIC_FAILURE</code> each sentIntent may include
+     *   the extra "errorCode" containing a radio technology specific value,
+     *   generally only useful for troubleshooting.<br>
      *   The per-application based SMS control checks sentIntent. If sentIntent
      *   is NULL the caller will be checked against all unknown applicaitons,
      *   which cause smaller number of SMS to be sent in checking period.
@@ -169,10 +175,13 @@
      * @param sentIntent if not NULL this <code>PendingIntent</code> is
      *  broadcast when the message is sucessfully sent, or failed.
      *  The result code will be <code>Activity.RESULT_OK<code> for success,
-     *  or one of these errors:
-     *  <code>RESULT_ERROR_GENERIC_FAILURE</code>
-     *  <code>RESULT_ERROR_RADIO_OFF</code>
-     *  <code>RESULT_ERROR_NULL_PDU</code>.
+     *  or one of these errors:<br>
+     *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
+     *  <code>RESULT_ERROR_RADIO_OFF</code><br>
+     *  <code>RESULT_ERROR_NULL_PDU</code><br>
+     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
+     *  the extra "errorCode" containing a radio technology specific value,
+     *  generally only useful for troubleshooting.<br>
      *  The per-application based SMS control checks sentIntent. If sentIntent
      *  is NULL the caller will be checked against all unknown applicaitons,
      *  which cause smaller number of SMS to be sent in checking period.
@@ -210,10 +219,13 @@
      * @param sentIntent if not NULL this <code>PendingIntent</code> is
      *  broadcast when the message is successfully sent, or failed.
      *  The result code will be <code>Activity.RESULT_OK<code> for success,
-     *  or one of these errors:
-     *  <code>RESULT_ERROR_GENERIC_FAILURE</code>
-     *  <code>RESULT_ERROR_RADIO_OFF</code>
-     *  <code>RESULT_ERROR_NULL_PDU</code>.
+     *  or one of these errors:<br>
+     *  <code>RESULT_ERROR_GENERIC_FAILURE</code><br>
+     *  <code>RESULT_ERROR_RADIO_OFF</code><br>
+     *  <code>RESULT_ERROR_NULL_PDU</code><br>
+     *  For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include
+     *  the extra "errorCode" containing a radio technology specific value,
+     *  generally only useful for troubleshooting.<br>
      *  The per-application based SMS control checks sentIntent. If sentIntent
      *  is NULL the caller will be checked against all unknown applications,
      *  which cause smaller number of SMS to be sent in checking period.
diff --git a/telephony/java/com/android/internal/telephony/SMSDispatcher.java b/telephony/java/com/android/internal/telephony/SMSDispatcher.java
index 890ea63..d66c20b 100644
--- a/telephony/java/com/android/internal/telephony/SMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/SMSDispatcher.java
@@ -445,7 +445,11 @@
             } else if (tracker.mSentIntent != null) {
                 // Done retrying; return an error to the app.
                 try {
-                    tracker.mSentIntent.send(RESULT_ERROR_GENERIC_FAILURE);
+                    Intent fillIn = new Intent();
+                    if (ar.result != null) {
+                        fillIn.putExtra("errorCode", ((SmsResponse)ar.result).errorCode);
+                    }
+                    tracker.mSentIntent.send(mContext, RESULT_ERROR_GENERIC_FAILURE, fillIn);
                 } catch (CanceledException ex) {}
             }
         }
diff --git a/tests/backup/test_backup.sh b/tests/backup/test_backup.sh
index dd3907c..f50d03f 100755
--- a/tests/backup/test_backup.sh
+++ b/tests/backup/test_backup.sh
@@ -20,6 +20,18 @@
 #FIXME: what was this for?
 #adb kill-server
 
+b_pkgs=$(adb $ADB_OPTS shell dumpsys backup | \
+         ruby -ne 'print($1+" ") if $_ =~ /^\s*ApplicationInfo\{\S+ (.+?)\}/')
+
+# wipe prior backup data for packages, including the metadata package @pm@
+for pkg in $b_pkgs '@pm@'; do
+    adb $ADB_OPTS shell bmgr wipe "$pkg"
+done
+
+# who knows?
+echo 'Waiting 5 seconds for things to settle...'
+sleep 5
+
 # run adb as root so we can poke at com.android.backuptest's data
 root_status=$(adb $ADB_OPTS root)
 if [ "x$root_status" != "xadbd is already running as root" ]; then
@@ -35,16 +47,20 @@
 
 # load up the three files
 adb $ADB_OPTS shell \
-   "rm /data/data/com.android.backuptest/files/* ; \
+   "rm /data/data/com.android.backuptest/files/file.txt ; \
+    rm /data/data/com.android.backuptest/files/another_file.txt ; \
+    rm /data/data/com.android.backuptest/files/empty.txt ; \
     mkdir /data/data/com.android.backuptest ; \
     mkdir /data/data/com.android.backuptest/files ; \
     mkdir /data/data/com.android.backuptest/shared_prefs ; \
-    echo -n \"<map><int name=\\\"pref\\\" value=\\\"1\\\" /></map>\" > /data/data com.android.backuptest/shared_prefs/raw.xml ; \
+    echo -n \"<map><int name=\\\"pref\\\" value=\\\"1\\\" /></map>\" \
+            > /data/data/com.android.backuptest/shared_prefs/raw.xml ; \
     echo -n first file > /data/data/com.android.backuptest/files/file.txt ; \
     echo -n asdf > /data/data/com.android.backuptest/files/another_file.txt ; \
-    echo -n 3 > /data/data/com.android.backuptest/files/3.txt ; \
     echo -n "" > /data/data/com.android.backuptest/files/empty.txt ; \
+    date >> /data/data/com.android.backuptest/files/3.txt ; \
 "
+#    echo -n 3 > /data/data/com.android.backuptest/files/3.txt ; \
 
 # say that the data has changed
 adb $ADB_OPTS shell bmgr backup com.android.backuptest
diff --git a/tests/backup/test_restore.sh b/tests/backup/test_restore.sh
index 8de70cb..44b3a28 100755
--- a/tests/backup/test_restore.sh
+++ b/tests/backup/test_restore.sh
@@ -70,7 +70,7 @@
 # check the results
 check_file files/file.txt "first file"
 check_file files/another_file.txt "asdf"
-check_file files/3.txt "3"
+#check_file files/3.txt "3"
 check_file files/empty.txt ""
 check_file shared_prefs/raw.xml '<map><int name="pref" value="1" /></map>'
 
@@ -84,3 +84,6 @@
 echo ---
 echo
 
+echo "Last 3 timestamps in 3.txt:"
+adb $ADB_OPTS shell cat /data/data/com.android.backuptest/files/3.txt | tail -n 3
+