am bd324c9b: Merge change I50a321c9 into eclair

Merge commit 'bd324c9bd32a3c86634c1cc1ab8525f46a56b694' into eclair-mr2

* commit 'bd324c9bd32a3c86634c1cc1ab8525f46a56b694':
  LocationManagerService: Fix race when removing LocationListener
diff --git a/api/current.xml b/api/current.xml
index f4d81c7..b269c82 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -117671,6 +117671,23 @@
 <parameter name="origId" type="long">
 </parameter>
 </method>
+<method name="cancelThumbnailRequest"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cr" type="android.content.ContentResolver">
+</parameter>
+<parameter name="origId" type="long">
+</parameter>
+<parameter name="groupId" type="long">
+</parameter>
+</method>
 <method name="getContentUri"
  return="android.net.Uri"
  abstract="false"
@@ -117703,6 +117720,27 @@
 <parameter name="options" type="android.graphics.BitmapFactory.Options">
 </parameter>
 </method>
+<method name="getThumbnail"
+ return="android.graphics.Bitmap"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cr" type="android.content.ContentResolver">
+</parameter>
+<parameter name="origId" type="long">
+</parameter>
+<parameter name="groupId" type="long">
+</parameter>
+<parameter name="kind" type="int">
+</parameter>
+<parameter name="options" type="android.graphics.BitmapFactory.Options">
+</parameter>
+</method>
 <method name="query"
  return="android.database.Cursor"
  abstract="false"
@@ -118128,6 +118166,23 @@
 <parameter name="origId" type="long">
 </parameter>
 </method>
+<method name="cancelThumbnailRequest"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cr" type="android.content.ContentResolver">
+</parameter>
+<parameter name="origId" type="long">
+</parameter>
+<parameter name="groupId" type="long">
+</parameter>
+</method>
 <method name="getContentUri"
  return="android.net.Uri"
  abstract="false"
@@ -118160,6 +118215,27 @@
 <parameter name="options" type="android.graphics.BitmapFactory.Options">
 </parameter>
 </method>
+<method name="getThumbnail"
+ return="android.graphics.Bitmap"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="cr" type="android.content.ContentResolver">
+</parameter>
+<parameter name="origId" type="long">
+</parameter>
+<parameter name="groupId" type="long">
+</parameter>
+<parameter name="kind" type="int">
+</parameter>
+<parameter name="options" type="android.graphics.BitmapFactory.Options">
+</parameter>
+</method>
 <field name="DATA"
  type="java.lang.String"
  transient="false"
diff --git a/core/java/android/net/http/Connection.java b/core/java/android/net/http/Connection.java
index 2d39e39..b8e17da 100644
--- a/core/java/android/net/http/Connection.java
+++ b/core/java/android/net/http/Connection.java
@@ -94,7 +94,6 @@
      */
     private static final String HTTP_CONNECTION = "http.connection";
 
-    RequestQueue.ConnectionManager mConnectionManager;
     RequestFeeder mRequestFeeder;
 
     /**
@@ -104,11 +103,9 @@
     private byte[] mBuf;
 
     protected Connection(Context context, HttpHost host,
-                         RequestQueue.ConnectionManager connectionManager,
                          RequestFeeder requestFeeder) {
         mContext = context;
         mHost = host;
-        mConnectionManager = connectionManager;
         mRequestFeeder = requestFeeder;
 
         mCanPersist = false;
@@ -124,18 +121,15 @@
      * necessary
      */
     static Connection getConnection(
-            Context context, HttpHost host,
-            RequestQueue.ConnectionManager connectionManager,
+            Context context, HttpHost host, HttpHost proxy,
             RequestFeeder requestFeeder) {
 
         if (host.getSchemeName().equals("http")) {
-            return new HttpConnection(context, host, connectionManager,
-                                      requestFeeder);
+            return new HttpConnection(context, host, requestFeeder);
         }
 
         // Otherwise, default to https
-        return new HttpsConnection(context, host, connectionManager,
-                                   requestFeeder);
+        return new HttpsConnection(context, host, proxy, requestFeeder);
     }
 
     /**
@@ -338,7 +332,7 @@
                 mRequestFeeder.requeueRequest(tReq);
                 empty = false;
             }
-            if (empty) empty = mRequestFeeder.haveRequest(mHost);
+            if (empty) empty = !mRequestFeeder.haveRequest(mHost);
         }
         return empty;
     }
diff --git a/core/java/android/net/http/ConnectionThread.java b/core/java/android/net/http/ConnectionThread.java
index 0b30e58..32191d2 100644
--- a/core/java/android/net/http/ConnectionThread.java
+++ b/core/java/android/net/http/ConnectionThread.java
@@ -108,24 +108,11 @@
                 if (HttpLog.LOGV) HttpLog.v("ConnectionThread: new request " +
                                             request.mHost + " " + request );
 
-                HttpHost proxy = mConnectionManager.getProxyHost();
-
-                HttpHost host;
-                if (false) {
-                    // Allow https proxy
-                    host = proxy == null ? request.mHost : proxy;
-                } else {
-                    // Disallow https proxy -- tmob proxy server
-                    // serves a request loop for https reqs
-                    host = (proxy == null ||
-                            request.mHost.getSchemeName().equals("https")) ?
-                            request.mHost : proxy;
-                }
-                mConnection = mConnectionManager.getConnection(mContext, host);
+                mConnection = mConnectionManager.getConnection(mContext,
+                        request.mHost);
                 mConnection.processRequests(request);
                 if (mConnection.getCanPersist()) {
-                    if (!mConnectionManager.recycleConnection(host,
-                                mConnection)) {
+                    if (!mConnectionManager.recycleConnection(mConnection)) {
                         mConnection.closeConnection();
                     }
                 } else {
diff --git a/core/java/android/net/http/HttpConnection.java b/core/java/android/net/http/HttpConnection.java
index 8b12d0b..6df86bf 100644
--- a/core/java/android/net/http/HttpConnection.java
+++ b/core/java/android/net/http/HttpConnection.java
@@ -35,9 +35,8 @@
 class HttpConnection extends Connection {
 
     HttpConnection(Context context, HttpHost host,
-                   RequestQueue.ConnectionManager connectionManager,
                    RequestFeeder requestFeeder) {
-        super(context, host, connectionManager, requestFeeder);
+        super(context, host, requestFeeder);
     }
 
     /**
diff --git a/core/java/android/net/http/HttpsConnection.java b/core/java/android/net/http/HttpsConnection.java
index 8a69d0d..f735f3d 100644
--- a/core/java/android/net/http/HttpsConnection.java
+++ b/core/java/android/net/http/HttpsConnection.java
@@ -131,13 +131,16 @@
      */
     private boolean mAborted = false;
 
+    // Used when connecting through a proxy.
+    private HttpHost mProxyHost;
+
     /**
      * Contructor for a https connection.
      */
-    HttpsConnection(Context context, HttpHost host,
-                    RequestQueue.ConnectionManager connectionManager,
+    HttpsConnection(Context context, HttpHost host, HttpHost proxy,
                     RequestFeeder requestFeeder) {
-        super(context, host, connectionManager, requestFeeder);
+        super(context, host, requestFeeder);
+        mProxyHost = proxy;
     }
 
     /**
@@ -159,8 +162,7 @@
     AndroidHttpClientConnection openConnection(Request req) throws IOException {
         SSLSocket sslSock = null;
 
-        HttpHost proxyHost = mConnectionManager.getProxyHost();
-        if (proxyHost != null) {
+        if (mProxyHost != null) {
             // If we have a proxy set, we first send a CONNECT request
             // to the proxy; if the proxy returns 200 OK, we negotiate
             // a secure connection to the target server via the proxy.
@@ -172,7 +174,7 @@
             Socket proxySock = null;
             try {
                 proxySock = new Socket
-                    (proxyHost.getHostName(), proxyHost.getPort());
+                    (mProxyHost.getHostName(), mProxyHost.getPort());
 
                 proxySock.setSoTimeout(60 * 1000);
 
diff --git a/core/java/android/net/http/RequestHandle.java b/core/java/android/net/http/RequestHandle.java
index 190ae7a..77cd544 100644
--- a/core/java/android/net/http/RequestHandle.java
+++ b/core/java/android/net/http/RequestHandle.java
@@ -42,15 +42,13 @@
     private WebAddress    mUri;
     private String        mMethod;
     private Map<String, String> mHeaders;
-
     private RequestQueue  mRequestQueue;
-
     private Request       mRequest;
-
     private InputStream   mBodyProvider;
     private int           mBodyLength;
-
     private int           mRedirectCount = 0;
+    // Used only with synchronous requests.
+    private Connection    mConnection;
 
     private final static String AUTHORIZATION_HEADER = "Authorization";
     private final static String PROXY_AUTHORIZATION_HEADER = "Proxy-Authorization";
@@ -81,6 +79,19 @@
     }
 
     /**
+     * Creates a new request session with a given Connection. This connection
+     * is used during a synchronous load to handle this request.
+     */
+    public RequestHandle(RequestQueue requestQueue, String url, WebAddress uri,
+            String method, Map<String, String> headers,
+            InputStream bodyProvider, int bodyLength, Request request,
+            Connection conn) {
+        this(requestQueue, url, uri, method, headers, bodyProvider, bodyLength,
+                request);
+        mConnection = conn;
+    }
+
+    /**
      * Cancels this request
      */
     public void cancel() {
@@ -262,6 +273,12 @@
         mRequest.waitUntilComplete();
     }
 
+    public void processRequest() {
+        if (mConnection != null) {
+            mConnection.processRequests(mRequest);
+        }
+    }
+
     /**
      * @return Digest-scheme authentication response.
      */
diff --git a/core/java/android/net/http/RequestQueue.java b/core/java/android/net/http/RequestQueue.java
index 875caa0..84b6487 100644
--- a/core/java/android/net/http/RequestQueue.java
+++ b/core/java/android/net/http/RequestQueue.java
@@ -171,16 +171,17 @@
         }
 
         public Connection getConnection(Context context, HttpHost host) {
+            host = RequestQueue.this.determineHost(host);
             Connection con = mIdleCache.getConnection(host);
             if (con == null) {
                 mTotalConnection++;
-                con = Connection.getConnection(
-                        mContext, host, this, RequestQueue.this);
+                con = Connection.getConnection(mContext, host, mProxyHost,
+                        RequestQueue.this);
             }
             return con;
         }
-        public boolean recycleConnection(HttpHost host, Connection connection) {
-            return mIdleCache.cacheConnection(host, connection);
+        public boolean recycleConnection(Connection connection) {
+            return mIdleCache.cacheConnection(connection.getHost(), connection);
         }
 
     }
@@ -342,6 +343,66 @@
                 req);
     }
 
+    private static class SyncFeeder implements RequestFeeder {
+        // This is used in the case where the request fails and needs to be
+        // requeued into the RequestFeeder.
+        private Request mRequest;
+        SyncFeeder() {
+        }
+        public Request getRequest() {
+            Request r = mRequest;
+            mRequest = null;
+            return r;
+        }
+        public Request getRequest(HttpHost host) {
+            return getRequest();
+        }
+        public boolean haveRequest(HttpHost host) {
+            return mRequest != null;
+        }
+        public void requeueRequest(Request r) {
+            mRequest = r;
+        }
+    }
+
+    public RequestHandle queueSynchronousRequest(String url, WebAddress uri,
+            String method, Map<String, String> headers,
+            EventHandler eventHandler, InputStream bodyProvider,
+            int bodyLength) {
+        if (HttpLog.LOGV) {
+            HttpLog.v("RequestQueue.dispatchSynchronousRequest " + uri);
+        }
+
+        HttpHost host = new HttpHost(uri.mHost, uri.mPort, uri.mScheme);
+
+        Request req = new Request(method, host, mProxyHost, uri.mPath,
+                bodyProvider, bodyLength, eventHandler, headers);
+
+        // Open a new connection that uses our special RequestFeeder
+        // implementation.
+        host = determineHost(host);
+        Connection conn = Connection.getConnection(mContext, host, mProxyHost,
+                new SyncFeeder());
+
+        // TODO: I would like to process the request here but LoadListener
+        // needs a RequestHandle to process some messages.
+        return new RequestHandle(this, url, uri, method, headers, bodyProvider,
+                bodyLength, req, conn);
+
+    }
+
+    // Chooses between the proxy and the request's host.
+    private HttpHost determineHost(HttpHost host) {
+        // There used to be a comment in ConnectionThread about t-mob's proxy
+        // being really bad about https. But, HttpsConnection actually looks
+        // for a proxy and connects through it anyway. I think that this check
+        // is still valid because if a site is https, we will use
+        // HttpsConnection rather than HttpConnection if the proxy address is
+        // not secure.
+        return (mProxyHost == null || "https".equals(host.getSchemeName()))
+                ? host : mProxyHost;
+    }
+
     /**
      * @return true iff there are any non-active requests pending
      */
@@ -478,6 +539,6 @@
     interface ConnectionManager {
         HttpHost getProxyHost();
         Connection getConnection(Context context, HttpHost host);
-        boolean recycleConnection(HttpHost host, Connection connection);
+        boolean recycleConnection(Connection connection);
     }
 }
diff --git a/core/java/android/pim/vcard/VCardDataBuilder.java b/core/java/android/pim/vcard/VCardDataBuilder.java
index d2026d0..d00f616 100644
--- a/core/java/android/pim/vcard/VCardDataBuilder.java
+++ b/core/java/android/pim/vcard/VCardDataBuilder.java
@@ -86,7 +86,7 @@
             boolean strictLineBreakParsing, int vcardType, Account account) {
         this(null, charset, strictLineBreakParsing, vcardType, account);
     }
-    
+
     /**
      * @hide
      */
@@ -127,6 +127,18 @@
     }
 
     /**
+     * Called when the parse failed between startRecord() and endRecord().
+     * Currently it happens only when the vCard format is 3.0.
+     * (VCardVersionException is thrown by VCardParser_V21 and this object is reused by
+     * VCardParser_V30. At that time, startRecord() is called twice before endRecord() is called.)
+     * TODO: Should this be in VCardBuilder interface?
+     */
+    public void clear() {
+        mCurrentContactStruct = null;
+        mCurrentProperty = new ContactStruct.Property();
+    }
+
+    /**
      * Assume that VCard is not nested. In other words, this code does not accept 
      */
     public void startRecord(String type) {
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index 08a2a9f..197d976 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -188,17 +188,7 @@
         mContext = context;
 
         TypedArray a = context.obtainStyledAttributes(attrs,
-                com.android.internal.R.styleable.Preference);
-        if (a.hasValue(com.android.internal.R.styleable.Preference_layout) ||
-                a.hasValue(com.android.internal.R.styleable.Preference_widgetLayout)) {
-            // This preference has a custom layout defined (not one taken from
-            // the default style)
-            mHasSpecifiedLayout = true;
-        }
-        a.recycle();
-        
-        a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.Preference,
-                defStyle, 0);
+                com.android.internal.R.styleable.Preference, defStyle, 0);
         for (int i = a.getIndexCount(); i >= 0; i--) {
             int attr = a.getIndex(i); 
             switch (attr) {
@@ -252,6 +242,11 @@
             }
         }
         a.recycle();
+
+        if (!getClass().getName().startsWith("android.preference")) {
+            // For subclasses not in this package, assume the worst and don't cache views
+            mHasSpecifiedLayout = true;
+        }
     }
     
     /**
@@ -332,11 +327,11 @@
      * @see #setWidgetLayoutResource(int)
      */
     public void setLayoutResource(int layoutResId) {
-        
-        if (!mHasSpecifiedLayout) {
+        if (layoutResId != mLayoutResId) {
+            // Layout changed
             mHasSpecifiedLayout = true;
         }
-        
+
         mLayoutResId = layoutResId;
     }
     
@@ -360,6 +355,10 @@
      * @see #setLayoutResource(int)
      */
     public void setWidgetLayoutResource(int widgetLayoutResId) {
+        if (widgetLayoutResId != mWidgetLayoutResId) {
+            // Layout changed
+            mHasSpecifiedLayout = true;
+        }
         mWidgetLayoutResId = widgetLayoutResId;
     }
 
diff --git a/core/java/android/preference/PreferenceGroupAdapter.java b/core/java/android/preference/PreferenceGroupAdapter.java
index 14c0054..a908ecd 100644
--- a/core/java/android/preference/PreferenceGroupAdapter.java
+++ b/core/java/android/preference/PreferenceGroupAdapter.java
@@ -69,7 +69,9 @@
      * count once--when the adapter is being set). We will not recycle views for
      * Preference subclasses seen after the count has been returned.
      */
-    private List<String> mPreferenceClassNames;
+    private ArrayList<PreferenceLayout> mPreferenceLayouts;
+
+    private PreferenceLayout mTempPreferenceLayout = new PreferenceLayout();
 
     /**
      * Blocks the mPreferenceClassNames from being changed anymore.
@@ -86,14 +88,37 @@
         }
     };
 
+    private static class PreferenceLayout implements Comparable<PreferenceLayout> {
+        private int resId;
+        private int widgetResId;
+        private String name;
+
+        public int compareTo(PreferenceLayout other) {
+            int compareNames = name.compareTo(other.name);
+            if (compareNames == 0) {
+                if (resId == other.resId) {
+                    if (widgetResId == other.widgetResId) {
+                        return 0;
+                    } else {
+                        return widgetResId - other.widgetResId;
+                    }
+                } else {
+                    return resId - other.resId;
+                }
+            } else {
+                return compareNames;
+            }
+        }
+    }
+
     public PreferenceGroupAdapter(PreferenceGroup preferenceGroup) {
         mPreferenceGroup = preferenceGroup;
         // If this group gets or loses any children, let us know
         mPreferenceGroup.setOnPreferenceChangeInternalListener(this);
-        
+
         mPreferenceList = new ArrayList<Preference>();
-        mPreferenceClassNames = new ArrayList<String>();
-        
+        mPreferenceLayouts = new ArrayList<PreferenceLayout>();
+
         syncMyPreferences();
     }
 
@@ -102,7 +127,7 @@
             if (mIsSyncing) {
                 return;
             }
-        
+
             mIsSyncing = true;
         }
 
@@ -128,7 +153,7 @@
             
             preferences.add(preference);
             
-            if (!mHasReturnedViewTypeCount) {
+            if (!mHasReturnedViewTypeCount && !preference.hasSpecifiedLayout()) {
                 addPreferenceClassName(preference);
             }
             
@@ -143,15 +168,28 @@
         }
     }
 
+    /**
+     * Creates a string that includes the preference name, layout id and widget layout id.
+     * If a particular preference type uses 2 different resources, they will be treated as
+     * different view types.
+     */
+    private PreferenceLayout createPreferenceLayout(Preference preference, PreferenceLayout in) {
+        PreferenceLayout pl = in != null? in : new PreferenceLayout();
+        pl.name = preference.getClass().getName();
+        pl.resId = preference.getLayoutResource();
+        pl.widgetResId = preference.getWidgetLayoutResource();
+        return pl;
+    }
+
     private void addPreferenceClassName(Preference preference) {
-        final String name = preference.getClass().getName();
-        int insertPos = Collections.binarySearch(mPreferenceClassNames, name);
-        
+        final PreferenceLayout pl = createPreferenceLayout(preference, null);
+        int insertPos = Collections.binarySearch(mPreferenceLayouts, pl);
+
         // Only insert if it doesn't exist (when it is negative).
         if (insertPos < 0) {
             // Convert to insert index
             insertPos = insertPos * -1 - 1;
-            mPreferenceClassNames.add(insertPos, name);
+            mPreferenceLayouts.add(insertPos, pl);
         }
     }
     
@@ -171,19 +209,15 @@
 
     public View getView(int position, View convertView, ViewGroup parent) {
         final Preference preference = this.getItem(position);
-        
-        if (preference.hasSpecifiedLayout()) {
-            // If the preference had specified a layout (as opposed to the
-            // default), don't use convert views.
+        // Build a PreferenceLayout to compare with known ones that are cacheable.
+        mTempPreferenceLayout = createPreferenceLayout(preference, mTempPreferenceLayout);
+
+        // If it's not one of the cached ones, set the convertView to null so that 
+        // the layout gets re-created by the Preference.
+        if (Collections.binarySearch(mPreferenceLayouts, mTempPreferenceLayout) < 0) {
             convertView = null;
-        } else {
-            // TODO: better way of doing this
-            final String name = preference.getClass().getName();
-            if (Collections.binarySearch(mPreferenceClassNames, name) < 0) {
-                convertView = null;
-            }
         }
-        
+
         return preference.getView(convertView, parent);
     }
 
@@ -225,8 +259,9 @@
             return IGNORE_ITEM_VIEW_TYPE;
         }
 
-        final String name = preference.getClass().getName();
-        int viewType = Collections.binarySearch(mPreferenceClassNames, name);
+        mTempPreferenceLayout = createPreferenceLayout(preference, mTempPreferenceLayout);
+
+        int viewType = Collections.binarySearch(mPreferenceLayouts, mTempPreferenceLayout);
         if (viewType < 0) {
             // This is a class that was seen after we returned the count, so
             // don't recycle it.
@@ -242,7 +277,7 @@
             mHasReturnedViewTypeCount = true;
         }
         
-        return Math.max(1, mPreferenceClassNames.size());
+        return Math.max(1, mPreferenceLayouts.size());
     }
 
 }
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 062080d..cd71682 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -238,6 +238,7 @@
         private static final int FULL_SCREEN_KIND = 2;
         private static final int MICRO_KIND = 3;
         private static final String[] PROJECTION = new String[] {_ID, MediaColumns.DATA};
+        static final int DEFAULT_GROUP_ID = 0;
 
         /**
          * This method cancels the thumbnail request so clients waiting for getThumbnail will be
@@ -246,11 +247,14 @@
          *
          * @param cr ContentResolver
          * @param origId original image or video id. use -1 to cancel all requests.
+         * @param groupId the same groupId used in getThumbnail
          * @param baseUri the base URI of requested thumbnails
          */
-        static void cancelThumbnailRequest(ContentResolver cr, long origId, Uri baseUri) {
+        static void cancelThumbnailRequest(ContentResolver cr, long origId, Uri baseUri,
+                long groupId) {
             Uri cancelUri = baseUri.buildUpon().appendQueryParameter("cancel", "1")
-                    .appendQueryParameter("orig_id", String.valueOf(origId)).build();
+                    .appendQueryParameter("orig_id", String.valueOf(origId))
+                    .appendQueryParameter("group_id", String.valueOf(groupId)).build();
             Cursor c = null;
             try {
                 c = cr.query(cancelUri, PROJECTION, null, null, null);
@@ -271,9 +275,10 @@
          * @param kind could be MINI_KIND or MICRO_KIND
          * @param options this is only used for MINI_KIND when decoding the Bitmap
          * @param baseUri the base URI of requested thumbnails
+         * @param groupId the id of group to which this request belongs
          * @return Bitmap bitmap of specified thumbnail kind
          */
-        static Bitmap getThumbnail(ContentResolver cr, long origId, int kind,
+        static Bitmap getThumbnail(ContentResolver cr, long origId, long groupId, int kind,
                 BitmapFactory.Options options, Uri baseUri, boolean isVideo) {
             Bitmap bitmap = null;
             String filePath = null;
@@ -297,7 +302,8 @@
             Cursor c = null;
             try {
                 Uri blockingUri = baseUri.buildUpon().appendQueryParameter("blocking", "1")
-                        .appendQueryParameter("orig_id", String.valueOf(origId)).build();
+                        .appendQueryParameter("orig_id", String.valueOf(origId))
+                        .appendQueryParameter("group_id", String.valueOf(groupId)).build();
                 c = cr.query(blockingUri, PROJECTION, null, null, null);
                 // This happens when original image/video doesn't exist.
                 if (c == null) return null;
@@ -354,7 +360,7 @@
                     }
                     if (isVideo) {
                         bitmap = ThumbnailUtil.createVideoThumbnail(filePath);
-                        if (kind == MICRO_KIND) {
+                        if (kind == MICRO_KIND && bitmap != null) {
                             bitmap = ThumbnailUtil.extractMiniThumb(bitmap,
                                     ThumbnailUtil.MINI_THUMB_TARGET_SIZE,
                                     ThumbnailUtil.MINI_THUMB_TARGET_SIZE,
@@ -669,7 +675,8 @@
              * @param origId original image id
              */
             public static void cancelThumbnailRequest(ContentResolver cr, long origId) {
-                InternalThumbnails.cancelThumbnailRequest(cr, origId, EXTERNAL_CONTENT_URI);
+                InternalThumbnails.cancelThumbnailRequest(cr, origId, EXTERNAL_CONTENT_URI,
+                        InternalThumbnails.DEFAULT_GROUP_ID);
             }
 
             /**
@@ -685,7 +692,39 @@
              */
             public static Bitmap getThumbnail(ContentResolver cr, long origId, int kind,
                     BitmapFactory.Options options) {
-                return InternalThumbnails.getThumbnail(cr, origId, kind, options,
+                return InternalThumbnails.getThumbnail(cr, origId,
+                        InternalThumbnails.DEFAULT_GROUP_ID, kind, options,
+                        EXTERNAL_CONTENT_URI, false);
+            }
+
+            /**
+             * This method cancels the thumbnail request so clients waiting for getThumbnail will be
+             * interrupted and return immediately. Only the original process which made the getThumbnail
+             * requests can cancel their own requests.
+             *
+             * @param cr ContentResolver
+             * @param origId original image id
+             * @param groupId the same groupId used in getThumbnail.
+             */
+            public static void cancelThumbnailRequest(ContentResolver cr, long origId, long groupId) {
+                InternalThumbnails.cancelThumbnailRequest(cr, origId, EXTERNAL_CONTENT_URI, groupId);
+            }
+
+            /**
+             * This method checks if the thumbnails of the specified image (origId) has been created.
+             * It will be blocked until the thumbnails are generated.
+             *
+             * @param cr ContentResolver used to dispatch queries to MediaProvider.
+             * @param origId Original image id associated with thumbnail of interest.
+             * @param groupId the id of group to which this request belongs
+             * @param kind The type of thumbnail to fetch. Should be either MINI_KIND or MICRO_KIND.
+             * @param options this is only used for MINI_KIND when decoding the Bitmap
+             * @return A Bitmap instance. It could be null if the original image
+             *         associated with origId doesn't exist or memory is not enough.
+             */
+            public static Bitmap getThumbnail(ContentResolver cr, long origId, long groupId,
+                    int kind, BitmapFactory.Options options) {
+                return InternalThumbnails.getThumbnail(cr, origId, groupId, kind, options,
                         EXTERNAL_CONTENT_URI, false);
             }
 
@@ -1598,7 +1637,8 @@
              * @param origId original video id
              */
             public static void cancelThumbnailRequest(ContentResolver cr, long origId) {
-                InternalThumbnails.cancelThumbnailRequest(cr, origId, EXTERNAL_CONTENT_URI);
+                InternalThumbnails.cancelThumbnailRequest(cr, origId, EXTERNAL_CONTENT_URI,
+                        InternalThumbnails.DEFAULT_GROUP_ID);
             }
 
             /**
@@ -1607,18 +1647,50 @@
              *
              * @param cr ContentResolver used to dispatch queries to MediaProvider.
              * @param origId Original image id associated with thumbnail of interest.
+             * @param kind The type of thumbnail to fetch. Should be either MINI_KIND or MICRO_KIND.
+             * @param options this is only used for MINI_KIND when decoding the Bitmap
+             * @return A Bitmap instance. It could be null if the original image
+             *         associated with origId doesn't exist or memory is not enough.
+             */
+            public static Bitmap getThumbnail(ContentResolver cr, long origId, int kind,
+                    BitmapFactory.Options options) {
+                return InternalThumbnails.getThumbnail(cr, origId,
+                        InternalThumbnails.DEFAULT_GROUP_ID, kind, options,
+                        EXTERNAL_CONTENT_URI, true);
+            }
+
+            /**
+             * This method checks if the thumbnails of the specified image (origId) has been created.
+             * It will be blocked until the thumbnails are generated.
+             *
+             * @param cr ContentResolver used to dispatch queries to MediaProvider.
+             * @param origId Original image id associated with thumbnail of interest.
+             * @param groupId the id of group to which this request belongs
              * @param kind The type of thumbnail to fetch. Should be either MINI_KIND or MICRO_KIND
              * @param options this is only used for MINI_KIND when decoding the Bitmap
              * @return A Bitmap instance. It could be null if the original image associated with
              *         origId doesn't exist or memory is not enough.
              */
-            public static Bitmap getThumbnail(ContentResolver cr, long origId, int kind,
-                    BitmapFactory.Options options) {
-                return InternalThumbnails.getThumbnail(cr, origId, kind, options,
+            public static Bitmap getThumbnail(ContentResolver cr, long origId, long groupId,
+                    int kind, BitmapFactory.Options options) {
+                return InternalThumbnails.getThumbnail(cr, origId, groupId, kind, options,
                         EXTERNAL_CONTENT_URI, true);
             }
 
             /**
+             * This method cancels the thumbnail request so clients waiting for getThumbnail will be
+             * interrupted and return immediately. Only the original process which made the getThumbnail
+             * requests can cancel their own requests.
+             *
+             * @param cr ContentResolver
+             * @param origId original video id
+             * @param groupId the same groupId used in getThumbnail.
+             */
+            public static void cancelThumbnailRequest(ContentResolver cr, long origId, long groupId) {
+                InternalThumbnails.cancelThumbnailRequest(cr, origId, EXTERNAL_CONTENT_URI, groupId);
+            }
+
+            /**
              * Get the content:// style URI for the image media table on the
              * given volume.
              *
diff --git a/core/java/android/webkit/HttpDateTime.java b/core/java/android/webkit/HttpDateTime.java
index 2f46f2b..042953c 100644
--- a/core/java/android/webkit/HttpDateTime.java
+++ b/core/java/android/webkit/HttpDateTime.java
@@ -50,13 +50,15 @@
      * Wdy Mon DD HH:MM:SS YYYY GMT
      * 
      * HH can be H if the first digit is zero.
+     * 
+     * Mon can be the full name of the month.
      */
     private static final String HTTP_DATE_RFC_REGEXP =
-            "([0-9]{1,2})[- ]([A-Za-z]{3,3})[- ]([0-9]{2,4})[ ]"
+            "([0-9]{1,2})[- ]([A-Za-z]{3,9})[- ]([0-9]{2,4})[ ]"
             + "([0-9]{1,2}:[0-9][0-9]:[0-9][0-9])";
 
     private static final String HTTP_DATE_ANSIC_REGEXP =
-            "[ ]([A-Za-z]{3,3})[ ]+([0-9]{1,2})[ ]"
+            "[ ]([A-Za-z]{3,9})[ ]+([0-9]{1,2})[ ]"
             + "([0-9]{1,2}:[0-9][0-9]:[0-9][0-9])[ ]([0-9]{2,4})";
 
     /**
diff --git a/core/java/android/webkit/LoadListener.java b/core/java/android/webkit/LoadListener.java
index 5995121..5145e03 100644
--- a/core/java/android/webkit/LoadListener.java
+++ b/core/java/android/webkit/LoadListener.java
@@ -1211,8 +1211,17 @@
                 // mRequestHandle can be null when the request was satisfied
                 // by the cache, and the cache returned a redirect
                 if (mRequestHandle != null) {
-                    mRequestHandle.setupRedirect(mUrl, mStatusCode,
-                            mRequestHeaders);
+                    try {
+                        mRequestHandle.setupRedirect(mUrl, mStatusCode,
+                                mRequestHeaders);
+                    } catch(RuntimeException e) {
+                        Log.e(LOGTAG, e.getMessage());
+                        // Signal a bad url error if we could not load the
+                        // redirection.
+                        handleError(EventHandler.ERROR_BAD_URL,
+                                mContext.getString(R.string.httpErrorBadUrl));
+                        return;
+                    }
                 } else {
                     // If the original request came from the cache, there is no
                     // RequestHandle, we have to create a new one through
diff --git a/core/java/android/webkit/Network.java b/core/java/android/webkit/Network.java
index af0cb1e..b53e404 100644
--- a/core/java/android/webkit/Network.java
+++ b/core/java/android/webkit/Network.java
@@ -180,20 +180,24 @@
         }
 
         RequestQueue q = mRequestQueue;
+        RequestHandle handle = null;
         if (loader.isSynchronous()) {
-            q = new RequestQueue(loader.getContext(), 1);
-        }
-
-        RequestHandle handle = q.queueRequest(
-                url, loader.getWebAddress(), method, headers, loader,
-                bodyProvider, bodyLength);
-        loader.attachRequestHandle(handle);
-
-        if (loader.isSynchronous()) {
-            handle.waitUntilComplete();
+            handle = q.queueSynchronousRequest(url, loader.getWebAddress(),
+                    method, headers, loader, bodyProvider, bodyLength);
+            loader.attachRequestHandle(handle);
+            handle.processRequest();
             loader.loadSynchronousMessages();
-            q.shutdown();
+        } else {
+            handle = q.queueRequest(url, loader.getWebAddress(), method,
+                    headers, loader, bodyProvider, bodyLength);
+            // FIXME: Although this is probably a rare condition, normal network
+            // requests are processed in a separate thread. This means that it
+            // is possible to process part of the request before setting the
+            // request handle on the loader. We should probably refactor this to
+            // ensure the handle is attached before processing begins.
+            loader.attachRequestHandle(handle);
         }
+
         return true;
     }
 
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 4fedec9..79d8c03 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -1007,7 +1007,8 @@
      *     should never be null.
      */
     public synchronized void setGeolocationDatabasePath(String databasePath) {
-        if (databasePath != null && !databasePath.equals(mDatabasePath)) {
+        if (databasePath != null
+                && !databasePath.equals(mGeolocationDatabasePath)) {
             mGeolocationDatabasePath = databasePath;
             postSync();
         }
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 4bc1a0e..a1590af 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2836,6 +2836,21 @@
      */
     private boolean mNeedToAdjustWebTextView;
 
+    private boolean didUpdateTextViewBounds(boolean allowIntersect) {
+        Rect contentBounds = nativeFocusCandidateNodeBounds();
+        Rect vBox = contentToViewRect(contentBounds);
+        Rect visibleRect = new Rect();
+        calcOurVisibleRect(visibleRect);
+        if (allowIntersect ? Rect.intersects(visibleRect, vBox) :
+                visibleRect.contains(vBox)) {
+            mWebTextView.setRect(vBox.left, vBox.top, vBox.width(),
+                    vBox.height());
+            return true;
+        } else {
+            return false;
+        }
+    }
+
     private void drawCoreAndCursorRing(Canvas canvas, int color,
         boolean drawCursorRing) {
         if (mDrawHistory) {
@@ -2863,19 +2878,13 @@
                 invalidate();
                 if (mNeedToAdjustWebTextView) {
                     mNeedToAdjustWebTextView = false;
-                    Rect contentBounds = nativeFocusCandidateNodeBounds();
-                    Rect vBox = contentToViewRect(contentBounds);
-                    Rect visibleRect = new Rect();
-                    calcOurVisibleRect(visibleRect);
-                    if (visibleRect.contains(vBox)) {
-                        // As a result of the zoom, the textfield is now on
-                        // screen.  Place the WebTextView in its new place,
-                        // accounting for our new scroll/zoom values.
+                    // As a result of the zoom, the textfield is now on
+                    // screen.  Place the WebTextView in its new place,
+                    // accounting for our new scroll/zoom values.
+                    if (didUpdateTextViewBounds(false)) {
                         mWebTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
                                 contentToViewDimension(
                                 nativeFocusCandidateTextSize()));
-                        mWebTextView.setRect(vBox.left, vBox.top, vBox.width(),
-                                vBox.height());
                         // If it is a password field, start drawing the
                         // WebTextView once again.
                         if (nativeFocusCandidateIsPassword()) {
@@ -2951,6 +2960,10 @@
         if (mFindIsUp && !animateScroll) {
             nativeDrawMatches(canvas);
         }
+        if (mFocusSizeChanged) {
+            mFocusSizeChanged = false;
+            didUpdateTextViewBounds(true);
+        }
     }
 
     // draw history
@@ -3316,7 +3329,9 @@
             // our view system's notion of focus
             rebuildWebTextView();
             // Now we need to pass the event to it
-            return mWebTextView.onKeyDown(keyCode, event);
+            if (inEditingMode()) {
+                return mWebTextView.onKeyDown(keyCode, event);
+            }
         } else if (nativeHasFocusNode()) {
             // In this case, the cursor is not on a text input, but the focus
             // might be.  Check it, and if so, hand over to the WebTextView.
@@ -4037,6 +4052,7 @@
     private static final int SELECT_CURSOR_OFFSET = 16;
     private int mSelectX = 0;
     private int mSelectY = 0;
+    private boolean mFocusSizeChanged = false;
     private boolean mShiftIsPressed = false;
     private boolean mTrackballDown = false;
     private long mTrackballUpTime = 0;
@@ -5035,6 +5051,9 @@
                                     / mZoomOverviewWidth, false);
                         }
                     }
+                    if (draw.mFocusSizeChanged && inEditingMode()) {
+                        mFocusSizeChanged = true;
+                    }
                     break;
                 }
                 case WEBCORE_INITIALIZED_MSG_ID:
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 86685fb..dbc42ca 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -422,6 +422,8 @@
      */
     private native boolean nativeRecordContent(Region invalRegion, Point wh);
 
+    private native boolean nativeFocusBoundsChanged();
+
     /**
      * Splits slow parts of the picture set. Called from the webkit
      * thread after nativeDrawContent returns true.
@@ -1593,6 +1595,7 @@
         int mMinPrefWidth;
         RestoreState mRestoreState; // only non-null if it is for the first
                                     // picture set after the first layout
+        boolean mFocusSizeChanged;
     }
 
     private void webkitDraw() {
@@ -1607,6 +1610,7 @@
         if (mWebView != null) {
             // Send the native view size that was used during the most recent
             // layout.
+            draw.mFocusSizeChanged = nativeFocusBoundsChanged();
             draw.mViewPoint = new Point(mCurrentViewWidth, mCurrentViewHeight);
             if (mSettings.getUseWideViewPort()) {
                 draw.mMinPrefWidth = Math.max(
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 165794a..5991ad4 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -3560,6 +3560,7 @@
             // into the scrap heap
             int viewType = lp.viewType;
             if (!shouldRecycleViewType(viewType)) {
+                removeDetachedView(scrap, false);
                 return;
             }
 
diff --git a/core/res/assets/images/combobox-disabled.png b/core/res/assets/images/combobox-disabled.png
index 42fc0c5..fe220e4 100644
--- a/core/res/assets/images/combobox-disabled.png
+++ b/core/res/assets/images/combobox-disabled.png
Binary files differ
diff --git a/core/res/assets/images/combobox-noHighlight.png b/core/res/assets/images/combobox-noHighlight.png
index 838dc65..abcdf72 100644
--- a/core/res/assets/images/combobox-noHighlight.png
+++ b/core/res/assets/images/combobox-noHighlight.png
Binary files differ
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 0bd0469..e2059d8 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -111,7 +111,8 @@
     <string name="httpErrorFile" msgid="8250549644091165175">"No se ha podido acceder al archivo."</string>
     <string name="httpErrorFileNotFound" msgid="5588380756326017105">"No se ha encontrado el archivo solicitado."</string>
     <string name="httpErrorTooManyRequests" msgid="1235396927087188253">"Se están procesando demasiadas solicitudes. Vuelve a intentarlo más tarde."</string>
-    <string name="notification_title" msgid="1259940370369187045">"Error al iniciar la sesión de <xliff:g id="ACCOUNT">%1$s</xliff:g>"</string>
+    <!-- no translation found for notification_title (1259940370369187045) -->
+    <skip />
     <string name="contentServiceSync" msgid="8353523060269335667">"Sincronización"</string>
     <string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Sincronización"</string>
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Demasiadas eliminaciones de <xliff:g id="CONTENT_TYPE">%s</xliff:g>"</string>
@@ -147,8 +148,8 @@
     <string name="permgroupdesc_location" msgid="2430258821648348660">"Controla tu ubicación física"</string>
     <string name="permgrouplab_network" msgid="5808983377727109831">"Comunicación de red"</string>
     <string name="permgroupdesc_network" msgid="5035763698958415998">"Admite aplicaciones que acceden a varias funciones de red."</string>
-    <string name="permgrouplab_accounts" msgid="3359646291125325519">"Tus cuentas"</string>
-    <string name="permgroupdesc_accounts" msgid="4948732641827091312">"Acceder a las cuentas disponibles."</string>
+    <string name="permgrouplab_accounts" msgid="7140261692496314430">"Tus cuentas de Google"</string>
+    <string name="permgroupdesc_accounts" msgid="6735915929704895193">"Acceder a las cuentas disponibles de Google."</string>
     <string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Controles de hardware"</string>
     <string name="permgroupdesc_hardwareControls" msgid="4357057861225462702">"Acceso directo al hardware en el teléfono."</string>
     <string name="permgrouplab_phoneCalls" msgid="9067173988325865923">"Llamadas telefónicas"</string>
@@ -432,59 +433,6 @@
     <item msgid="2506857312718630823">"ICQ"</item>
     <item msgid="1648797903785279353">"Jabber"</item>
   </string-array>
-    <string name="phoneTypeCustom" msgid="1644738059053355820">"Personalizado"</string>
-    <string name="phoneTypeHome" msgid="2570923463033985887">"Página principal"</string>
-    <string name="phoneTypeMobile" msgid="6501463557754751037">"Celular"</string>
-    <string name="phoneTypeWork" msgid="8863939667059911633">"Trabajo"</string>
-    <string name="phoneTypeFaxWork" msgid="3517792160008890912">"Fax laboral"</string>
-    <string name="phoneTypeFaxHome" msgid="2067265972322971467">"Fax personal"</string>
-    <string name="phoneTypePager" msgid="7582359955394921732">"Localizador"</string>
-    <string name="phoneTypeOther" msgid="1544425847868765990">"Otro"</string>
-    <string name="phoneTypeCallback" msgid="2712175203065678206">"Devolución de llamada"</string>
-    <string name="phoneTypeCar" msgid="8738360689616716982">"Automóvil"</string>
-    <string name="phoneTypeCompanyMain" msgid="540434356461478916">"Empresa principal"</string>
-    <string name="phoneTypeIsdn" msgid="8022453193171370337">"ISDN"</string>
-    <string name="phoneTypeMain" msgid="6766137010628326916">"Principal"</string>
-    <string name="phoneTypeOtherFax" msgid="8587657145072446565">"Otro fax"</string>
-    <string name="phoneTypeRadio" msgid="4093738079908667513">"Radio"</string>
-    <string name="phoneTypeTelex" msgid="3367879952476250512">"Télex"</string>
-    <string name="phoneTypeTtyTdd" msgid="8606514378585000044">"TTY TDD"</string>
-    <string name="phoneTypeWorkMobile" msgid="1311426989184065709">"Celular del trabajo"</string>
-    <string name="phoneTypeWorkPager" msgid="649938731231157056">"Localizador del trabajo"</string>
-    <string name="phoneTypeAssistant" msgid="5596772636128562884">"Asistente"</string>
-    <string name="phoneTypeMms" msgid="7254492275502768992">"MMS"</string>
-    <string name="eventTypeBirthday" msgid="2813379844211390740">"Cumpleaños"</string>
-    <string name="eventTypeAnniversary" msgid="3876779744518284000">"Aniversario"</string>
-    <string name="eventTypeOther" msgid="5834288791948564594">"Evento"</string>
-    <string name="emailTypeCustom" msgid="8525960257804213846">"Personalizado"</string>
-    <string name="emailTypeHome" msgid="449227236140433919">"Página principal"</string>
-    <string name="emailTypeWork" msgid="3548058059601149973">"Trabajo"</string>
-    <string name="emailTypeOther" msgid="2923008695272639549">"Otro"</string>
-    <string name="emailTypeMobile" msgid="119919005321166205">"Celular"</string>
-    <string name="postalTypeCustom" msgid="8903206903060479902">"Personalizado"</string>
-    <string name="postalTypeHome" msgid="8165756977184483097">"Página principal"</string>
-    <string name="postalTypeWork" msgid="5268172772387694495">"Trabajo"</string>
-    <string name="postalTypeOther" msgid="2726111966623584341">"Otro"</string>
-    <string name="imTypeCustom" msgid="2074028755527826046">"Personalizado"</string>
-    <string name="imTypeHome" msgid="6241181032954263892">"Página principal"</string>
-    <string name="imTypeWork" msgid="1371489290242433090">"Trabajo"</string>
-    <string name="imTypeOther" msgid="5377007495735915478">"Otro"</string>
-    <string name="imProtocolCustom" msgid="6919453836618749992">"Personalizado"</string>
-    <string name="imProtocolAim" msgid="7050360612368383417">"AIM"</string>
-    <string name="imProtocolMsn" msgid="144556545420769442">"Windows Live"</string>
-    <string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
-    <string name="imProtocolSkype" msgid="9019296744622832951">"Skype"</string>
-    <string name="imProtocolQq" msgid="8887484379494111884">"QQ"</string>
-    <string name="imProtocolGoogleTalk" msgid="3808393979157698766">"Google Talk"</string>
-    <string name="imProtocolIcq" msgid="1574870433606517315">"ICQ"</string>
-    <string name="imProtocolJabber" msgid="2279917630875771722">"Jabber"</string>
-    <string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
-    <string name="orgTypeWork" msgid="29268870505363872">"Trabajo"</string>
-    <string name="orgTypeOther" msgid="3951781131570124082">"Otro"</string>
-    <string name="orgTypeCustom" msgid="225523415372088322">"Personalizado"</string>
-    <!-- no translation found for contact_status_update_attribution (5112589886094402795) -->
-    <skip />
-    <string name="contact_status_update_attribution_with_date" msgid="5945386376369979909">"<xliff:g id="DATE">%1$s</xliff:g> a través de <xliff:g id="SOURCE">%2$s</xliff:g>"</string>
     <string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Ingresar el código de PIN"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"¡Código de PIN incorrecto!"</string>
     <string name="keyguard_label_text" msgid="861796461028298424">"Para desbloquear, presiona el menú y luego 0."</string>
@@ -499,7 +447,6 @@
     <string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"Lo sentimos, vuelve a intentarlo"</string>
     <string name="lockscreen_plugged_in" msgid="613343852842944435">"Cargando (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
     <string name="lockscreen_charged" msgid="4938930459620989972">"Cargada."</string>
-    <string name="lockscreen_battery_short" msgid="3617549178603354656">"Segmento <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
     <string name="lockscreen_low_battery" msgid="1482873981919249740">"Conecta tu cargador."</string>
     <string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"No hay tarjeta SIM."</string>
     <string name="lockscreen_missing_sim_message" msgid="2186920585695169078">"No hay tarjeta SIM en el teléfono."</string>
@@ -531,7 +478,7 @@
     <string name="battery_status_charging" msgid="756617993998772213">"Cargando..."</string>
     <string name="battery_low_title" msgid="7923774589611311406">"Conecta el cargador"</string>
     <string name="battery_low_subtitle" msgid="7388781709819722764">"Hay poca batería:"</string>
-    <string name="battery_low_percent_format" msgid="696154104579022959">"Restan <xliff:g id="NUMBER">%d%%</xliff:g> o menos."</string>
+    <string name="battery_low_percent_format" msgid="6564958083485073855">"menos de <xliff:g id="NUMBER">%d%%</xliff:g> restante."</string>
     <string name="battery_low_why" msgid="7279169609518386372">"Uso de la batería"</string>
     <string name="factorytest_failed" msgid="5410270329114212041">"Error en la prueba de fábrica"</string>
     <string name="factorytest_not_system" msgid="4435201656767276723">"La acción FACTORY_TEST se admite solamente en paquetes instalados en /system/app."</string>
@@ -541,7 +488,6 @@
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
     <string name="js_dialog_before_unload" msgid="1901675448179653089">"¿Deseas salir de esta página?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Selecciona Aceptar para continuar o Cancelar para permanecer en la página actual."</string>
     <string name="save_password_label" msgid="6860261758665825069">"Confirmar"</string>
-    <string name="double_tap_toast" msgid="1068216937244567247">"Sugerencia: presiona dos veces para acercar y alejar"</string>
     <string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"leer historial y marcadores del navegador"</string>
     <string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Permite a la aplicación leer todas las URL que ha visitado el navegador y todos los marcadores del navegador."</string>
     <string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"escribir historial y marcadores del navegador"</string>
@@ -746,8 +692,10 @@
     <string name="extmedia_format_message" msgid="3621369962433523619">"¿Estás seguro de que quieres formatear la tarjeta SD? Se perderán todos los datos de tu tarjeta."</string>
     <string name="extmedia_format_button_format" msgid="4131064560127478695">"Formato"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Depuración de USB conectada"</string>
-    <string name="adb_active_notification_message" msgid="8470296818270110396">"Seleccionar para desactivar la depuración de USB."</string>
-    <string name="select_input_method" msgid="6865512749462072765">"Seleccionar método de entrada"</string>
+    <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
+    <skip />
+    <!-- no translation found for select_input_method (6865512749462072765) -->
+    <skip />
     <string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
     <string name="candidates_style" msgid="4333913089637062257"><u>"candidatos"</u></string>
@@ -783,14 +731,11 @@
     <string name="allow" msgid="7225948811296386551">"Permitir"</string>
     <string name="deny" msgid="2081879885755434506">"Denegar"</string>
     <string name="permission_request_notification_title" msgid="5390555465778213840">"Permiso solicitado"</string>
-    <string name="permission_request_notification_with_subtitle" msgid="4325409589686688000">"Permiso solicitado"\n"para la cuenta <xliff:g id="ACCOUNT">%s</xliff:g>"</string>
+    <!-- no translation found for permission_request_notification_with_subtitle (4325409589686688000) -->
+    <skip />
     <string name="input_method_binding_label" msgid="1283557179944992649">"Método de entrada"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"Sincronización"</string>
     <string name="accessibility_binding_label" msgid="4148120742096474641">"Accesibilidad"</string>
     <string name="wallpaper_binding_label" msgid="1240087844304687662">"Papel tapiz"</string>
     <string name="chooser_wallpaper" msgid="7873476199295190279">"Cambiar fondo de pantalla"</string>
-    <string name="pptp_vpn_description" msgid="2688045385181439401">"Protocolo de túnel punto a punto"</string>
-    <string name="l2tp_vpn_description" msgid="3750692169378923304">"Protocolo de túnel de nivel 2"</string>
-    <string name="l2tp_ipsec_psk_vpn_description" msgid="3945043564008303239">"Clave previamente compartida según L2TP/IPSec VPN"</string>
-    <string name="l2tp_ipsec_crt_vpn_description" msgid="5382714073103653577">"Certificado según L2TP/IPSec VPN"</string>
 </resources>
diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
index e80d8aa..1713324 100644
--- a/media/java/android/media/Ringtone.java
+++ b/media/java/android/media/Ringtone.java
@@ -137,11 +137,17 @@
                     cursor = res.query(uri, MEDIA_COLUMNS, null, null, null);
                 }
                 
-                if (cursor != null && cursor.getCount() == 1) {
-                    cursor.moveToFirst();
-                    return cursor.getString(2);
-                } else {
-                    title = uri.getLastPathSegment();
+                try {
+                    if (cursor != null && cursor.getCount() == 1) {
+                        cursor.moveToFirst();
+                        return cursor.getString(2);
+                    } else {
+                        title = uri.getLastPathSegment();
+                    }
+                } finally {
+                    if (cursor != null) {
+                        cursor.close();
+                    }
                 }
             }
         }
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index c4c6149..cd9c991 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -39,6 +39,8 @@
 
 namespace android {
 
+static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
+
 struct CodecInfo {
     const char *mime;
     const char *codec;
@@ -217,11 +219,6 @@
     if (!strcmp(componentName, "OMX.TI.AAC.decode")) {
         quirks |= kNeedsFlushBeforeDisable;
         quirks |= kRequiresFlushCompleteEmulation;
-
-        // The following is currently necessary for proper shutdown
-        // behaviour, but NOT enabled by default in order to make the
-        // bug reproducible...
-        // quirks |= kRequiresFlushBeforeShutdown;
     }
     if (!strncmp(componentName, "OMX.qcom.video.encoder.", 23)) {
         quirks |= kRequiresLoadedToIdleAfterAllocation;
@@ -2017,8 +2014,6 @@
 
     size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
 
-    static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
-
     if (type == OMX_QCOM_COLOR_FormatYVU420SemiPlanar) {
         return "OMX_QCOM_COLOR_FormatYVU420SemiPlanar";
     } else if (type < 0 || (size_t)type >= numNames) {
diff --git a/opengl/tests/gl2_jni/src/com/android/gl2jni/GL2JNIView.java b/opengl/tests/gl2_jni/src/com/android/gl2jni/GL2JNIView.java
index 2dae090..72b1dfb 100644
--- a/opengl/tests/gl2_jni/src/com/android/gl2jni/GL2JNIView.java
+++ b/opengl/tests/gl2_jni/src/com/android/gl2jni/GL2JNIView.java
@@ -56,19 +56,22 @@
  */
 class GL2JNIView extends GLSurfaceView {
     private static String TAG = "GL2JNIView";
-    GL2JNIView(Context context) {
+
+    public GL2JNIView(Context context) {
         super(context);
-        init();
+        init(false, 0, 0);
     }
 
-    public GL2JNIView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        init();
+    public GL2JNIView(Context context, boolean translucent, int depth, int stencil) {
+        super(context);
+        init(translucent, depth, stencil);
     }
 
-    private void init() {
+    private void init(boolean translucent, int depth, int stencil) {
         setEGLContextFactory(new ContextFactory());
-        setEGLConfigChooser(new ConfigChooser());
+        setEGLConfigChooser( translucent ?
+              new ConfigChooser(8,8,8,8, depth, stencil) :
+              new ConfigChooser(5,6,5,0, depth, stencil));
         setRenderer(new Renderer());
     }
 
@@ -105,6 +108,16 @@
             EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
             EGL10.EGL_NONE
         };
+
+        public ConfigChooser(int r, int g, int b, int a, int depth, int stencil) {
+            mRedSize = r;
+            mGreenSize = g;
+            mBlueSize = b;
+            mAlphaSize = a;
+            mDepthSize = depth;
+            mStencilSize = stencil;
+        }
+
         public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
 
             int[] num_config = new int[1];
@@ -112,14 +125,158 @@
 
             int numConfigs = num_config[0];
 
-            Log.w(TAG, String.format("Found %d configurations", numConfigs));
             if (numConfigs <= 0) {
                 throw new IllegalArgumentException("No configs match configSpec");
             }
             EGLConfig[] configs = new EGLConfig[numConfigs];
             egl.eglChooseConfig(display, s_configAttribs2, configs, numConfigs, num_config);
-            return configs[0];
+            // printConfigs(egl, display, configs);
+            return chooseConfig(egl, display, configs);
         }
+
+        public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
+                EGLConfig[] configs) {
+            EGLConfig closestConfig = null;
+            int closestDistance = 1000;
+            for(EGLConfig config : configs) {
+                int d = findConfigAttrib(egl, display, config,
+                        EGL10.EGL_DEPTH_SIZE, 0);
+                int s = findConfigAttrib(egl, display, config,
+                        EGL10.EGL_STENCIL_SIZE, 0);
+                if (d >= mDepthSize && s>= mStencilSize) {
+                    int r = findConfigAttrib(egl, display, config,
+                            EGL10.EGL_RED_SIZE, 0);
+                    int g = findConfigAttrib(egl, display, config,
+                             EGL10.EGL_GREEN_SIZE, 0);
+                    int b = findConfigAttrib(egl, display, config,
+                              EGL10.EGL_BLUE_SIZE, 0);
+                    int a = findConfigAttrib(egl, display, config,
+                            EGL10.EGL_ALPHA_SIZE, 0);
+                    int distance = Math.abs(r - mRedSize)
+                                + Math.abs(g - mGreenSize)
+                                + Math.abs(b - mBlueSize)
+                                + Math.abs(a - mAlphaSize);
+                    if (distance < closestDistance) {
+                        closestDistance = distance;
+                        closestConfig = config;
+                    }
+                }
+            }
+            return closestConfig;
+        }
+
+        private int findConfigAttrib(EGL10 egl, EGLDisplay display,
+                EGLConfig config, int attribute, int defaultValue) {
+
+            if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) {
+                return mValue[0];
+            }
+            return defaultValue;
+        }
+
+        private void printConfigs(EGL10 egl, EGLDisplay display,
+            EGLConfig[] configs) {
+            int numConfigs = configs.length;
+            Log.w(TAG, String.format("%d configurations", numConfigs));
+            for (int i = 0; i < numConfigs; i++) {
+                Log.w(TAG, String.format("Configuration %d:\n", i));
+                printConfig(egl, display, configs[i]);
+            }
+        }
+
+        private void printConfig(EGL10 egl, EGLDisplay display,
+                EGLConfig config) {
+            int[] attributes = {
+                    EGL10.EGL_BUFFER_SIZE,
+                    EGL10.EGL_ALPHA_SIZE,
+                    EGL10.EGL_BLUE_SIZE,
+                    EGL10.EGL_GREEN_SIZE,
+                    EGL10.EGL_RED_SIZE,
+                    EGL10.EGL_DEPTH_SIZE,
+                    EGL10.EGL_STENCIL_SIZE,
+                    EGL10.EGL_CONFIG_CAVEAT,
+                    EGL10.EGL_CONFIG_ID,
+                    EGL10.EGL_LEVEL,
+                    EGL10.EGL_MAX_PBUFFER_HEIGHT,
+                    EGL10.EGL_MAX_PBUFFER_PIXELS,
+                    EGL10.EGL_MAX_PBUFFER_WIDTH,
+                    EGL10.EGL_NATIVE_RENDERABLE,
+                    EGL10.EGL_NATIVE_VISUAL_ID,
+                    EGL10.EGL_NATIVE_VISUAL_TYPE,
+                    0x3030, // EGL10.EGL_PRESERVED_RESOURCES,
+                    EGL10.EGL_SAMPLES,
+                    EGL10.EGL_SAMPLE_BUFFERS,
+                    EGL10.EGL_SURFACE_TYPE,
+                    EGL10.EGL_TRANSPARENT_TYPE,
+                    EGL10.EGL_TRANSPARENT_RED_VALUE,
+                    EGL10.EGL_TRANSPARENT_GREEN_VALUE,
+                    EGL10.EGL_TRANSPARENT_BLUE_VALUE,
+                    0x3039, // EGL10.EGL_BIND_TO_TEXTURE_RGB,
+                    0x303A, // EGL10.EGL_BIND_TO_TEXTURE_RGBA,
+                    0x303B, // EGL10.EGL_MIN_SWAP_INTERVAL,
+                    0x303C, // EGL10.EGL_MAX_SWAP_INTERVAL,
+                    EGL10.EGL_LUMINANCE_SIZE,
+                    EGL10.EGL_ALPHA_MASK_SIZE,
+                    EGL10.EGL_COLOR_BUFFER_TYPE,
+                    EGL10.EGL_RENDERABLE_TYPE,
+                    0x3042 // EGL10.EGL_CONFORMANT
+            };
+            String[] names = {
+                    "EGL_BUFFER_SIZE",
+                    "EGL_ALPHA_SIZE",
+                    "EGL_BLUE_SIZE",
+                    "EGL_GREEN_SIZE",
+                    "EGL_RED_SIZE",
+                    "EGL_DEPTH_SIZE",
+                    "EGL_STENCIL_SIZE",
+                    "EGL_CONFIG_CAVEAT",
+                    "EGL_CONFIG_ID",
+                    "EGL_LEVEL",
+                    "EGL_MAX_PBUFFER_HEIGHT",
+                    "EGL_MAX_PBUFFER_PIXELS",
+                    "EGL_MAX_PBUFFER_WIDTH",
+                    "EGL_NATIVE_RENDERABLE",
+                    "EGL_NATIVE_VISUAL_ID",
+                    "EGL_NATIVE_VISUAL_TYPE",
+                    "EGL_PRESERVED_RESOURCES",
+                    "EGL_SAMPLES",
+                    "EGL_SAMPLE_BUFFERS",
+                    "EGL_SURFACE_TYPE",
+                    "EGL_TRANSPARENT_TYPE",
+                    "EGL_TRANSPARENT_RED_VALUE",
+                    "EGL_TRANSPARENT_GREEN_VALUE",
+                    "EGL_TRANSPARENT_BLUE_VALUE",
+                    "EGL_BIND_TO_TEXTURE_RGB",
+                    "EGL_BIND_TO_TEXTURE_RGBA",
+                    "EGL_MIN_SWAP_INTERVAL",
+                    "EGL_MAX_SWAP_INTERVAL",
+                    "EGL_LUMINANCE_SIZE",
+                    "EGL_ALPHA_MASK_SIZE",
+                    "EGL_COLOR_BUFFER_TYPE",
+                    "EGL_RENDERABLE_TYPE",
+                    "EGL_CONFORMANT"
+            };
+            int[] value = new int[1];
+            for (int i = 0; i < attributes.length; i++) {
+                int attribute = attributes[i];
+                String name = names[i];
+                if ( egl.eglGetConfigAttrib(display, config, attribute, value)) {
+                    Log.w(TAG, String.format("  %s: %d\n", name, value[0]));
+                } else {
+                    // Log.w(TAG, String.format("  %s: failed\n", name));
+                    while (egl.eglGetError() != EGL10.EGL_SUCCESS);
+                }
+            }
+        }
+
+        // Subclasses can adjust these values:
+        protected int mRedSize;
+        protected int mGreenSize;
+        protected int mBlueSize;
+        protected int mAlphaSize;
+        protected int mDepthSize;
+        protected int mStencilSize;
+        private int[] mValue = new int[1];
     }
 
     private static class Renderer implements GLSurfaceView.Renderer {
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 78215b0..a91635e 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -572,6 +572,8 @@
 
     // javadoc from interface
     public int stopUsingNetworkFeature(int networkType, String feature) {
+        enforceChangePermission();
+
         int pid = getCallingPid();
         int uid = getCallingUid();
 
@@ -611,7 +613,7 @@
             Log.d(TAG, "stopUsingNetworkFeature for net " + networkType +
                     ": " + feature);
         }
-        enforceChangePermission();
+
         if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
             return -1;
         }