Merge "Setting the synth busy flag inside a synchronized block for thread safety."
diff --git a/common/Android.mk b/common/Android.mk
index 76091eb..5c5b01b 100644
--- a/common/Android.mk
+++ b/common/Android.mk
@@ -19,6 +19,7 @@
 
 include $(CLEAR_VARS)
 LOCAL_MODULE := android-common
+LOCAL_SDK_VERSION := current
 LOCAL_SRC_FILES := $(call all-java-files-under, java)
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
diff --git a/common/java/com/android/common/AndroidHttpClient.java b/common/java/com/android/common/AndroidHttpClient.java
index 99faf6e..4c65eb0 100644
--- a/common/java/com/android/common/AndroidHttpClient.java
+++ b/common/java/com/android/common/AndroidHttpClient.java
@@ -47,8 +47,6 @@
 import org.apache.http.protocol.BasicHttpProcessor;
 import org.apache.http.protocol.HttpContext;
 import org.apache.http.protocol.BasicHttpContext;
-import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
-import org.apache.harmony.xnet.provider.jsse.SSLContextImpl;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -59,11 +57,11 @@
 import java.net.URI;
 import java.security.KeyManagementException;
 
+import android.content.Context;
 import android.content.ContentResolver;
+import android.net.SSLCertificateSocketFactory;
+import android.net.SSLSessionCache;
 import android.os.Looper;
-import android.os.SystemProperties;
-import android.provider.Settings;
-import android.text.TextUtils;
 import android.util.Log;
 
 /**
@@ -76,11 +74,9 @@
  * To retain cookies, simply add a cookie store to the HttpContext:</p>
  *
  * <pre>context.setAttribute(ClientContext.COOKIE_STORE, cookieStore);</pre>
- * 
- * {@hide}
  */
 public final class AndroidHttpClient implements HttpClient {
-        
+
     // Gzip of data shorter than this probably won't be worthwhile
     public static long DEFAULT_SYNC_MIN_GZIP_BYTES = 256;
 
@@ -101,12 +97,11 @@
     /**
      * Create a new HttpClient with reasonable defaults (which you can update).
      *
-     * @param userAgent to report in your HTTP requests.
-     * @param sessionCache persistent session cache
+     * @param userAgent to report in your HTTP requests
+     * @param context to use for caching SSL sessions (may be null for no caching)
      * @return AndroidHttpClient for you to use for all your requests.
      */
-    public static AndroidHttpClient newInstance(String userAgent,
-            SSLClientSessionCache sessionCache) {
+    public static AndroidHttpClient newInstance(String userAgent, Context context) {
         HttpParams params = new BasicHttpParams();
 
         // Turn off stale checking.  Our connections break all the time anyway,
@@ -122,13 +117,16 @@
         // often wants to re-POST after a redirect, which we must do ourselves.
         HttpClientParams.setRedirecting(params, false);
 
+        // Use a session cache for SSL sockets
+        SSLSessionCache sessionCache = context == null ? null : new SSLSessionCache(context);
+
         // Set the specified user agent and register standard protocols.
         HttpProtocolParams.setUserAgent(params, userAgent);
         SchemeRegistry schemeRegistry = new SchemeRegistry();
         schemeRegistry.register(new Scheme("http",
                 PlainSocketFactory.getSocketFactory(), 80));
         schemeRegistry.register(new Scheme("https",
-                socketFactoryWithCache(sessionCache), 443));
+                SSLCertificateSocketFactory.getHttpSocketFactory(30 * 1000, sessionCache), 443));
 
         ClientConnectionManager manager =
                 new ThreadSafeClientConnManager(params, schemeRegistry);
@@ -139,32 +137,6 @@
     }
 
     /**
-     * Returns a socket factory backed by the given persistent session cache.
-     *
-     * @param sessionCache to retrieve sessions from, null for no cache
-     */
-    private static SSLSocketFactory socketFactoryWithCache(
-            SSLClientSessionCache sessionCache) {
-        if (sessionCache == null) {
-            // Use the default factory which doesn't support persistent
-            // caching.
-            return SSLSocketFactory.getSocketFactory();
-        }
-
-        // Create a new SSL context backed by the cache.
-        // TODO: Keep a weak *identity* hash map of caches to engines. In the
-        // mean time, if we have two engines for the same cache, they'll still
-        // share sessions but will have to do so through the persistent cache.
-        SSLContextImpl sslContext = new SSLContextImpl();
-        try {
-            sslContext.engineInit(null, null, null, sessionCache, null);
-        } catch (KeyManagementException e) {
-            throw new AssertionError(e);
-        }
-        return new SSLSocketFactory(sslContext.engineGetSocketFactory());
-    }
-
-    /**
      * Create a new HttpClient with reasonable defaults (which you can update).
      * @param userAgent to report in your HTTP requests.
      * @return AndroidHttpClient for you to use for all your requests.
@@ -339,9 +311,7 @@
      * Shorter data will not be compressed.
      */
     public static long getMinGzipSize(ContentResolver resolver) {
-        return Settings.Secure.getLong(resolver,
-                                       Settings.Secure.SYNC_MIN_GZIP_BYTES,
-                                       DEFAULT_SYNC_MIN_GZIP_BYTES);
+        return DEFAULT_SYNC_MIN_GZIP_BYTES;  // For now, this is just a constant.
     }
 
     /* cURL logging support. */
@@ -367,15 +337,6 @@
         }
 
         /**
-         * Returns true if auth logging is turned on for this configuration.  Can only be set on
-         * insecure devices.
-         */
-        private boolean isAuthLoggable() {
-            String secure = SystemProperties.get("ro.secure");
-            return "0".equals(secure) && Log.isLoggable(tag + "-auth", level);
-        }
-
-        /**
          * Prints a message using this configuration.
          */
         private void println(String message) {
@@ -421,8 +382,9 @@
             if (configuration != null
                     && configuration.isLoggable()
                     && request instanceof HttpUriRequest) {
-                configuration.println(toCurl((HttpUriRequest) request,
-                        configuration.isAuthLoggable()));
+                // Never print auth token -- we used to check ro.secure=0 to
+                // enable that, but can't do that in unbundled code.
+                configuration.println(toCurl((HttpUriRequest) request, false));
             }
         }
     }
diff --git a/common/java/com/android/common/ArrayListCursor.java b/common/java/com/android/common/ArrayListCursor.java
index cc1fe27..9ad5c36 100644
--- a/common/java/com/android/common/ArrayListCursor.java
+++ b/common/java/com/android/common/ArrayListCursor.java
@@ -115,11 +115,6 @@
     }
 
     @Override
-    public boolean deleteRow() {
-        return false;
-    }
-
-    @Override
     public String[] getColumnNames() {
         return mColumnNames;
     }
diff --git a/common/java/com/android/common/Base64.java b/common/java/com/android/common/Base64.java
index 771875c..772d567 100644
--- a/common/java/com/android/common/Base64.java
+++ b/common/java/com/android/common/Base64.java
@@ -51,6 +51,10 @@
      */
     public static final int WEB_SAFE = 8;
 
+    //  --------------------------------------------------------
+    //  decoding
+    //  --------------------------------------------------------
+
     /**
      * Lookup table for turning bytes into their position in the
      * Base64 alphabet.
@@ -155,18 +159,71 @@
      * incorrect padding
      */
     public static byte[] decode(byte[] input, int offset, int len, int flags) {
-        int p = offset;
         // Allocate space for the most data the input could represent.
         // (It could contain less if it contains whitespace, etc.)
-        byte[] output = new byte[len*3/4];
-        len += offset;
+        DecoderState state = new DecoderState(flags, new byte[len*3/4]);
+
+        if (!decodeInternal(input, offset, len, state, true)) {
+            throw new IllegalArgumentException("bad base-64");
+        }
+
+        // Maybe we got lucky and allocated exactly enough output space.
+        if (state.op == state.output.length) {
+            return state.output;
+        }
+
+        // Need to shorten the array, so allocate a new one of the
+        // right size and copy.
+        byte[] temp = new byte[state.op];
+        System.arraycopy(state.output, 0, temp, 0, state.op);
+        return temp;
+    }
+
+    /* package */ static class DecoderState {
+        public byte[] output;
+        public int op;
+
+        public int state;   // state number (0 to 6)
+        public int value;
+
+        final public int[] alphabet;
+
+        public DecoderState(int flags, byte[] output) {
+            this.output = output;
+
+            alphabet = ((flags & WEB_SAFE) == 0) ? DECODE : DECODE_WEBSAFE;
+            state = 0;
+            value = 0;
+        }
+    }
+
+    /**
+     * Decode another block of input data.
+     *
+     * @param dstate a DecoderState object whose (caller-provided)
+     *        output array is big enough to hold all the decoded data.
+     *        On return, dstate.op will be set to the length of the
+     *        decoded data.
+     * @param finish true if this is the final call to decodeInternal
+     *        with the given DecoderState object.  Will finalize the
+     *        decoder state and include any final bytes in the output.
+     *
+     * @return true if the state machine is still healthy.  false if
+     *         bad base-64 data has been detected in the input stream.
+     */
+
+    /* package */ static boolean decodeInternal(
+        byte[] input, int offset, int len, final DecoderState dstate, boolean finish) {
+        if (dstate.state == 6) return false;
+
+        int state = dstate.state;
+        int value = dstate.value;
+        final int[] decode = dstate.alphabet;
+        final byte[] output = dstate.output;
         int op = 0;
 
-        final int[] decode = ((flags & WEB_SAFE) == 0) ?
-            DECODE : DECODE_WEBSAFE;
-
-        int state = 0;
-        int value = 0;
+        int p = offset;
+        len += offset;
 
         while (p < len) {
 
@@ -207,6 +264,8 @@
             // one more.
             // State 5 is expecting no more data or padding characters
             // in the input.
+            // State 6 is the error state; an error has been detected
+            // in the input and no future input can "fix" it.
 
             int d = decode[input[p++] & 0xff];
 
@@ -216,7 +275,8 @@
                         value = d;
                         ++state;
                     } else if (d != SKIP) {
-                        throw new IllegalArgumentException("bad base-64");
+                        dstate.state = 6;
+                        return false;
                     }
                     break;
 
@@ -225,7 +285,8 @@
                         value = (value << 6) | d;
                         ++state;
                     } else if (d != SKIP) {
-                        throw new IllegalArgumentException("bad base-64");
+                        dstate.state = 6;
+                        return false;
                     }
                     break;
 
@@ -239,7 +300,8 @@
                         output[op++] = (byte) (value >> 4);
                         state = 4;
                     } else if (d != SKIP) {
-                        throw new IllegalArgumentException("bad base-64");
+                        dstate.state = 6;
+                        return false;
                     }
                     break;
 
@@ -260,7 +322,8 @@
                         op += 2;
                         state = 5;
                     } else if (d != SKIP) {
-                        throw new IllegalArgumentException("bad base-64");
+                        dstate.state = 6;
+                        return false;
                     }
                     break;
 
@@ -268,18 +331,30 @@
                     if (d == EQUALS) {
                         ++state;
                     } else if (d != SKIP) {
-                        throw new IllegalArgumentException("bad base-64");
+                        dstate.state = 6;
+                        return false;
                     }
                     break;
 
                 case 5:
                     if (d != SKIP) {
-                        throw new IllegalArgumentException("bad base-64");
+                        dstate.state = 6;
+                        return false;
                     }
                     break;
             }
         }
 
+        if (!finish) {
+            // We're out of input, but a future call could provide
+            // more.  Return the output we've produced on this call
+            // and save the current state of the state machine.
+            dstate.state = state;
+            dstate.value = value;
+            dstate.op = op;
+            return true;
+        }
+
         // Done reading input.  Now figure out where we are left in
         // the state machine and finish up.
 
@@ -290,7 +365,8 @@
             case 1:
                 // Read one extra input byte, which isn't enough to
                 // make another output byte.  Illegal.
-                throw new IllegalArgumentException("bad base-64");
+                dstate.state = 6;
+                return false;
             case 2:
                 // Read two extra input bytes, enough to emit 1 more
                 // output byte.  Fine.
@@ -305,25 +381,22 @@
                 break;
             case 4:
                 // Read one padding '=' when we expected 2.  Illegal.
-                throw new IllegalArgumentException("bad base-64");
+                dstate.state = 6;
+                return false;
             case 5:
                 // Read all the padding '='s we expected and no more.
                 // Fine.
                 break;
         }
 
-        // Maybe we got lucky and allocated exactly enough output space.
-        if (op == output.length) {
-            return output;
-        }
-
-        // Need to shorten the array, so allocate a new one of the
-        // right size and copy.
-        byte[] temp = new byte[op];
-        System.arraycopy(output, 0, temp, 0, op);
-        return temp;
+        dstate.op = op;
+        return true;
     }
 
+    //  --------------------------------------------------------
+    //  encoding
+    //  --------------------------------------------------------
+
     /**
      * Emit a new line every this many output tuples.  Corresponds to
      * a 76-character line length (the maximum allowable according to
@@ -416,17 +489,13 @@
      *               adheres to RFC 2045.
      */
     public static byte[] encode(byte[] input, int offset, int len, int flags) {
-        final boolean do_padding = (flags & NO_PADDING) == 0;
-        final boolean do_newline = (flags & NO_WRAP) == 0;
-        final boolean do_cr = (flags & CRLF) != 0;
-
-        final byte[] encode = ((flags & WEB_SAFE) == 0) ? ENCODE : ENCODE_WEBSAFE;
+        EncoderState state = new EncoderState(flags, null);
 
         // Compute the exact length of the array we will produce.
         int output_len = len / 3 * 4;
 
         // Account for the tail of the data and the padding bytes, if any.
-        if (do_padding) {
+        if (state.do_padding) {
             if (len % 3 > 0) {
                 output_len += 4;
             }
@@ -439,26 +508,107 @@
         }
 
         // Account for the newlines, if any.
-        if (do_newline && len > 0) {
-            output_len += (((len-1) / (3 * LINE_GROUPS)) + 1) * (do_cr ? 2 : 1);
+        if (state.do_newline && len > 0) {
+            output_len += (((len-1) / (3 * LINE_GROUPS)) + 1) * (state.do_cr ? 2 : 1);
         }
 
-        int op = 0;
-        byte[] output = new byte[output_len];
+        state.output = new byte[output_len];
+        encodeInternal(input, offset, len, state, true);
 
-        // The main loop, turning 3 input bytes into 4 output bytes on
-        // each iteration.
-        int count = do_newline ? LINE_GROUPS : -1;
+        assert state.op == output_len;
+
+        return state.output;
+    }
+
+    /* package */ static class EncoderState {
+        public byte[] output;
+        public int op;
+
+        final public byte[] tail;
+        public int tailLen;
+        public int count;
+
+        final public boolean do_padding;
+        final public boolean do_newline;
+        final public boolean do_cr;
+        final public byte[] alphabet;
+
+        public EncoderState(int flags, byte[] output) {
+            this.output = output;
+
+            do_padding = (flags & NO_PADDING) == 0;
+            do_newline = (flags & NO_WRAP) == 0;
+            do_cr = (flags & CRLF) != 0;
+            alphabet = ((flags & WEB_SAFE) == 0) ? ENCODE : ENCODE_WEBSAFE;
+
+            tail = new byte[2];
+            tailLen = 0;
+
+            count = do_newline ? LINE_GROUPS : -1;
+        }
+    }
+
+    /**
+     * Encode another block of input data.
+     *
+     * @param estate an EncoderState object whose (caller-provided)
+     *        output array is big enough to hold all the encoded data.
+     *        On return, estate.op will be set to the length of the
+     *        encoded data.
+     * @param finish true if this is the final call to encodeInternal
+     *        with the given EncoderState object.  Will finalize the
+     *        encoder state and include any final bytes in the output.
+     */
+    static void encodeInternal(byte[] input, int offset, int len,
+                               final EncoderState estate, boolean finish) {
+        final boolean do_cr = estate.do_cr;
+        final boolean do_newline = estate.do_newline;
+        final boolean do_padding = estate.do_padding;
+        final byte[] output = estate.output;
+
+        int op = 0;
+
         int p = offset;
         len += offset;
-        while (p+3 <= len) {
-            int v = ((input[p++] & 0xff) << 16) |
-                ((input[p++] & 0xff) << 8) |
-                (input[p++] & 0xff);
-            output[op++] = encode[(v >> 18) & 0x3f];
-            output[op++] = encode[(v >> 12) & 0x3f];
-            output[op++] = encode[(v >> 6) & 0x3f];
-            output[op++] = encode[v & 0x3f];
+        int v = -1;
+        int count = estate.count;
+
+        // First we need to concatenate the tail of the previous call
+        // with any input bytes available now and see if we can empty
+        // the tail.
+
+        switch (estate.tailLen) {
+            case 0:
+                // There was no tail.
+                break;
+
+            case 1:
+                if (p+2 <= len) {
+                    // A 1-byte tail with at least 2 bytes of
+                    // input available now.
+                    v = ((estate.tail[0] & 0xff) << 16) |
+                        ((input[p++] & 0xff) << 8) |
+                        (input[p++] & 0xff);
+                    estate.tailLen = 0;
+                };
+                break;
+
+            case 2:
+                if (p+1 <= len) {
+                    // A 2-byte tail with at least 1 byte of input.
+                    v = ((estate.tail[0] & 0xff) << 16) |
+                        ((estate.tail[1] & 0xff) << 8) |
+                        (input[p++] & 0xff);
+                    estate.tailLen = 0;
+                }
+                break;
+        }
+
+        if (v != -1) {
+            output[op++] = estate.alphabet[(v >> 18) & 0x3f];
+            output[op++] = estate.alphabet[(v >> 12) & 0x3f];
+            output[op++] = estate.alphabet[(v >> 6) & 0x3f];
+            output[op++] = estate.alphabet[v & 0x3f];
             if (--count == 0) {
                 if (do_cr) output[op++] = '\r';
                 output[op++] = '\n';
@@ -466,38 +616,82 @@
             }
         }
 
-        // Finish up the tail of the input.
-        if (p == len-1) {
-            int v = (input[p] & 0xff) << 4;
-            output[op++] = encode[(v >> 6) & 0x3f];
-            output[op++] = encode[v & 0x3f];
-            if (do_padding) {
-                output[op++] = '=';
-                output[op++] = '=';
-            }
-            if (do_newline) {
+        // At this point either there is no tail, or there are fewer
+        // than 3 bytes of input available.
+
+        // The main loop, turning 3 input bytes into 4 output bytes on
+        // each iteration.
+        while (p+3 <= len) {
+            v = ((input[p++] & 0xff) << 16) |
+                ((input[p++] & 0xff) << 8) |
+                (input[p++] & 0xff);
+            output[op++] = estate.alphabet[(v >> 18) & 0x3f];
+            output[op++] = estate.alphabet[(v >> 12) & 0x3f];
+            output[op++] = estate.alphabet[(v >> 6) & 0x3f];
+            output[op++] = estate.alphabet[v & 0x3f];
+            if (--count == 0) {
                 if (do_cr) output[op++] = '\r';
                 output[op++] = '\n';
+                count = LINE_GROUPS;
             }
-        } else if (p == len-2) {
-            int v = ((input[p] & 0xff) << 10) | ((input[p+1] & 0xff) << 2);
-            output[op++] = encode[(v >> 12) & 0x3f];
-            output[op++] = encode[(v >> 6) & 0x3f];
-            output[op++] = encode[v & 0x3f];
-            if (do_padding) {
-                output[op++] = '=';
-            }
-            if (do_newline) {
-                if (do_cr) output[op++] = '\r';
-                output[op++] = '\n';
-            }
-        } else if (do_newline && op > 0 && count != LINE_GROUPS) {
-            if (do_cr) output[op++] = '\r';
-            output[op++] = '\n';
         }
 
-        assert op == output.length;
-        return output;
+        if (finish) {
+            // Finish up the tail of the input.  Note that we need to
+            // consume any bytes in estate.tail before any bytes
+            // remaining in input; there should be at most two bytes
+            // total.
+
+            if (p-estate.tailLen == len-1) {
+                int t = 0;
+                v = ((estate.tailLen > 0 ? estate.tail[t++] : input[p++]) & 0xff) << 4;
+                estate.tailLen -= t;
+                output[op++] = estate.alphabet[(v >> 6) & 0x3f];
+                output[op++] = estate.alphabet[v & 0x3f];
+                if (do_padding) {
+                    output[op++] = '=';
+                    output[op++] = '=';
+                }
+                if (do_newline) {
+                    if (do_cr) output[op++] = '\r';
+                    output[op++] = '\n';
+                }
+            } else if (p-estate.tailLen == len-2) {
+                int t = 0;
+                v = (((estate.tailLen > 1 ? estate.tail[t++] : input[p++]) & 0xff) << 10) |
+                    (((estate.tailLen > 0 ? estate.tail[t++] : input[p++]) & 0xff) << 2);
+                estate.tailLen -= t;
+                output[op++] = estate.alphabet[(v >> 12) & 0x3f];
+                output[op++] = estate.alphabet[(v >> 6) & 0x3f];
+                output[op++] = estate.alphabet[v & 0x3f];
+                if (do_padding) {
+                    output[op++] = '=';
+                }
+                if (do_newline) {
+                    if (do_cr) output[op++] = '\r';
+                    output[op++] = '\n';
+                }
+            } else if (do_newline && op > 0 && count != LINE_GROUPS) {
+                if (do_cr) output[op++] = '\r';
+                output[op++] = '\n';
+            }
+
+            assert estate.tailLen == 0;
+            assert p == len;
+        } else {
+            // Save the leftovers in tail to be consumed on the next
+            // call to encodeInternal.
+
+            if (p == len-1) {
+                estate.tail[estate.tailLen++] = input[p];
+            } else if (p == len-2) {
+                estate.tail[estate.tailLen++] = input[p];
+                estate.tail[estate.tailLen++] = input[p+1];
+            }
+        }
+
+        estate.op = op;
+        estate.count = count;
     }
 
     private Base64() { }   // don't instantiate
diff --git a/common/java/com/android/common/Base64OutputStream.java b/common/java/com/android/common/Base64OutputStream.java
new file mode 100644
index 0000000..7c37428
--- /dev/null
+++ b/common/java/com/android/common/Base64OutputStream.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.common;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * An OutputStream that does either Base64 encoding or decoding on the
+ * data written to it, writing the resulting data to another
+ * OutputStream.
+ */
+public class Base64OutputStream extends FilterOutputStream {
+    private final boolean encode;
+    private final Base64.EncoderState estate;
+    private final Base64.DecoderState dstate;
+
+    private byte[] buffer = null;
+    private int bpos = 0;
+
+    private static byte[] EMPTY = new byte[0];
+
+    /**
+     * Performs Base64 encoding on the data written to the stream,
+     * writing the encoded data to another OutputStream.
+     *
+     * @param out the OutputStream to write the encoded data to
+     * @param flags bit flags for controlling the encoder; see the
+     *        constants in {@link Base64}
+     */
+    public Base64OutputStream(OutputStream out, int flags) {
+        this(out, flags, true);
+    }
+
+    /**
+     * Performs Base64 encoding or decoding on the data written to the
+     * stream, writing the encoded/decoded data to another
+     * OutputStream.
+     *
+     * @param out the OutputStream to write the encoded data to
+     * @param flags bit flags for controlling the encoder; see the
+     *        constants in {@link Base64}
+     * @param encode true to encode, false to decode
+     */
+    public Base64OutputStream(OutputStream out, int flags, boolean encode) {
+        super(out);
+        this.encode = encode;
+        if (encode) {
+            estate = new Base64.EncoderState(flags, null);
+            dstate = null;
+        } else {
+            estate = null;
+            dstate = new Base64.DecoderState(flags, null);
+        }
+    }
+
+    public void write(int b) throws IOException {
+        // To avoid invoking the encoder/decoder routines for single
+        // bytes, we buffer up calls to write(int) in an internal
+        // byte array to transform them into writes of decently-sized
+        // arrays.
+
+        if (buffer == null) {
+            buffer = new byte[1024];
+        }
+        if (bpos >= buffer.length) {
+            // internal buffer full; write it out.
+            internalWrite(buffer, 0, bpos, false);
+            bpos = 0;
+        }
+        buffer[bpos++] = (byte) b;
+    }
+
+    /**
+     * Flush any buffered data from calls to write(int).  Needed
+     * before doing a write(byte[], int, int) or a close().
+     */
+    private void flushBuffer() throws IOException {
+        if (bpos > 0) {
+            internalWrite(buffer, 0, bpos, false);
+            bpos = 0;
+        }
+    }
+
+    public void write(byte[] b, int off, int len) throws IOException {
+        if (len <= 0) return;
+        flushBuffer();
+        internalWrite(b, off, len, false);
+    }
+
+    public void close() throws IOException {
+        flushBuffer();
+        internalWrite(EMPTY, 0, 0, true);
+        out.close();
+    }
+
+    /**
+     * Write the given bytes to the encoder/decoder.
+     *
+     * @param finish true if this is the last batch of input, to cause
+     *        encoder/decoder state to be finalized.
+     */
+    private void internalWrite(byte[] b, int off, int len, boolean finish) throws IOException {
+        if (encode) {
+            // len*8/5+10 is an overestimate of the most bytes the
+            // encoder can produce for len bytes of input.
+            estate.output = embiggen(estate.output, len*8/5+10);
+            Base64.encodeInternal(b, off, len, estate, finish);
+            out.write(estate.output, 0, estate.op);
+        } else {
+            // len*3/4+10 is an overestimate of the most bytes the
+            // decoder can produce for len bytes of input.
+            dstate.output = embiggen(dstate.output, len*3/4+10);
+            if (!Base64.decodeInternal(b, off, len, dstate, finish)) {
+                throw new IOException("bad base-64");
+            }
+            out.write(dstate.output, 0, dstate.op);
+        }
+    }
+
+    /**
+     * If b.length is at least len, return b.  Otherwise return a new
+     * byte array of length len.
+     */
+    private byte[] embiggen(byte[] b, int len) {
+        if (b == null || b.length < len) {
+            return new byte[len];
+        } else {
+            return b;
+        }
+    }
+}
diff --git a/common/java/com/android/common/Patterns.java b/common/java/com/android/common/Patterns.java
index 24a18c0..71c3a5e 100644
--- a/common/java/com/android/common/Patterns.java
+++ b/common/java/com/android/common/Patterns.java
@@ -25,87 +25,87 @@
 public class Patterns {
     /**
      *  Regular expression pattern to match all IANA top-level domains.
-     *  List accurate as of 2007/06/15.  List taken from:
+     *  List accurate as of 2010/02/05.  List taken from:
      *  http://data.iana.org/TLD/tlds-alpha-by-domain.txt
-     *  This pattern is auto-generated by //device/tools/make-iana-tld-pattern.py
+     *  This pattern is auto-generated by development/tools/make-iana-tld-pattern.py
      */
-    public static final Pattern TOP_LEVEL_DOMAIN
-        = Pattern.compile(
-                "((aero|arpa|asia|a[cdefgilmnoqrstuwxz])"
-                + "|(biz|b[abdefghijmnorstvwyz])"
-                + "|(cat|com|coop|c[acdfghiklmnoruvxyz])"
-                + "|d[ejkmoz]"
-                + "|(edu|e[cegrstu])"
-                + "|f[ijkmor]"
-                + "|(gov|g[abdefghilmnpqrstuwy])"
-                + "|h[kmnrtu]"
-                + "|(info|int|i[delmnoqrst])"
-                + "|(jobs|j[emop])"
-                + "|k[eghimnrwyz]"
-                + "|l[abcikrstuvy]"
-                + "|(mil|mobi|museum|m[acdghklmnopqrstuvwxyz])"
-                + "|(name|net|n[acefgilopruz])"
-                + "|(org|om)"
-                + "|(pro|p[aefghklmnrstwy])"
-                + "|qa"
-                + "|r[eouw]"
-                + "|s[abcdeghijklmnortuvyz]"
-                + "|(tel|travel|t[cdfghjklmnoprtvwz])"
-                + "|u[agkmsyz]"
-                + "|v[aceginu]"
-                + "|w[fs]"
-                + "|y[etu]"
-                + "|z[amw])");
+    public static final Pattern TOP_LEVEL_DOMAIN = Pattern.compile(
+        "((aero|arpa|asia|a[cdefgilmnoqrstuwxz])"
+        + "|(biz|b[abdefghijmnorstvwyz])"
+        + "|(cat|com|coop|c[acdfghiklmnoruvxyz])"
+        + "|d[ejkmoz]"
+        + "|(edu|e[cegrstu])"
+        + "|f[ijkmor]"
+        + "|(gov|g[abdefghilmnpqrstuwy])"
+        + "|h[kmnrtu]"
+        + "|(info|int|i[delmnoqrst])"
+        + "|(jobs|j[emop])"
+        + "|k[eghimnprwyz]"
+        + "|l[abcikrstuvy]"
+        + "|(mil|mobi|museum|m[acdeghklmnopqrstuvwxyz])"
+        + "|(name|net|n[acefgilopruz])"
+        + "|(org|om)"
+        + "|(pro|p[aefghklmnrstwy])"
+        + "|qa"
+        + "|r[eosuw]"
+        + "|s[abcdeghijklmnortuvyz]"
+        + "|(tel|travel|t[cdfghjklmnoprtvwz])"
+        + "|u[agksyz]"
+        + "|v[aceginu]"
+        + "|w[fs]"
+        + "|(xn\\-\\-0zwm56d|xn\\-\\-11b5bs3a9aj6g|xn\\-\\-80akhbyknj4f|xn\\-\\-9t4b11yi5a|xn\\-\\-deba0ad|xn\\-\\-g6w251d|xn\\-\\-hgbk6aj7f53bba|xn\\-\\-hlcj6aya9esc7a|xn\\-\\-jxalpdlp|xn\\-\\-kgbechtv|xn\\-\\-zckzah)"
+        + "|y[etu]"
+        + "|z[amw])");
 
     /**
      *  Regular expression pattern to match RFC 1738 URLs
-     *  List accurate as of 2007/06/15.  List taken from:
+     *  List accurate as of 2010/02/05.  List taken from:
      *  http://data.iana.org/TLD/tlds-alpha-by-domain.txt
-     *  This pattern is auto-generated by //device/tools/make-iana-tld-pattern.py
+     *  This pattern is auto-generated by development/tools/make-iana-tld-pattern.py
      */
-    public static final Pattern WEB_URL
-        = Pattern.compile(
-            "((?:(http|https|Http|Https|rtsp|Rtsp):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)"
-            + "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_"
-            + "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@)?)?"
-            + "((?:(?:[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}\\.)+"   // named host
-            + "(?:"   // plus top level domain
-            + "(?:aero|arpa|asia|a[cdefgilmnoqrstuwxz])"
-            + "|(?:biz|b[abdefghijmnorstvwyz])"
-            + "|(?:cat|com|coop|c[acdfghiklmnoruvxyz])"
-            + "|d[ejkmoz]"
-            + "|(?:edu|e[cegrstu])"
-            + "|f[ijkmor]"
-            + "|(?:gov|g[abdefghilmnpqrstuwy])"
-            + "|h[kmnrtu]"
-            + "|(?:info|int|i[delmnoqrst])"
-            + "|(?:jobs|j[emop])"
-            + "|k[eghimnrwyz]"
-            + "|l[abcikrstuvy]"
-            + "|(?:mil|mobi|museum|m[acdghklmnopqrstuvwxyz])"
-            + "|(?:name|net|n[acefgilopruz])"
-            + "|(?:org|om)"
-            + "|(?:pro|p[aefghklmnrstwy])"
-            + "|qa"
-            + "|r[eouw]"
-            + "|s[abcdeghijklmnortuvyz]"
-            + "|(?:tel|travel|t[cdfghjklmnoprtvwz])"
-            + "|u[agkmsyz]"
-            + "|v[aceginu]"
-            + "|w[fs]"
-            + "|y[etu]"
-            + "|z[amw]))"
-            + "|(?:(?:25[0-5]|2[0-4]" // or ip address
-            + "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(?:25[0-5]|2[0-4][0-9]"
-            + "|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1]"
-            + "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}"
-            + "|[1-9][0-9]|[0-9])))"
-            + "(?:\\:\\d{1,5})?)" // plus option port number
-            + "(\\/(?:(?:[a-zA-Z0-9\\;\\/\\?\\:\\@\\&\\=\\#\\~"  // plus option query params
-            + "\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])|(?:\\%[a-fA-F0-9]{2}))*)?"
-            + "(?:\\b|$)"); // and finally, a word boundary or end of
-                            // input.  This is to stop foo.sure from
-                            // matching as foo.su
+    public static final Pattern WEB_URL = Pattern.compile(
+        "((?:(http|https|Http|Https|rtsp|Rtsp):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)"
+        + "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_"
+        + "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@)?)?"
+        + "((?:(?:[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}\\.)+"   // named host
+        + "(?:"   // plus top level domain
+        + "(?:aero|arpa|asia|a[cdefgilmnoqrstuwxz])"
+        + "|(?:biz|b[abdefghijmnorstvwyz])"
+        + "|(?:cat|com|coop|c[acdfghiklmnoruvxyz])"
+        + "|d[ejkmoz]"
+        + "|(?:edu|e[cegrstu])"
+        + "|f[ijkmor]"
+        + "|(?:gov|g[abdefghilmnpqrstuwy])"
+        + "|h[kmnrtu]"
+        + "|(?:info|int|i[delmnoqrst])"
+        + "|(?:jobs|j[emop])"
+        + "|k[eghimnprwyz]"
+        + "|l[abcikrstuvy]"
+        + "|(?:mil|mobi|museum|m[acdeghklmnopqrstuvwxyz])"
+        + "|(?:name|net|n[acefgilopruz])"
+        + "|(?:org|om)"
+        + "|(?:pro|p[aefghklmnrstwy])"
+        + "|qa"
+        + "|r[eosuw]"
+        + "|s[abcdeghijklmnortuvyz]"
+        + "|(?:tel|travel|t[cdfghjklmnoprtvwz])"
+        + "|u[agksyz]"
+        + "|v[aceginu]"
+        + "|w[fs]"
+        + "|(?:xn\\-\\-0zwm56d|xn\\-\\-11b5bs3a9aj6g|xn\\-\\-80akhbyknj4f|xn\\-\\-9t4b11yi5a|xn\\-\\-deba0ad|xn\\-\\-g6w251d|xn\\-\\-hgbk6aj7f53bba|xn\\-\\-hlcj6aya9esc7a|xn\\-\\-jxalpdlp|xn\\-\\-kgbechtv|xn\\-\\-zckzah)"
+        + "|y[etu]"
+        + "|z[amw]))"
+        + "|(?:(?:25[0-5]|2[0-4]" // or ip address
+        + "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(?:25[0-5]|2[0-4][0-9]"
+        + "|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1]"
+        + "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}"
+        + "|[1-9][0-9]|[0-9])))"
+        + "(?:\\:\\d{1,5})?)" // plus option port number
+        + "(\\/(?:(?:[a-zA-Z0-9\\;\\/\\?\\:\\@\\&\\=\\#\\~"  // plus option query params
+        + "\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])|(?:\\%[a-fA-F0-9]{2}))*)?"
+        + "(?:\\b|$)"); // and finally, a word boundary or end of
+                        // input.  This is to stop foo.sure from
+                        // matching as foo.su
 
     public static final Pattern IP_ADDRESS
         = Pattern.compile(
diff --git a/common/java/com/android/common/Search.java b/common/java/com/android/common/Search.java
new file mode 100644
index 0000000..55fa6f5
--- /dev/null
+++ b/common/java/com/android/common/Search.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.common;
+
+/**
+ * Utilities for search implementations.
+ *
+ * @see android.app.SearchManager
+ */
+public class Search {
+
+    /**
+     * Key for the source identifier set by the application that launched a search intent.
+     * The identifier is search-source specific string. It can be used
+     * by the search provider to keep statistics of where searches are started from.
+     *
+     * The source identifier is stored in the {@link android.app.SearchManager#APP_DATA}
+     * Bundle in {@link android.content.Intent#ACTION_SEARCH} and
+     * {@link android.content.Intent#ACTION_WEB_SEARCH} intents.
+     */
+    public final static String SOURCE = "source";
+
+    private Search() { }   // don't instantiate
+}
diff --git a/common/tests/src/com/android/common/Base64Test.java b/common/tests/src/com/android/common/Base64Test.java
index 5c9712a..e6b491f 100644
--- a/common/tests/src/com/android/common/Base64Test.java
+++ b/common/tests/src/com/android/common/Base64Test.java
@@ -18,6 +18,9 @@
 
 import junit.framework.TestCase;
 
+import java.io.ByteArrayOutputStream;
+import java.util.Random;
+
 public class Base64Test extends TestCase {
     private static final String TAG = "B64Test";
 
@@ -55,6 +58,22 @@
         }
     }
 
+    /** Assert that actual equals the first len bytes of expected. */
+    private void assertEquals(byte[] expected, int len, byte[] actual, int alen) {
+        assertEquals(len, alen);
+        for (int i = 0; i < len; ++i) {
+            assertEquals(expected[i], actual[i]);
+        }
+    }
+
+    /** Assert that actual equals the first len bytes of expected. */
+    private void assertEquals(byte[] expected, byte[] actual) {
+        assertEquals(expected.length, actual.length);
+        for (int i = 0; i < expected.length; ++i) {
+            assertEquals(expected[i], actual[i]);
+        }
+    }
+
     public void testDecodeExtraChars() throws Exception {
         // padding 0
         assertEquals("hello, world", decodeString("aGVsbG8sIHdvcmxk"));
@@ -205,4 +224,187 @@
         assertEquals(out_60.replaceAll("\n", ""), encodeToString(in_60, Base64.NO_WRAP));
         assertEquals(out_61.replaceAll("\n", ""), encodeToString(in_61, Base64.NO_WRAP));
     }
+
+    /**
+     * Tests that Base64.encodeInternal does correct handling of the
+     * tail for each call.
+     */
+    public void testEncodeInternal() throws Exception {
+        byte[] input = { (byte) 0x61, (byte) 0x62, (byte) 0x63 };
+        byte[] output = new byte[100];
+
+        Base64.EncoderState state = new Base64.EncoderState(Base64.NO_PADDING | Base64.NO_WRAP,
+                                                            output);
+
+        Base64.encodeInternal(input, 0, 3, state, false);
+        assertEquals("YWJj".getBytes(), 4, state.output, state.op);
+        assertEquals(0, state.tailLen);
+
+        Base64.encodeInternal(input, 0, 3, state, false);
+        assertEquals("YWJj".getBytes(), 4, state.output, state.op);
+        assertEquals(0, state.tailLen);
+
+        Base64.encodeInternal(input, 0, 1, state, false);
+        assertEquals(0, state.op);
+        assertEquals(1, state.tailLen);
+
+        Base64.encodeInternal(input, 0, 1, state, false);
+        assertEquals(0, state.op);
+        assertEquals(2, state.tailLen);
+
+        Base64.encodeInternal(input, 0, 1, state, false);
+        assertEquals("YWFh".getBytes(), 4, state.output, state.op);
+        assertEquals(0, state.tailLen);
+
+        Base64.encodeInternal(input, 0, 2, state, false);
+        assertEquals(0, state.op);
+        assertEquals(2, state.tailLen);
+
+        Base64.encodeInternal(input, 0, 2, state, false);
+        assertEquals("YWJh".getBytes(), 4, state.output, state.op);
+        assertEquals(1, state.tailLen);
+
+        Base64.encodeInternal(input, 0, 2, state, false);
+        assertEquals("YmFi".getBytes(), 4, state.output, state.op);
+        assertEquals(0, state.tailLen);
+
+        Base64.encodeInternal(input, 0, 1, state, true);
+        assertEquals("YQ".getBytes(), 2, state.output, state.op);
+    }
+
+    /**
+     * Tests that Base64OutputStream produces exactly the same results
+     * as calling Base64.encode/.decode on an in-memory array.
+     */
+    public void testOutputStream() throws Exception {
+        int[] flagses = { Base64.DEFAULT,
+                          Base64.NO_PADDING,
+                          Base64.NO_WRAP,
+                          Base64.NO_PADDING | Base64.NO_WRAP,
+                          Base64.CRLF,
+                          Base64.WEB_SAFE };
+        int[] writeLengths = { -10, -5, -1, 0, 1, 1, 2, 2, 3, 10, 100 };
+        Random rng = new Random(32176L);
+
+        // input needs to be at least 1024 bytes to test filling up
+        // the write(int) buffer.
+        byte[] input = ("Lorem ipsum dolor sit amet, consectetur adipiscing elit. " +
+                        "Quisque congue eleifend odio, eu ornare nulla facilisis eget. " +
+                        "Integer eget elit diam, sit amet laoreet nibh. Quisque enim " +
+                        "urna, pharetra vitae consequat eget, adipiscing eu ante. " +
+                        "Aliquam venenatis arcu nec nibh imperdiet tempor. In id dui " +
+                        "eget lorem aliquam rutrum vel vitae eros. In placerat ornare " +
+                        "pretium. Curabitur non fringilla mi. Fusce ultricies, turpis " +
+                        "eu ultrices suscipit, ligula nisi consectetur eros, dapibus " +
+                        "aliquet dui sapien a turpis. Donec ultricies varius ligula, " +
+                        "ut hendrerit arcu malesuada at. Praesent sed elit pretium " +
+                        "eros luctus gravida. In ac dolor lorem. Cras condimentum " +
+                        "convallis elementum. Phasellus vel felis in nulla ultrices " +
+                        "venenatis. Nam non tortor non orci convallis convallis. " +
+                        "Nam tristique lacinia hendrerit. Pellentesque habitant morbi " +
+                        "tristique senectus et netus et malesuada fames ac turpis " +
+                        "egestas. Vivamus cursus, nibh eu imperdiet porta, magna " +
+                        "ipsum mollis mauris, sit amet fringilla mi nisl eu mi. " +
+                        "Phasellus posuere, leo at ultricies vehicula, massa risus " +
+                        "volutpat sapien, eu tincidunt diam ipsum eget nulla. Cras " +
+                        "molestie dapibus commodo. Ut vel tellus at massa gravida " +
+                        "semper non sed orci.").getBytes();
+
+        for (int f = 0; f < flagses.length; ++f) {
+            int flags = flagses[f];
+
+            byte[] expected = Base64.encode(input, flags);
+
+            ByteArrayOutputStream baos;
+            Base64OutputStream b64os;
+            byte[] actual;
+            int p;
+
+            // ----- test encoding ("input" -> "expected") -----
+
+            // one large write(byte[]) of the whole input
+            baos = new ByteArrayOutputStream();
+            b64os = new Base64OutputStream(baos, flags);
+            b64os.write(input);
+            b64os.close();
+            actual = baos.toByteArray();
+            assertEquals(expected, actual);
+
+            // many calls to write(int)
+            baos = new ByteArrayOutputStream();
+            b64os = new Base64OutputStream(baos, flags);
+            for (int i = 0; i < input.length; ++i) {
+                b64os.write(input[i]);
+            }
+            b64os.close();
+            actual = baos.toByteArray();
+            assertEquals(expected, actual);
+
+            // intermixed sequences of write(int) with
+            // write(byte[],int,int) of various lengths.
+            baos = new ByteArrayOutputStream();
+            b64os = new Base64OutputStream(baos, flags);
+            p = 0;
+            while (p < input.length) {
+                int l = writeLengths[rng.nextInt(writeLengths.length)];
+                l = Math.min(l, input.length-p);
+                if (l >= 0) {
+                    b64os.write(input, p, l);
+                    p += l;
+                } else {
+                    l = Math.min(-l, input.length-p);
+                    for (int i = 0; i < l; ++i) {
+                        b64os.write(input[p+i]);
+                    }
+                    p += l;
+                }
+            }
+            b64os.close();
+            actual = baos.toByteArray();
+            assertEquals(expected, actual);
+
+            // ----- test decoding ("expected" -> "input") -----
+
+            // one large write(byte[]) of the whole input
+            baos = new ByteArrayOutputStream();
+            b64os = new Base64OutputStream(baos, flags, false);
+            b64os.write(expected);
+            b64os.close();
+            actual = baos.toByteArray();
+            assertEquals(input, actual);
+
+            // many calls to write(int)
+            baos = new ByteArrayOutputStream();
+            b64os = new Base64OutputStream(baos, flags, false);
+            for (int i = 0; i < expected.length; ++i) {
+                b64os.write(expected[i]);
+            }
+            b64os.close();
+            actual = baos.toByteArray();
+            assertEquals(input, actual);
+
+            // intermixed sequences of write(int) with
+            // write(byte[],int,int) of various lengths.
+            baos = new ByteArrayOutputStream();
+            b64os = new Base64OutputStream(baos, flags, false);
+            p = 0;
+            while (p < expected.length) {
+                int l = writeLengths[rng.nextInt(writeLengths.length)];
+                l = Math.min(l, expected.length-p);
+                if (l >= 0) {
+                    b64os.write(expected, p, l);
+                    p += l;
+                } else {
+                    l = Math.min(-l, expected.length-p);
+                    for (int i = 0; i < l; ++i) {
+                        b64os.write(expected[p+i]);
+                    }
+                    p += l;
+                }
+            }
+            b64os.close();
+            actual = baos.toByteArray();
+            assertEquals(input, actual);
+        }
+    }
 }
diff --git a/common/tests/src/com/android/common/PatternsTest.java b/common/tests/src/com/android/common/PatternsTest.java
index 7fabe5e..635601e 100644
--- a/common/tests/src/com/android/common/PatternsTest.java
+++ b/common/tests/src/com/android/common/PatternsTest.java
@@ -31,6 +31,20 @@
         t = Patterns.TOP_LEVEL_DOMAIN.matcher("com").matches();
         assertTrue("Missed valid TLD", t);
 
+        // One of the new top level domain.
+        t = Patterns.TOP_LEVEL_DOMAIN.matcher("me").matches();
+        assertTrue("Missed valid TLD", t);
+
+        // One of the new top level test domain.
+        t = Patterns.TOP_LEVEL_DOMAIN.matcher("xn--0zwm56d").matches();
+        assertTrue("Missed valid TLD", t);
+
+        t = Patterns.TOP_LEVEL_DOMAIN.matcher("mem").matches();
+        assertFalse("Matched invalid TLD!", t);
+
+        t = Patterns.TOP_LEVEL_DOMAIN.matcher("xn").matches();
+        assertFalse("Matched invalid TLD!", t);
+
         t = Patterns.TOP_LEVEL_DOMAIN.matcher("xer").matches();
         assertFalse("Matched invalid TLD!", t);
     }
@@ -42,6 +56,18 @@
         t = Patterns.WEB_URL.matcher("http://www.google.com").matches();
         assertTrue("Valid URL", t);
 
+        // Google in one of the new top level domain.
+        t = Patterns.WEB_URL.matcher("http://www.google.me").matches();
+        assertTrue("Valid URL", t);
+        t = Patterns.WEB_URL.matcher("google.me").matches();
+        assertTrue("Valid URL", t);
+
+        // Test url in Chinese: http://xn--fsqu00a.xn--0zwm56d
+        t = Patterns.WEB_URL.matcher("http://xn--fsqu00a.xn--0zwm56d").matches();
+        assertTrue("Valid URL", t);
+        t = Patterns.WEB_URL.matcher("xn--fsqu00a.xn--0zwm56d").matches();
+        assertTrue("Valid URL", t);
+
         t = Patterns.WEB_URL.matcher("ftp://www.example.com").matches();
         assertFalse("Matched invalid protocol", t);
 
diff --git a/common/tools/make-iana-tld-pattern.py b/common/tools/make-iana-tld-pattern.py
new file mode 100755
index 0000000..ece4dcf
--- /dev/null
+++ b/common/tools/make-iana-tld-pattern.py
@@ -0,0 +1,160 @@
+#!/usr/bin/env python
+
+from urllib2 import urlopen
+
+TLD_PREFIX = r"""
+    /**
+     *  Regular expression pattern to match all IANA top-level domains.
+     *  List accurate as of 2010/02/05.  List taken from:
+     *  http://data.iana.org/TLD/tlds-alpha-by-domain.txt
+     *  This pattern is auto-generated by frameworks/base/common/tools/make-iana-tld-pattern.py
+     */
+    public static final Pattern TOP_LEVEL_DOMAIN = Pattern.compile(
+"""
+TLD_SUFFIX = '");'
+
+URL_PREFIX = r"""
+    /**
+     *  Regular expression pattern to match RFC 1738 URLs
+     *  List accurate as of 2010/02/05.  List taken from:
+     *  http://data.iana.org/TLD/tlds-alpha-by-domain.txt
+     *  This pattern is auto-generated by frameworkds/base/common/tools/make-iana-tld-pattern.py
+     */
+    public static final Pattern WEB_URL = Pattern.compile(
+        "((?:(http|https|Http|Https|rtsp|Rtsp):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)"
+        + "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_"
+        + "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@)?)?"
+        + "((?:(?:[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}\\.)+"   // named host
+        + "(?:"   // plus top level domain
+"""
+
+URL_SUFFIX = r"""
+        + "|(?:(?:25[0-5]|2[0-4]" // or ip address
+        + "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(?:25[0-5]|2[0-4][0-9]"
+        + "|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1]"
+        + "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(?:25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}"
+        + "|[1-9][0-9]|[0-9])))"
+        + "(?:\\:\\d{1,5})?)" // plus option port number
+        + "(\\/(?:(?:[a-zA-Z0-9\\;\\/\\?\\:\\@\\&\\=\\#\\~"  // plus option query params
+        + "\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])|(?:\\%[a-fA-F0-9]{2}))*)?"
+        + "(?:\\b|$)"); // and finally, a word boundary or end of
+                        // input.  This is to stop foo.sure from
+                        // matching as foo.su
+"""
+
+class Bucket:
+    def __init__(self, baseLetter):
+        self.base=baseLetter
+        self.words=[]
+        self.letters=[]
+
+    def dump(self, isWebUrl=False, isFirst=False, isLast=False):
+        if (len(self.words) == 0) and (len(self.letters) == 0):
+            return ''
+
+        self.words.sort()
+        self.letters.sort()
+
+        output = '        ';
+
+        if isFirst:
+            if isWebUrl:
+                output += '+ "'
+            else:
+                output += '"('
+        else:
+            output += '+ "|'
+
+        if len(self.words) != 0:
+            output += '('
+
+            if isWebUrl:
+                output += '?:'
+
+        firstWord = 1
+        for word in self.words:
+            if firstWord == 0:
+                output += '|'
+            firstWord = 0
+            for letter in word:
+                if letter == '-':
+                    output += '\\\\'  # escape the '-' character.
+                output += letter
+
+        if len(self.words) > 0 and len(self.letters) > 0:
+            output += '|'
+
+        if len(self.letters) == 1:
+            output += '%c%c' % (self.base, self.letters[0])
+        elif len(self.letters) > 0:
+            output += '%c[' % self.base
+
+            for letter in self.letters:
+                output += letter
+
+            output += ']'
+
+        if len(self.words) != 0:
+            output += ')'
+
+        if not isLast:
+            output += '"'
+            output += '\n'
+
+        return output;
+
+    def add(self, line):
+        length = len(line)
+
+        if line.startswith('#') or (length == 0):
+            return;
+
+        if length == 2:
+            self.letters.append(line[1:2])
+        else:
+            self.words.append(line)
+
+def getBucket(buckets, line):
+    letter = line[0]
+    bucket = buckets.get(letter)
+
+    if bucket is None:
+        bucket = Bucket(letter)
+        buckets[letter] = bucket
+
+    return bucket
+
+def makePattern(prefix, suffix, buckets, isWebUrl=False):
+    output = prefix
+
+    output += getBucket(buckets, 'a').dump(isFirst=True, isWebUrl=isWebUrl)
+
+    for letter in range(ord('b'), ord('z')):
+        output += getBucket(buckets, chr(letter)).dump(isWebUrl=isWebUrl)
+
+    output += getBucket(buckets, 'z').dump(isLast=True, isWebUrl=isWebUrl)
+
+    if isWebUrl:
+        output += '))"'
+    else:
+        output += ')'
+
+    output += suffix
+
+    print output
+
+if __name__ == "__main__":
+    f = urlopen('http://data.iana.org/TLD/tlds-alpha-by-domain.txt')
+    domains = f.readlines()
+    f.close()
+
+    buckets = {}
+
+    for domain in domains:
+        domain = domain.lower()
+
+        if len(domain) > 0:
+            getBucket(buckets, domain[0]).add(domain.strip())
+
+    makePattern(TLD_PREFIX, TLD_SUFFIX, buckets, isWebUrl=False)
+    makePattern(URL_PREFIX, URL_SUFFIX, buckets, isWebUrl=True)
diff --git a/include/ui/CameraParameters.h b/include/ui/CameraParameters.h
index 2c29bfb..e328f33 100644
--- a/include/ui/CameraParameters.h
+++ b/include/ui/CameraParameters.h
@@ -187,6 +187,13 @@
     // Vertical angle of view in degrees.
     // Example value: "42.5". Read only.
     static const char KEY_VERTICAL_VIEW_ANGLE[];
+    // Exposure compensation. The value is multiplied by 100. -100 means -1 EV.
+    // 130 means +1.3 EV.
+    // Example value: "0" or "133". Read/write.
+    static const char KEY_EXPOSURE_COMPENSATION[];
+    // Supported exposure compensation.
+    // Example value: "-100,-66,-33,0,33,66,100". Read only.
+    static const char KEY_SUPPORTED_EXPOSURE_COMPENSATION[];
 
 
         // Values for white balance settings.
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index 965b7dd..2d6152e 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -39,7 +39,6 @@
 
 #include <ui/GraphicBufferAllocator.h>
 #include <ui/PixelFormat.h>
-#include <ui/DisplayInfo.h>
 
 #include <pixelflinger/pixelflinger.h>
 #include <GLES/gl.h>
@@ -350,8 +349,8 @@
     mServerCblk->connected |= 1<<dpy;
     display_cblk_t* dcblk = mServerCblk->displays + dpy;
     memset(dcblk, 0, sizeof(display_cblk_t));
-    dcblk->w            = w;
-    dcblk->h            = h;
+    dcblk->w            = plane.getWidth();
+    dcblk->h            = plane.getHeight();
     dcblk->format       = f;
     dcblk->orientation  = ISurfaceComposer::eOrientationDefault;
     dcblk->xdpi         = hw.getDpiX();
@@ -621,14 +620,8 @@
             const DisplayHardware& hw(plane.displayHardware());
             volatile display_cblk_t* dcblk = mServerCblk->displays + dpy;
             dcblk->orientation = orientation;
-            if (orientation & eOrientationSwapMask) {
-                // 90 or 270 degrees orientation
-                dcblk->w = hw.getHeight();
-                dcblk->h = hw.getWidth();
-            } else {
-                dcblk->w = hw.getWidth();
-                dcblk->h = hw.getHeight();
-            }
+            dcblk->w = plane.getWidth();
+            dcblk->h = plane.getHeight();
 
             mVisibleRegionsDirty = true;
             mDirtyRegion.set(hw.bounds());
@@ -1795,13 +1788,47 @@
     return mHw ? true : false;
 }
 
-void GraphicPlane::setDisplayHardware(DisplayHardware *hw) {
-    mHw = hw;
+int GraphicPlane::getWidth() const {
+    return mWidth;
 }
 
-void GraphicPlane::setTransform(const Transform& tr) {
-    mTransform = tr;
-    mGlobalTransform = mOrientationTransform * mTransform;
+int GraphicPlane::getHeight() const {
+    return mHeight;
+}
+
+void GraphicPlane::setDisplayHardware(DisplayHardware *hw)
+{
+    mHw = hw;
+
+    // initialize the display orientation transform.
+    // it's a constant that should come from the display driver.
+    int displayOrientation = ISurfaceComposer::eOrientationDefault;
+    char property[PROPERTY_VALUE_MAX];
+    if (property_get("ro.sf.hwrotation", property, NULL) > 0) {
+        //displayOrientation
+        switch (atoi(property)) {
+        case 90:
+            displayOrientation = ISurfaceComposer::eOrientation90;
+            break;
+        case 270:
+            displayOrientation = ISurfaceComposer::eOrientation270;
+            break;
+        }
+    }
+
+    const float w = hw->getWidth();
+    const float h = hw->getHeight();
+    GraphicPlane::orientationToTransfrom(displayOrientation, w, h,
+            &mDisplayTransform);
+    if (displayOrientation & ISurfaceComposer::eOrientationSwapMask) {
+        mDisplayWidth = h;
+        mDisplayHeight = w;
+    } else {
+        mDisplayWidth = w;
+        mDisplayHeight = h;
+    }
+
+    setOrientation(ISurfaceComposer::eOrientationDefault);
 }
 
 status_t GraphicPlane::orientationToTransfrom(
@@ -1810,8 +1837,9 @@
     float a, b, c, d, x, y;
     switch (orientation) {
     case ISurfaceComposer::eOrientationDefault:
-        a=1; b=0; c=0; d=1; x=0; y=0;
-        break;
+        // make sure the default orientation is optimal
+        tr->reset();
+        return NO_ERROR;
     case ISurfaceComposer::eOrientation90:
         a=0; b=-1; c=1; d=0; x=w; y=0;
         break;
@@ -1831,20 +1859,16 @@
 
 status_t GraphicPlane::setOrientation(int orientation)
 {
-    const DisplayHardware& hw(displayHardware());
-    const float w = hw.getWidth();
-    const float h = hw.getHeight();
-
-    if (orientation == ISurfaceComposer::eOrientationDefault) {
-        // make sure the default orientation is optimal
-        mOrientationTransform.reset();
-        mOrientation = orientation;
-        mGlobalTransform = mTransform;
-        return NO_ERROR;
-    }
-
     // If the rotation can be handled in hardware, this is where
     // the magic should happen.
+
+    const DisplayHardware& hw(displayHardware());
+    const float w = mDisplayWidth;
+    const float h = mDisplayHeight;
+    mWidth = int(w);
+    mHeight = int(h);
+
+    Transform orientationTransform;
     if (UNLIKELY(orientation == 42)) {
         float a, b, c, d, x, y;
         const float r = (3.14159265f / 180.0f) * 42.0f;
@@ -1853,14 +1877,18 @@
         a=co; b=-si; c=si; d=co;
         x = si*(h*0.5f) + (1-co)*(w*0.5f);
         y =-si*(w*0.5f) + (1-co)*(h*0.5f);
-        mOrientationTransform.set(a, b, c, d);
-        mOrientationTransform.set(x, y);
+        orientationTransform.set(a, b, c, d);
+        orientationTransform.set(x, y);
     } else {
         GraphicPlane::orientationToTransfrom(orientation, w, h,
-                &mOrientationTransform);
+                &orientationTransform);
+        if (orientation & ISurfaceComposer::eOrientationSwapMask) {
+            mWidth = int(h);
+            mHeight = int(w);
+        }
     }
     mOrientation = orientation;
-    mGlobalTransform = mOrientationTransform * mTransform;
+    mGlobalTransform = mDisplayTransform * orientationTransform;
     return NO_ERROR;
 }
 
diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/libs/surfaceflinger/SurfaceFlinger.h
index c0ab73d..2b7820c 100644
--- a/libs/surfaceflinger/SurfaceFlinger.h
+++ b/libs/surfaceflinger/SurfaceFlinger.h
@@ -116,9 +116,10 @@
         bool                    initialized() const;
 
         void                    setDisplayHardware(DisplayHardware *);
-        void                    setTransform(const Transform& tr);
         status_t                setOrientation(int orientation);
         int                     getOrientation() const { return mOrientation; }
+        int                     getWidth() const;
+        int                     getHeight() const;
 
         const DisplayHardware&  displayHardware() const;
         const Transform&        transform() const;
@@ -129,10 +130,13 @@
         GraphicPlane            operator = (const GraphicPlane&);
 
         DisplayHardware*        mHw;
-        Transform               mTransform;
-        Transform               mOrientationTransform;
         Transform               mGlobalTransform;
+        Transform               mDisplayTransform;
         int                     mOrientation;
+        float                   mDisplayWidth;
+        float                   mDisplayHeight;
+        int                     mWidth;
+        int                     mHeight;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/libs/ui/Camera.cpp b/libs/ui/Camera.cpp
index 09a36f1..f374fbc 100644
--- a/libs/ui/Camera.cpp
+++ b/libs/ui/Camera.cpp
@@ -281,7 +281,7 @@
 // send command to camera driver
 status_t Camera::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2)
 {
-    LOGD("sendCommand");
+    LOGV("sendCommand");
     sp <ICamera> c = mCamera;
     if (c == 0) return NO_INIT;
     return c->sendCommand(cmd, arg1, arg2);
diff --git a/libs/ui/CameraParameters.cpp b/libs/ui/CameraParameters.cpp
index c4958a0..493b9c1 100644
--- a/libs/ui/CameraParameters.cpp
+++ b/libs/ui/CameraParameters.cpp
@@ -59,6 +59,8 @@
 const char CameraParameters::KEY_FOCAL_LENGTH[] = "focal-length";
 const char CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE[] = "horizontal-view-angle";
 const char CameraParameters::KEY_VERTICAL_VIEW_ANGLE[] = "vertical-view-angle";
+const char CameraParameters::KEY_EXPOSURE_COMPENSATION[] = "exposure-compensation";
+const char CameraParameters::KEY_SUPPORTED_EXPOSURE_COMPENSATION[] = "exposure-compensation-values";
 
 // Values for white balance settings.
 const char CameraParameters::WHITE_BALANCE_AUTO[] = "auto";
diff --git a/libs/ui/ICamera.cpp b/libs/ui/ICamera.cpp
index e1b3ec7..4154b05 100644
--- a/libs/ui/ICamera.cpp
+++ b/libs/ui/ICamera.cpp
@@ -344,7 +344,7 @@
             return NO_ERROR;
          } break;
         case SEND_COMMAND: {
-            LOGD("SEND_COMMAND");
+            LOGV("SEND_COMMAND");
             CHECK_INTERFACE(ICamera, data, reply);
             int command = data.readInt32();
             int arg1 = data.readInt32();