Merge change Ie8672184 into eclair-mr2

* changes:
  Add error code column to SMS
diff --git a/Android.mk b/Android.mk
index 5008ad7..a40d3f9 100644
--- a/Android.mk
+++ b/Android.mk
@@ -108,7 +108,6 @@
 	core/java/android/hardware/ISensorService.aidl \
 	core/java/android/net/IConnectivityManager.aidl \
 	core/java/android/os/ICheckinService.aidl \
-	core/java/android/os/IDropBox.aidl \
 	core/java/android/os/IHardwareService.aidl \
 	core/java/android/os/IMessenger.aidl \
 	core/java/android/os/IMountService.aidl \
@@ -137,6 +136,7 @@
 	core/java/com/android/internal/appwidget/IAppWidgetService.aidl \
 	core/java/com/android/internal/appwidget/IAppWidgetHost.aidl \
 	core/java/com/android/internal/backup/IBackupTransport.aidl \
+	core/java/com/android/internal/os/IDropBoxService.aidl \
 	core/java/com/android/internal/os/IResultReceiver.aidl \
 	core/java/com/android/internal/view/IInputContext.aidl \
 	core/java/com/android/internal/view/IInputContextCallback.aidl \
@@ -217,7 +217,7 @@
 	frameworks/base/core/java/android/appwidget/AppWidgetProviderInfo.aidl \
 	frameworks/base/core/java/android/net/Uri.aidl \
 	frameworks/base/core/java/android/os/Bundle.aidl \
-	frameworks/base/core/java/android/os/DropBoxEntry.aidl \
+	frameworks/base/core/java/android/os/DropBox.aidl \
 	frameworks/base/core/java/android/os/ParcelFileDescriptor.aidl \
 	frameworks/base/core/java/android/os/ParcelUuid.aidl \
 	frameworks/base/core/java/android/view/KeyEvent.aidl \
@@ -491,6 +491,8 @@
 
 include $(BUILD_DROIDDOC)
 
+# explicitly specify that online-sdk depends on framework-res.
+$(full_target): framework-res-package-target
 
 # ==== docs that have all of the stuff that's @hidden =======================
 include $(CLEAR_VARS)
diff --git a/api/current.xml b/api/current.xml
index 4cd9718..6ba1199 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -99410,6 +99410,17 @@
  visibility="public"
 >
 </field>
+<field name="ECLAIR_MR1"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="6"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 </class>
 <class name="Bundle"
  extends="java.lang.Object"
diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java
index f48f150..305ee6a 100644
--- a/core/java/android/app/ApplicationContext.java
+++ b/core/java/android/app/ApplicationContext.java
@@ -70,6 +70,7 @@
 import android.net.wifi.WifiManager;
 import android.os.Binder;
 import android.os.Bundle;
+import android.os.DropBox;
 import android.os.FileUtils;
 import android.os.Handler;
 import android.os.IBinder;
@@ -93,6 +94,8 @@
 import android.accounts.AccountManager;
 import android.accounts.IAccountManager;
 
+import com.android.internal.os.IDropBoxService;
+
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
@@ -182,6 +185,7 @@
     private ClipboardManager mClipboardManager = null;
     private boolean mRestricted;
     private AccountManager mAccountManager; // protected by mSync
+    private DropBox mDropBox = null;
 
     private final Object mSync = new Object();
 
@@ -896,6 +900,8 @@
             return getClipboardManager();
         } else if (WALLPAPER_SERVICE.equals(name)) {
             return getWallpaperManager();
+        } else if (DROPBOX_SERVICE.equals(name)) {
+            return getDropBox();
         }
 
         return null;
@@ -1045,7 +1051,7 @@
         }
         return mVibrator;
     }
-  
+
     private AudioManager getAudioManager()
     {
         if (mAudioManager == null) {
@@ -1054,6 +1060,17 @@
         return mAudioManager;
     }
 
+    private DropBox getDropBox() {
+        synchronized (mSync) {
+            if (mDropBox == null) {
+                IBinder b = ServiceManager.getService(DROPBOX_SERVICE);
+                IDropBoxService service = IDropBoxService.Stub.asInterface(b);
+                mDropBox = new DropBox(service);
+            }
+        }
+        return mDropBox;
+    }
+
     @Override
     public int checkPermission(String permission, int pid, int uid) {
         if (permission == null) {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 8f1c671..b4ab408 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1309,7 +1309,7 @@
      * @see #getSystemService
      */
     public static final String APPWIDGET_SERVICE = "appwidget";
-    
+
     /**
      * Use with {@link #getSystemService} to retrieve an
      * {@blink android.backup.IBackupManager IBackupManager} for communicating
@@ -1319,7 +1319,16 @@
      * @see #getSystemService
      */
     public static final String BACKUP_SERVICE = "backup";
-    
+
+    /**
+     * Use with {@link #getSystemService} to retrieve a
+     * {@blink android.os.DropBox DropBox} instance for recording
+     * diagnostic logs.
+     * @hide
+     * @see #getSystemService
+     */
+    public static final String DROPBOX_SERVICE = "dropbox";
+
     /**
      * Determine whether the given permission is allowed for a particular
      * process and user ID running in the system.
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 0f8bc08..d4aaba3 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -103,16 +103,19 @@
          * October 2008: The original, first, version of Android.  Yay!
          */
         public static final int BASE = 1;
+        
         /**
          * February 2009: First Android update, officially called 1.1.
          */
         public static final int BASE_1_1 = 2;
+        
         /**
          * May 2009: Android 1.5.
          */
         public static final int CUPCAKE = 3;
+        
         /**
-         * Current work on "Donut" development branch.
+         * September 2009: Android 1.6.
          * 
          * <p>Applications targeting this or a later release will get these
          * new changes in behavior:</p>
@@ -133,8 +136,9 @@
          * </ul>
          */
         public static final int DONUT = 4;
+        
         /**
-         * Current work on "Eclair" development branch.
+         * November 2009: Android 2.0
          * 
          * <p>Applications targeting this or a later release will get these
          * new changes in behavior:</p>
@@ -152,6 +156,11 @@
          * </ul>
          */
         public static final int ECLAIR = 5;
+        
+        /**
+         * Current work on Eclair MR1.
+         */
+        public static final int ECLAIR_MR1 = 6;
     }
     
     /** The type of build, like "user" or "eng". */
diff --git a/core/java/android/os/DropBoxEntry.aidl b/core/java/android/os/DropBox.aidl
similarity index 95%
rename from core/java/android/os/DropBoxEntry.aidl
rename to core/java/android/os/DropBox.aidl
index 225eee1..77abd22 100644
--- a/core/java/android/os/DropBoxEntry.aidl
+++ b/core/java/android/os/DropBox.aidl
@@ -16,4 +16,4 @@
 
 package android.os;
 
-parcelable DropBoxEntry;
+parcelable DropBox.Entry;
diff --git a/core/java/android/os/DropBox.java b/core/java/android/os/DropBox.java
new file mode 100644
index 0000000..0551dc1
--- /dev/null
+++ b/core/java/android/os/DropBox.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.util.Log;
+
+import com.android.internal.os.IDropBoxService;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.zip.GZIPInputStream;
+
+/**
+ * Enqueues chunks of data (from various sources -- application crashes, kernel
+ * log records, etc.).  The queue is size bounded and will drop old data if the
+ * enqueued data exceeds the maximum size.  You can think of this as a
+ * persistent, system-wide, blob-oriented "logcat".
+ *
+ * <p>You can obtain an instance of this class by calling
+ * {@link android.content.Context#getSystemService}
+ * with {@link android.content.Context#DROPBOX_SERVICE}.
+ *
+ * <p>DropBox entries are not sent anywhere directly, but other system services
+ * and debugging tools may scan and upload entries for processing.
+ *
+ * {@pending}
+ */
+public class DropBox {
+    private static final String TAG = "DropBox";
+    private final IDropBoxService mService;
+
+    /** Flag value: Entry's content was deleted to save space. */
+    public static final int IS_EMPTY = 1;
+
+    /** Flag value: Content is human-readable UTF-8 text (can be combined with IS_GZIPPED). */
+    public static final int IS_TEXT = 2;
+
+    /** Flag value: Content can be decompressed with {@link GZIPOutputStream}. */
+    public static final int IS_GZIPPED = 4;
+
+    /**
+     * A single entry retrieved from the drop box.
+     * This may include a reference to a stream, so you must call
+     * {@link #close()} when you are done using it.
+     */
+    public static class Entry implements Parcelable {
+        private final String mTag;
+        private final long mTimeMillis;
+
+        private final byte[] mData;
+        private final ParcelFileDescriptor mFileDescriptor;
+        private final int mFlags;
+
+        /** Create a new empty Entry with no contents. */
+        public Entry(String tag, long millis) {
+            this(tag, millis, (Object) null, IS_EMPTY);
+        }
+
+        /** Create a new Entry with plain text contents. */
+        public Entry(String tag, long millis, String text) {
+            this(tag, millis, (Object) text.getBytes(), IS_TEXT);
+        }
+
+        /**
+         * Create a new Entry with byte array contents.
+         * The data array must not be modified after creating this entry.
+         */
+        public Entry(String tag, long millis, byte[] data, int flags) {
+            this(tag, millis, (Object) data, flags);
+        }
+
+        /**
+         * Create a new Entry with streaming data contents.
+         * Takes ownership of the ParcelFileDescriptor.
+         */
+        public Entry(String tag, long millis, ParcelFileDescriptor data, int flags) {
+            this(tag, millis, (Object) data, flags);
+        }
+
+        /**
+         * Create a new Entry with the contents read from a file.
+         * The file will be read when the entry's contents are requested.
+         */
+        public Entry(String tag, long millis, File data, int flags) throws IOException {
+            this(tag, millis, (Object) ParcelFileDescriptor.open(
+                    data, ParcelFileDescriptor.MODE_READ_ONLY), flags);
+        }
+
+        /** Internal constructor for CREATOR.createFromParcel(). */
+        private Entry(String tag, long millis, Object value, int flags) {
+            if (tag == null) throw new NullPointerException();
+            if (((flags & IS_EMPTY) != 0) != (value == null)) throw new IllegalArgumentException();
+
+            mTag = tag;
+            mTimeMillis = millis;
+            mFlags = flags;
+
+            if (value == null) {
+                mData = null;
+                mFileDescriptor = null;
+            } else if (value instanceof byte[]) {
+                mData = (byte[]) value;
+                mFileDescriptor = null;
+            } else if (value instanceof ParcelFileDescriptor) {
+                mData = null;
+                mFileDescriptor = (ParcelFileDescriptor) value;
+            } else {
+                throw new IllegalArgumentException();
+            }
+        }
+
+        /** Close the input stream associated with this entry. */
+        public void close() {
+            try { if (mFileDescriptor != null) mFileDescriptor.close(); } catch (IOException e) { }
+        }
+
+        /** @return the tag originally attached to the entry. */
+        public String getTag() { return mTag; }
+
+        /** @return time when the entry was originally created. */
+        public long getTimeMillis() { return mTimeMillis; }
+
+        /** @return flags describing the content returned by @{link #getInputStream()}. */
+        public int getFlags() { return mFlags & ~IS_GZIPPED; }  // getInputStream() decompresses.
+
+        /**
+         * @param maxBytes of string to return (will truncate at this length).
+         * @return the uncompressed text contents of the entry, null if the entry is not text.
+         */
+        public String getText(int maxBytes) {
+            if ((mFlags & IS_TEXT) == 0) return null;
+            if (mData != null) return new String(mData, 0, Math.min(maxBytes, mData.length));
+
+            InputStream is = null;
+            try {
+                is = getInputStream();
+                byte[] buf = new byte[maxBytes];
+                return new String(buf, 0, Math.max(0, is.read(buf)));
+            } catch (IOException e) {
+                return null;
+            } finally {
+                try { if (is != null) is.close(); } catch (IOException e) {}
+            }
+        }
+
+        /** @return the uncompressed contents of the entry, or null if the contents were lost */
+        public InputStream getInputStream() throws IOException {
+            InputStream is;
+            if (mData != null) {
+                is = new ByteArrayInputStream(mData);
+            } else if (mFileDescriptor != null) {
+                is = new ParcelFileDescriptor.AutoCloseInputStream(mFileDescriptor);
+            } else {
+                return null;
+            }
+            return (mFlags & IS_GZIPPED) != 0 ? new GZIPInputStream(is) : is;
+        }
+
+        public static final Parcelable.Creator<Entry> CREATOR = new Parcelable.Creator() {
+            public Entry[] newArray(int size) { return new Entry[size]; }
+            public Entry createFromParcel(Parcel in) {
+                return new Entry(
+                        in.readString(), in.readLong(), in.readValue(null), in.readInt());
+            }
+        };
+
+        public int describeContents() {
+            return mFileDescriptor != null ? Parcelable.CONTENTS_FILE_DESCRIPTOR : 0;
+        }
+
+        public void writeToParcel(Parcel out, int flags) {
+            out.writeString(mTag);
+            out.writeLong(mTimeMillis);
+            if (mFileDescriptor != null) {
+                out.writeValue(mFileDescriptor);
+            } else {
+                out.writeValue(mData);
+            }
+            out.writeInt(mFlags);
+        }
+    }
+
+    /** {@hide} */
+    public DropBox(IDropBoxService service) { mService = service; }
+
+    /**
+     * Create a dummy instance for testing.  All methods will fail unless
+     * overridden with an appropriate mock implementation.  To obtain a
+     * functional instance, use {@link android.content.Context#getSystemService}.
+     */
+    protected DropBox() { mService = null; }
+
+    /**
+     * Stores human-readable text.  The data may be discarded eventually (or even
+     * immediately) if space is limited, or ignored entirely if the tag has been
+     * blocked (see {@link #isTagEnabled}).
+     *
+     * @param tag describing the type of entry being stored
+     * @param data value to store
+     */
+    public void addText(String tag, String data) {
+        try { mService.add(new Entry(tag, 0, data)); } catch (RemoteException e) {}
+    }
+
+    /**
+     * Stores binary data, which may be ignored or discarded as with {@link #addText}.
+     *
+     * @param tag describing the type of entry being stored
+     * @param data value to store
+     * @param flags describing the data
+     */
+    public void addData(String tag, byte[] data, int flags) {
+        if (data == null) throw new NullPointerException();
+        try { mService.add(new Entry(tag, 0, data, flags)); } catch (RemoteException e) {}
+    }
+
+    /**
+     * Stores data read from a file descriptor.  The data may be ignored or
+     * discarded as with {@link #addText}.  You must close your
+     * ParcelFileDescriptor object after calling this method!
+     *
+     * @param tag describing the type of entry being stored
+     * @param fd file descriptor to read from
+     * @param flags describing the data
+     */
+    public void addFile(String tag, ParcelFileDescriptor fd, int flags) {
+        if (fd == null) throw new NullPointerException();
+        try { mService.add(new Entry(tag, 0, fd, flags)); } catch (RemoteException e) {}
+    }
+
+    /**
+     * Checks any blacklists (set in system settings) to see whether a certain
+     * tag is allowed.  Entries with disabled tags will be dropped immediately,
+     * so you can save the work of actually constructing and sending the data.
+     *
+     * @param tag that would be used in {@link #addText} or {@link #addFile}
+     * @return whether events with that tag would be accepted
+     */
+    public boolean isTagEnabled(String tag) {
+        try { return mService.isTagEnabled(tag); } catch (RemoteException e) { return false; }
+    }
+
+    /**
+     * Gets the next entry from the drop box *after* the specified time.
+     * Requires android.permission.READ_LOGS.  You must always call
+     * {@link Entry#close()} on the return value!
+     *
+     * @param tag of entry to look for, null for all tags
+     * @param msec time of the last entry seen
+     * @return the next entry, or null if there are no more entries
+     */
+    public Entry getNextEntry(String tag, long msec) {
+        try { return mService.getNextEntry(tag, msec); } catch (RemoteException e) { return null; }
+    }
+
+    // TODO: It may be useful to have some sort of notification mechanism
+    // when data is added to the dropbox, for demand-driven readers --
+    // for now readers need to poll the dropbox to find new data.
+}
diff --git a/core/java/android/os/DropBoxEntry.java b/core/java/android/os/DropBoxEntry.java
deleted file mode 100644
index e3816a8..0000000
--- a/core/java/android/os/DropBoxEntry.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.os;
-
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.io.StringReader;
-import java.util.zip.GZIPInputStream;
-
-/**
- * A single entry retrieved from an {@link IDropBox} implementation.
- * This may include a reference to a stream, so you must call
- * {@link #close()} when you are done using it.
- *
- * {@pending}
- */
-public class DropBoxEntry implements Parcelable {
-    private final String mTag;
-    private final long mTimeMillis;
-
-    private final String mText;
-    private final ParcelFileDescriptor mFileDescriptor;
-    private final int mFlags;
-
-    /** Flag value: Entry's content was deleted to save space. */
-    public static final int IS_EMPTY = 1;
-
-    /** Flag value: Content is human-readable UTF-8 text (possibly compressed). */
-    public static final int IS_TEXT = 2;
-
-    /** Flag value: Content can been decompressed with {@link GZIPOutputStream}. */
-    public static final int IS_GZIPPED = 4;
-
-    /** Create a new DropBoxEntry with the specified contents. */
-    public DropBoxEntry(String tag, long timeMillis, String text) {
-        if (tag == null || text == null) throw new NullPointerException();
-        mTag = tag;
-        mTimeMillis = timeMillis;
-        mText = text;
-        mFileDescriptor = null;
-        mFlags = IS_TEXT;
-    }
-
-    /** Create a new DropBoxEntry with the specified contents. */
-    public DropBoxEntry(String tag, long millis, File data, int flags) throws IOException {
-        if (tag == null) throw new NullPointerException();
-        if (((flags & IS_EMPTY) != 0) != (data == null)) throw new IllegalArgumentException();
-
-        mTag = tag;
-        mTimeMillis = millis;
-        mText = null;
-        mFlags = flags;
-        mFileDescriptor = data == null ? null :
-                ParcelFileDescriptor.open(data, ParcelFileDescriptor.MODE_READ_ONLY);
-    }
-
-    /** Internal constructor for CREATOR.createFromParcel(). */
-    private DropBoxEntry(String tag, long millis, Object value, int flags) {
-        if (tag == null) throw new NullPointerException();
-        if (((flags & IS_EMPTY) != 0) != (value == null)) throw new IllegalArgumentException();
-
-        mTag = tag;
-        mTimeMillis = millis;
-        mFlags = flags;
-
-        if (value == null) {
-            mText = null;
-            mFileDescriptor = null;
-        } else if (value instanceof String) {
-            if ((flags & IS_TEXT) == 0) throw new IllegalArgumentException();
-            mText = (String) value;
-            mFileDescriptor = null;
-        } else if (value instanceof ParcelFileDescriptor) {
-            mText = null;
-            mFileDescriptor = (ParcelFileDescriptor) value;
-        } else {
-            throw new IllegalArgumentException();
-        }
-    }
-
-    /** Close the input stream associated with this entry. */
-    public synchronized void close() {
-        try { if (mFileDescriptor != null) mFileDescriptor.close(); } catch (IOException e) { }
-    }
-
-    /** @return the tag originally attached to the entry. */
-    public String getTag() { return mTag; }
-
-    /** @return time when the entry was originally created. */
-    public long getTimeMillis() { return mTimeMillis; }
-
-    /** @return flags describing the content returned by @{link #getInputStream()}. */
-    public int getFlags() { return mFlags & ~IS_GZIPPED; }  // getInputStream() decompresses.
-
-    /**
-     * @param maxLength of string to return (will truncate at this length).
-     * @return the uncompressed text contents of the entry, null if the entry is not text.
-     */
-    public String getText(int maxLength) {
-        if (mText != null) return mText.substring(0, Math.min(maxLength, mText.length()));
-        if ((mFlags & IS_TEXT) == 0) return null;
-
-        try {
-            InputStream stream = getInputStream();
-            if (stream == null) return null;
-            char[] buf = new char[maxLength];
-            InputStreamReader reader = new InputStreamReader(stream);
-            return new String(buf, 0, Math.max(0, reader.read(buf)));
-        } catch (IOException e) {
-            return null;
-        }
-    }
-
-    /** @return the uncompressed contents of the entry, or null if the contents were lost */
-    public InputStream getInputStream() throws IOException {
-        if (mText != null) return new ByteArrayInputStream(mText.getBytes("UTF8"));
-        if (mFileDescriptor == null) return null;
-        InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(mFileDescriptor);
-        return (mFlags & IS_GZIPPED) != 0 ? new GZIPInputStream(is) : is;
-    }
-
-    public static final Parcelable.Creator<DropBoxEntry> CREATOR = new Parcelable.Creator() {
-        public DropBoxEntry[] newArray(int size) { return new DropBoxEntry[size]; }
-        public DropBoxEntry createFromParcel(Parcel in) {
-            return new DropBoxEntry(
-                    in.readString(), in.readLong(), in.readValue(null), in.readInt());
-        }
-    };
-
-    public int describeContents() {
-        return mFileDescriptor != null ? Parcelable.CONTENTS_FILE_DESCRIPTOR : 0;
-    }
-
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeString(mTag);
-        out.writeLong(mTimeMillis);
-        if (mFileDescriptor != null) {
-            out.writeValue(mFileDescriptor);
-        } else {
-            out.writeValue(mText);
-        }
-        out.writeInt(mFlags);
-    }
-}
diff --git a/core/java/android/os/IDropBox.aidl b/core/java/android/os/IDropBox.aidl
deleted file mode 100644
index 26294b6..0000000
--- a/core/java/android/os/IDropBox.aidl
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.os;
-
-import android.os.DropBoxEntry;
-import android.os.ParcelFileDescriptor;
-
-/**
- * Enqueues chunks of data (from various sources -- application crashes, kernel
- * log records, etc.).  The queue is size bounded and will drop old data if the
- * enqueued data exceeds the maximum size.
- *
- * <p>This interface is implemented by a system service you can access:
- *
- * <pre>IDropBox.Stub.asInterface(ServiceManager.getService("dropbox"));</pre>
- *
- * <p>Other system services and debugging tools may scan the drop box to upload
- * entries for processing.
- *
- * {@pending}
- */
-interface IDropBox {
-    /**
-     * Stores human-readable text.  The data may be discarded eventually (or even
-     * immediately) if space is limited, or ignored entirely if the tag has been
-     * blocked (see {@link #isTagEnabled}).
-     *
-     * @param tag describing the type of entry being stored
-     * @param data value to store
-     */
-    void addText(String tag, String data);
-
-    /**
-     * Stores binary data.  The data may be ignored or discarded as with
-     * {@link #addText}.
-     *
-     * @param tag describing the type of entry being stored
-     * @param data value to store
-     * @param flags describing the data, defined in {@link DropBoxEntry}
-     */
-    void addData(String tag, in byte[] data, int flags);
-
-    /**
-     * Stores data read from a file descriptor.  The data may be ignored or
-     * discarded as with {@link #addText}.  You must close your
-     * ParcelFileDescriptor object after calling this method!
-     *
-     * @param tag describing the type of entry being stored
-     * @param data file descriptor to read from
-     * @param flags describing the data, defined in {@link DropBoxEntry}
-     */
-    void addFile(String tag, in ParcelFileDescriptor data, int flags);
-
-    /**
-     * Checks any blacklists (set in system settings) to see whether a certain
-     * tag is allowed.  Entries with disabled tags will be dropped immediately,
-     * so you can save the work of actually constructing and sending the data.
-     *
-     * @param tag that would be used in {@link #addText} or {@link #addFile}
-     * @return whether events with that tag would be accepted
-     */
-    boolean isTagEnabled(String tag);
-
-    /**
-     * Gets the next entry from the drop box *after* the specified time.
-     * Requires android.permission.READ_LOGS.  You must always call
-     * {@link DropBoxEntry#close()} on the return value!
-     *
-     * @param tag of entry to look for, null for all tags
-     * @param millis time of the last entry seen
-     * @return the next entry, or null if there are no more entries
-     */
-    DropBoxEntry getNextEntry(String tag, long millis);
-
-    // TODO: It may be useful to have some sort of notification mechanism
-    // when data is added to the dropbox, for demand-driven readers --
-    // for now readers need to poll the dropbox to find new data.
-}
diff --git a/core/java/android/pim/vcard/Constants.java b/core/java/android/pim/vcard/Constants.java
index a1c7e10..052f329 100644
--- a/core/java/android/pim/vcard/Constants.java
+++ b/core/java/android/pim/vcard/Constants.java
@@ -72,6 +72,9 @@
     // Phone number for Skype, available as usual phone.
     public static final String PROPERTY_X_SKYPE_PSTNNUMBER = "X-SKYPE-PSTNNUMBER";
 
+    // Property for Android-specific fields.
+    public static final String PROPERTY_X_ANDROID_CUSTOM = "X-ANDROID-CUSTOM";
+
     // Properties for DoCoMo vCard.
     public static final String PROPERTY_X_CLASS = "X-CLASS";
     public static final String PROPERTY_X_REDUCTION = "X-REDUCTION";
@@ -158,6 +161,9 @@
         public static final String PROPERTY_X_GOOGLE_TALK_WITH_SPACE = "X-GOOGLE TALK";
     }
 
+    // TODO: Should be in ContactsContract?
+    /* package */ static final int MAX_DATA_COLUMN = 15;
+
     private Constants() {
     }
 }
\ No newline at end of file
diff --git a/core/java/android/pim/vcard/ContactStruct.java b/core/java/android/pim/vcard/ContactStruct.java
index eb9c48a..4069729 100644
--- a/core/java/android/pim/vcard/ContactStruct.java
+++ b/core/java/android/pim/vcard/ContactStruct.java
@@ -442,7 +442,8 @@
     private List<ImData> mImList;
     private List<PhotoData> mPhotoList;
     private List<String> mWebsiteList;
-    
+    private List<List<String>> mAndroidCustomPropertyList;
+
     private final int mVCardType;
     private final Account mAccount;
 
@@ -479,23 +480,11 @@
             }
         }
 
-        final String formattedPhoneNumber;
-        {
-            final String rawPhoneNumber = builder.toString();
-            if (VCardConfig.isJapaneseDevice(mVCardType)) {
-                // As of 2009-10-07, there's no formatNumber() which accepts
-                // the second argument and returns String directly. 
-                final SpannableStringBuilder tmpBuilder =
-                    new SpannableStringBuilder(rawPhoneNumber);
-                PhoneNumberUtils.formatNumber(tmpBuilder, PhoneNumberUtils.FORMAT_JAPAN);
-                formattedPhoneNumber = tmpBuilder.toString();
-            } else {
-                // There's no information available on vCard side. Depend on the default
-                // behavior, which may cause problem in the future when the additional format
-                // rule is supported (e.g. PhoneNumberUtils.FORMAT_KLINGON)
-                formattedPhoneNumber = PhoneNumberUtils.formatNumber(rawPhoneNumber);
-            }
-        }
+        // Use NANP in default when there's no information about locale.
+        final int formattingType = (VCardConfig.isJapaneseDevice(mVCardType) ?
+                PhoneNumberUtils.FORMAT_JAPAN : PhoneNumberUtils.FORMAT_NANP);
+        final String formattedPhoneNumber =
+                PhoneNumberUtils.formatNumber(builder.toString(), formattingType);
         PhoneData phoneData = new PhoneData(type, formattedPhoneNumber, label, isPrimary);
         mPhoneList.add(phoneData);
     }
@@ -928,14 +917,19 @@
                 mWebsiteList = new ArrayList<String>(1);
             }
             mWebsiteList.add(propValue);
+        } else if (propName.equals(Constants.PROPERTY_BDAY)) {
+            mBirthday = propValue;
         } else if (propName.equals(Constants.PROPERTY_X_PHONETIC_FIRST_NAME)) {
             mPhoneticGivenName = propValue;
         } else if (propName.equals(Constants.PROPERTY_X_PHONETIC_MIDDLE_NAME)) {
             mPhoneticMiddleName = propValue;
         } else if (propName.equals(Constants.PROPERTY_X_PHONETIC_LAST_NAME)) {
             mPhoneticFamilyName = propValue;
-        } else if (propName.equals(Constants.PROPERTY_BDAY)) {
-            mBirthday = propValue;
+        } else if (propName.equals(Constants.PROPERTY_X_ANDROID_CUSTOM)) {
+            final List<String> customPropertyList =
+                VCardUtils.constructListFromValue(propValue,
+                        VCardConfig.isV30(mVCardType));
+            handleAndroidCustomProperty(customPropertyList);
         /*} else if (propName.equals("REV")) {                
             // Revision of this VCard entry. I think we can ignore this.
         } else if (propName.equals("UID")) {
@@ -963,6 +957,13 @@
         }
     }
 
+    private void handleAndroidCustomProperty(final List<String> customPropertyList) {
+        if (mAndroidCustomPropertyList == null) {
+            mAndroidCustomPropertyList = new ArrayList<List<String>>();
+        }
+        mAndroidCustomPropertyList.add(customPropertyList);
+    }
+
     /**
      * Construct the display name. The constructed data must not be null.
      */
@@ -1017,7 +1018,7 @@
             mDisplayName = "";
         }
     }
-    
+
     /**
      * Consolidate several fielsds (like mName) using name candidates, 
      */
@@ -1028,7 +1029,7 @@
             mPhoneticFullName = mPhoneticFullName.trim();
         }
     }
-    
+
     // From GoogleSource.java in Contacts app.
     private static final String ACCOUNT_TYPE_GOOGLE = "com.google";
     private static final String GOOGLE_MY_CONTACTS_GROUP = "System Group: My Contacts";
@@ -1224,6 +1225,36 @@
             operationList.add(builder.build());
         }
 
+        if (mAndroidCustomPropertyList != null) {
+            for (List<String> customPropertyList : mAndroidCustomPropertyList) {
+                int size = customPropertyList.size();
+                if (size < 2 || TextUtils.isEmpty(customPropertyList.get(0))) {
+                    continue;
+                } else if (size > Constants.MAX_DATA_COLUMN + 1) {
+                    size = Constants.MAX_DATA_COLUMN + 1;
+                    customPropertyList =
+                        customPropertyList.subList(0, Constants.MAX_DATA_COLUMN + 2);
+                }
+
+                int i = 0;
+                for (final String customPropertyValue : customPropertyList) {
+                    if (i == 0) {
+                        final String mimeType = customPropertyValue;
+                        builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
+                        builder.withValueBackReference(GroupMembership.RAW_CONTACT_ID, 0);
+                        builder.withValue(Data.MIMETYPE, mimeType);
+                    } else {  // 1 <= i && i <= MAX_DATA_COLUMNS  
+                        if (!TextUtils.isEmpty(customPropertyValue)) {
+                            builder.withValue("data" + i, customPropertyValue);
+                        }
+                    }
+
+                    operationList.add(builder.build());
+                    i++;
+                }
+            }
+        }
+
         if (myGroupsId != null) {
             builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
             builder.withValueBackReference(GroupMembership.RAW_CONTACT_ID, 0);
diff --git a/core/java/android/pim/vcard/VCardComposer.java b/core/java/android/pim/vcard/VCardComposer.java
index 8eabd4b1..6476e40 100644
--- a/core/java/android/pim/vcard/VCardComposer.java
+++ b/core/java/android/pim/vcard/VCardComposer.java
@@ -1019,11 +1019,11 @@
             return;
         }
 
-        final String propertyNickname;
+        final boolean useAndroidProperty;
         if (mIsV30) {
-            propertyNickname = Constants.PROPERTY_NICKNAME;
-        /*} else if (mUsesAndroidProperty) {
-            propertyNickname = VCARD_PROPERTY_X_NICKNAME;*/
+            useAndroidProperty = false;
+        } else if (mUsesAndroidProperty) {
+            useAndroidProperty = true;
         } else {
             // There's no way to add this field.
             return;
@@ -1034,29 +1034,13 @@
             if (TextUtils.isEmpty(nickname)) {
                 continue;
             }
-
-            final String encodedNickname;
-            final boolean reallyUseQuotedPrintable =
-                (mUsesQuotedPrintable &&
-                        !VCardUtils.containsOnlyNonCrLfPrintableAscii(nickname));
-            if (reallyUseQuotedPrintable) {
-                encodedNickname = encodeQuotedPrintable(nickname);
+            if (useAndroidProperty) {
+                appendAndroidSpecificProperty(builder, Nickname.CONTENT_ITEM_TYPE,
+                        contentValues);
             } else {
-                encodedNickname = escapeCharacters(nickname);
+                appendVCardLineWithCharsetAndQPDetection(builder,
+                        Constants.PROPERTY_NICKNAME, nickname);
             }
-
-            builder.append(propertyNickname);
-            if (shouldAppendCharsetAttribute(propertyNickname)) {
-                builder.append(VCARD_ATTR_SEPARATOR);
-                builder.append(mVCardAttributeCharset);
-            }
-            if (reallyUseQuotedPrintable) {
-                builder.append(VCARD_ATTR_SEPARATOR);
-                builder.append(VCARD_ATTR_ENCODING_QP);
-            }
-            builder.append(VCARD_DATA_SEPARATOR);
-            builder.append(encodedNickname);
-            builder.append(VCARD_COL_SEPARATOR);
         }
     }
 
@@ -1491,6 +1475,33 @@
         }
     }
 
+    private void appendAndroidSpecificProperty(final StringBuilder builder,
+            final String mimeType, ContentValues contentValues) {
+        List<String> rawDataList = new ArrayList<String>();
+        rawDataList.add(mimeType);
+        final List<String> columnNameList;
+        if (Nickname.CONTENT_ITEM_TYPE.equals(mimeType)) {
+            
+        } else {
+            // If you add the other field, please check all the columns are able to be
+            // converted to String.
+            //
+            // e.g. BLOB is not what we can handle here now.
+            return;
+        }
+
+        for (int i = 1; i <= Constants.MAX_DATA_COLUMN; i++) {
+            String value = contentValues.getAsString("data" + i);
+            if (value == null) {
+                value = "";
+            }
+            rawDataList.add(value);
+        }
+
+        appendVCardLineWithCharsetAndQPDetection(builder,
+                Constants.PROPERTY_X_ANDROID_CUSTOM, rawDataList);
+    }
+
     /**
      * Append '\' to the characters which should be escaped. The character set is different
      * not only between vCard 2.1 and vCard 3.0 but also among each device.
@@ -1968,6 +1979,8 @@
         }
     }
 
+    // appendVCardLine() variants accepting one String.
+
     private void appendVCardLineWithCharsetAndQPDetection(final StringBuilder builder,
             final String propertyName, final String rawData) {
         appendVCardLineWithCharsetAndQPDetection(builder, propertyName, null, rawData);
@@ -2026,6 +2039,87 @@
         builder.append(VCARD_COL_SEPARATOR);
     }
 
+    // appendVCardLine() variants accepting List<String>.
+
+    private void appendVCardLineWithCharsetAndQPDetection(final StringBuilder builder,
+            final String propertyName, final List<String> rawDataList) {
+        appendVCardLineWithCharsetAndQPDetection(builder, propertyName, null, rawDataList);
+    }
+
+    private void appendVCardLineWithCharsetAndQPDetection(final StringBuilder builder,
+            final String propertyName,
+            final List<String> attributeList, final List<String> rawDataList) {
+        boolean needCharset = false;
+        boolean reallyUseQuotedPrintable = false;
+        for (String rawData : rawDataList) {
+            if (!needCharset && mUsesQuotedPrintable &&
+                    !VCardUtils.containsOnlyPrintableAscii(rawData)) {
+                needCharset = true;
+            }
+            if (!reallyUseQuotedPrintable &&
+                    !VCardUtils.containsOnlyNonCrLfPrintableAscii(rawData)) {
+                reallyUseQuotedPrintable = true;
+            }
+            if (needCharset && reallyUseQuotedPrintable) {
+                break;
+            }
+        }
+
+        appendVCardLine(builder, propertyName, attributeList,
+                rawDataList, needCharset, reallyUseQuotedPrintable);
+    }
+
+    /*
+    private void appendVCardLine(final StringBuilder builder,
+            final String propertyName, final List<String> rawDataList) {
+        appendVCardLine(builder, propertyName, rawDataList, false, false);
+    }
+
+    private void appendVCardLine(final StringBuilder builder,
+            final String propertyName, final List<String> rawDataList,
+            final boolean needCharset, boolean needQuotedPrintable) {
+        appendVCardLine(builder, propertyName, null, rawDataList, needCharset, needQuotedPrintable);
+    }*/
+
+    private void appendVCardLine(final StringBuilder builder,
+            final String propertyName,
+            final List<String> attributeList,
+            final List<String> rawDataList, final boolean needCharset,
+            boolean needQuotedPrintable) {
+        builder.append(propertyName);
+        if (attributeList != null && attributeList.size() > 0) {
+            builder.append(VCARD_ATTR_SEPARATOR);
+            appendTypeAttributes(builder, attributeList);
+        }
+        if (needCharset) {
+            builder.append(VCARD_ATTR_SEPARATOR);
+            builder.append(mVCardAttributeCharset);
+        }
+
+        builder.append(VCARD_DATA_SEPARATOR);
+        boolean first = true;
+        for (String rawData : rawDataList) {
+            final String encodedData;
+            if (needQuotedPrintable) {
+                builder.append(VCARD_ATTR_SEPARATOR);
+                builder.append(VCARD_ATTR_ENCODING_QP);
+                encodedData = encodeQuotedPrintable(rawData);
+            } else {
+                // TODO: one line may be too huge, which may be invalid in vCard spec, though
+                //       several (even well-known) applications do not care this.
+                encodedData = escapeCharacters(rawData);
+            }
+
+            if (first) {
+                first = false;
+            } else {
+                builder.append(VCARD_ITEM_SEPARATOR);
+            }
+            builder.append(encodedData);
+        }
+        builder.append(VCARD_COL_SEPARATOR);
+    }
+
     /**
      * VCARD_ATTR_SEPARATOR must be appended before this method being called.
      */
diff --git a/core/java/com/android/internal/os/IDropBoxService.aidl b/core/java/com/android/internal/os/IDropBoxService.aidl
new file mode 100644
index 0000000..f940041
--- /dev/null
+++ b/core/java/com/android/internal/os/IDropBoxService.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import android.os.DropBox;
+import android.os.ParcelFileDescriptor;
+
+/**
+ * "Backend" interface used by {@link android.os.DropBox} to talk to the
+ * DropBoxService that actually implements the drop box functionality.
+ *
+ * @see DropBox
+ * @hide
+ */
+interface IDropBoxService {
+    /**
+     * @see DropBox#addText
+     * @see DropBox#addData
+     * @see DropBox#addFile
+     */
+    void add(in DropBox.Entry entry);
+
+    /** @see DropBox#getNextEntry */
+    boolean isTagEnabled(String tag);
+
+    /** @see DropBox#getNextEntry */
+    DropBox.Entry getNextEntry(String tag, long millis);
+}
diff --git a/core/res/Android.mk b/core/res/Android.mk
index cb5524a..78cb86d 100644
--- a/core/res/Android.mk
+++ b/core/res/Android.mk
@@ -34,3 +34,7 @@
 LOCAL_EXPORT_PACKAGE_RESOURCES := true
 
 include $(BUILD_PACKAGE)
+
+# define a global intermediate target that other module may depend on.
+.PHONY: framework-res-package-target
+framework-res-package-target: $(LOCAL_BUILT_MODULE)
diff --git a/data/sounds/ringtones/FreeFlight.ogg b/data/sounds/ringtones/FreeFlight.ogg
new file mode 100644
index 0000000..76dfabe
--- /dev/null
+++ b/data/sounds/ringtones/FreeFlight.ogg
Binary files differ
diff --git a/data/sounds/ringtones/FreeFlight.wav b/data/sounds/ringtones/FreeFlight.wav
new file mode 100644
index 0000000..a4e14aa
--- /dev/null
+++ b/data/sounds/ringtones/FreeFlight.wav
Binary files differ
diff --git a/docs/html/sdk/download.jd b/docs/html/sdk/download.jd
index 76f1213..47505e6 100644
--- a/docs/html/sdk/download.jd
+++ b/docs/html/sdk/download.jd
@@ -58,7 +58,7 @@
   <h2>Thank you for downloading the Android SDK!</h2>
   <p>Your download should be underway. If not, <a id="click-download">click here to start the download</a>.</p>
   <p>To set up your Android development environment, please read the guide to
-    <a href="installing.html" class="addVersionPath">Installing the Android SDK</a>.
+    <a href="installing.html">Installing the Android SDK</a>.
     Once you have completed the installation, see the
     <a href="/guide/index.html">Dev Guide</a> for documentation about
     developing Android applications.</p>
diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h
index 8897f03..2172536 100644
--- a/include/ui/GraphicBuffer.h
+++ b/include/ui/GraphicBuffer.h
@@ -66,7 +66,11 @@
     GraphicBuffer();
 
     // creates w * h buffer
-    GraphicBuffer(uint32_t w, uint32_t h, PixelFormat format, uint32_t ssage);
+    GraphicBuffer(uint32_t w, uint32_t h, PixelFormat format, uint32_t usage);
+
+    // create a buffer from an existing handle
+    GraphicBuffer(uint32_t w, uint32_t h, PixelFormat format, uint32_t usage,
+            uint32_t stride, native_handle_t* handle, bool keepOwnership);
 
     // return status
     status_t initCheck() const;
@@ -94,9 +98,15 @@
     GraphicBuffer(const Parcel& reply);
     virtual ~GraphicBuffer();
 
+    enum {
+        ownNone   = 0,
+        ownHandle = 1,
+        ownData   = 2,
+    };
+
     inline const GraphicBufferMapper& getBufferMapper() const { return mBufferMapper; }
     inline GraphicBufferMapper& getBufferMapper() { return mBufferMapper; }
-    bool mOwner;
+    uint8_t mOwner;
 
 private:
     friend class Surface;
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index cc39dac..eb388af 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -30,8 +30,21 @@
 
 pthread_key_t Context::gThreadTLSKey = 0;
 uint32_t Context::gThreadTLSKeyCount = 0;
+uint32_t Context::gGLContextCount = 0;
 pthread_mutex_t Context::gInitMutex = PTHREAD_MUTEX_INITIALIZER;
 
+static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) {
+    if (returnVal != EGL_TRUE) {
+        fprintf(stderr, "%s() returned %d\n", op, returnVal);
+    }
+
+    for (EGLint error = eglGetError(); error != EGL_SUCCESS; error
+            = eglGetError()) {
+        fprintf(stderr, "after %s() eglError %s (0x%x)\n", op, EGLUtils::strerror(error),
+                error);
+    }
+}
+
 void Context::initEGL()
 {
     mEGL.mNumConfigs = -1;
@@ -61,7 +74,10 @@
 
     LOGV("initEGL start");
     mEGL.mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    checkEglError("eglGetDisplay");
+
     eglInitialize(mEGL.mDisplay, &mEGL.mMajorVersion, &mEGL.mMinorVersion);
+    checkEglError("eglInitialize");
 
     status_t err = EGLUtils::selectConfigForNativeWindow(mEGL.mDisplay, configAttribs, mWndSurface, &mEGL.mConfig);
     if (err) {
@@ -76,9 +92,24 @@
              android_createDisplaySurface(),
              NULL);
     }
+    checkEglError("eglCreateWindowSurface");
+    if (mEGL.mSurface == EGL_NO_SURFACE) {
+        LOGE("eglCreateWindowSurface returned EGL_NO_SURFACE");
+    }
 
-    mEGL.mContext = eglCreateContext(mEGL.mDisplay, mEGL.mConfig, NULL, NULL);
-    eglMakeCurrent(mEGL.mDisplay, mEGL.mSurface, mEGL.mSurface, mEGL.mContext);
+    mEGL.mContext = eglCreateContext(mEGL.mDisplay, mEGL.mConfig, EGL_NO_CONTEXT, NULL);
+    checkEglError("eglCreateContext");
+    if (mEGL.mContext == EGL_NO_CONTEXT) {
+        LOGE("eglCreateContext returned EGL_NO_CONTEXT");
+    }
+    gGLContextCount++;
+
+    EGLBoolean ret = eglMakeCurrent(mEGL.mDisplay, mEGL.mSurface, mEGL.mSurface, mEGL.mContext);
+    checkEglError("eglCreateContext", ret);
+    if (mEGL.mContext == EGL_NO_CONTEXT) {
+        LOGE("eglCreateContext returned EGL_NO_CONTEXT");
+    }
+
     eglQuerySurface(mEGL.mDisplay, mEGL.mSurface, EGL_WIDTH, &mEGL.mWidth);
     eglQuerySurface(mEGL.mDisplay, mEGL.mSurface, EGL_HEIGHT, &mEGL.mHeight);
 
@@ -101,6 +132,24 @@
     }
 }
 
+void Context::deinitEGL()
+{
+    EGLBoolean ret = eglMakeCurrent(mEGL.mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+    checkEglError("eglCreateContext", ret);
+    if (mEGL.mContext == EGL_NO_CONTEXT) {
+        LOGE("eglCreateContext returned EGL_NO_CONTEXT");
+    }
+
+    eglDestroyContext(mEGL.mDisplay, mEGL.mContext);
+    checkEglError("eglDestroyContext");
+
+    gGLContextCount--;
+    if (!gGLContextCount) {
+        eglTerminate(mEGL.mDisplay);
+    }
+}
+
+
 bool Context::runScript(Script *s, uint32_t launchID)
 {
     ObjectBaseRef<ProgramFragment> frag(mFragment);
@@ -232,7 +281,9 @@
      rsc->props.mLogScripts = getProp("debug.rs.script");
      rsc->props.mLogObjects = getProp("debug.rs.objects");
 
+     pthread_mutex_lock(&gInitMutex);
      rsc->initEGL();
+     pthread_mutex_unlock(&gInitMutex);
 
      ScriptTLSStruct *tlsStruct = new ScriptTLSStruct;
      if (!tlsStruct) {
@@ -294,7 +345,11 @@
      glClearColor(0,0,0,0);
      glClear(GL_COLOR_BUFFER_BIT);
      eglSwapBuffers(rsc->mEGL.mDisplay, rsc->mEGL.mSurface);
-     eglTerminate(rsc->mEGL.mDisplay);
+
+     pthread_mutex_lock(&gInitMutex);
+     rsc->deinitEGL();
+     pthread_mutex_unlock(&gInitMutex);
+
      rsc->objDestroyOOBRun();
      LOGV("RS Thread exited");
      return NULL;
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index 0dd90ed..c80fd5a 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -54,6 +54,7 @@
 
     static pthread_key_t gThreadTLSKey;
     static uint32_t gThreadTLSKeyCount;
+    static uint32_t gGLContextCount;
     static pthread_mutex_t gInitMutex;
 
     struct ScriptTLSStruct {
@@ -215,6 +216,7 @@
     Context();
 
     void initEGL();
+    void deinitEGL();
 
     bool runRootScript();
 
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index f84933e..1abfd68 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -256,12 +256,16 @@
     if (strstr(gl_extensions, "GL_OES_draw_texture")) {
         mFlags |= DRAW_TEXTURE_EXTENSION;
     }
+#ifdef EGL_ANDROID_image_native_buffer
     if (strstr( gl_extensions, "GL_OES_EGL_image") &&
         (strstr(egl_extensions, "EGL_KHR_image_base") || 
                 strstr(egl_extensions, "EGL_KHR_image")) &&
         strstr(egl_extensions, "EGL_ANDROID_image_native_buffer")) {
         mFlags |= DIRECT_TEXTURE;
     }
+#else
+#warning "EGL_ANDROID_image_native_buffer not supported"
+#endif
 
     // Unbind the context from this thread
     eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp
index 2bb1e12..f5a5a0b 100644
--- a/libs/surfaceflinger/Layer.cpp
+++ b/libs/surfaceflinger/Layer.cpp
@@ -130,62 +130,6 @@
     return NO_ERROR;
 }
 
-status_t Layer::initializeEglImageLocked(
-        const sp<GraphicBuffer>& buffer, Texture* texture)
-{
-    status_t err = NO_ERROR;
-
-    // we need to recreate the texture
-    EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
-
-    // free the previous image
-    if (texture->image != EGL_NO_IMAGE_KHR) {
-        eglDestroyImageKHR(dpy, texture->image);
-        texture->image = EGL_NO_IMAGE_KHR;
-    }
-
-    // construct an EGL_NATIVE_BUFFER_ANDROID
-    android_native_buffer_t* clientBuf = buffer->getNativeBuffer();
-
-    // create the new EGLImageKHR
-    const EGLint attrs[] = {
-            EGL_IMAGE_PRESERVED_KHR,    EGL_TRUE,
-            EGL_NONE,                   EGL_NONE
-    };
-    texture->image = eglCreateImageKHR(
-            dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
-            (EGLClientBuffer)clientBuf, attrs);
-
-    LOGE_IF(texture->image == EGL_NO_IMAGE_KHR,
-            "eglCreateImageKHR() failed. err=0x%4x",
-            eglGetError());
-
-    if (texture->image != EGL_NO_IMAGE_KHR) {
-        glBindTexture(GL_TEXTURE_2D, texture->name);
-        glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,
-                (GLeglImageOES)texture->image);
-        GLint error = glGetError();
-        if (UNLIKELY(error != GL_NO_ERROR)) {
-            // this failed, for instance, because we don't support NPOT.
-            // FIXME: do something!
-            LOGE("layer=%p, glEGLImageTargetTexture2DOES(%p) "
-                 "failed err=0x%04x",
-                 this, texture->image, error);
-            mFlags &= ~DisplayHardware::DIRECT_TEXTURE;
-            err = INVALID_OPERATION;
-        } else {
-            // Everything went okay!
-            texture->NPOTAdjust = false;
-            texture->dirty  = false;
-            texture->width  = clientBuf->width;
-            texture->height = clientBuf->height;
-        }
-    } else {
-        err = INVALID_OPERATION;
-    }
-    return err;
-}
-
 void Layer::reloadTexture(const Region& dirty)
 {
     Mutex::Autolock _l(mLock);
@@ -199,10 +143,11 @@
         mTextures[index].height = 0;
     }
 
+#ifdef EGL_ANDROID_image_native_buffer
     if (mFlags & DisplayHardware::DIRECT_TEXTURE) {
         if (buffer->usage & GraphicBuffer::USAGE_HW_TEXTURE) {
             if (mTextures[index].dirty) {
-                initializeEglImageLocked(buffer, &mTextures[index]);
+                initializeEglImage(buffer, &mTextures[index]);
             }
         } else {
             if (mHybridBuffer==0 || (mHybridBuffer->width != buffer->width ||
@@ -212,7 +157,7 @@
                         buffer->width, buffer->height, buffer->format,
                         GraphicBuffer::USAGE_SW_WRITE_OFTEN |
                         GraphicBuffer::USAGE_HW_TEXTURE);
-                initializeEglImageLocked(
+                initializeEglImage(
                         mHybridBuffer, &mTextures[0]);
             }
 
@@ -279,7 +224,9 @@
                 buffer->unlock();
             }
         }
-    } else {
+    } else
+#endif
+    {
         for (size_t i=0 ; i<NUM_BUFFERS ; i++) {
             mTextures[i].image = EGL_NO_IMAGE_KHR;
         }
diff --git a/libs/surfaceflinger/Layer.h b/libs/surfaceflinger/Layer.h
index 57b3dfa..1310ecc 100644
--- a/libs/surfaceflinger/Layer.h
+++ b/libs/surfaceflinger/Layer.h
@@ -85,8 +85,6 @@
     }
  
     void reloadTexture(const Region& dirty);
-    status_t initializeEglImageLocked(
-            const sp<GraphicBuffer>& buffer, Texture* texture);
 
     uint32_t getEffectiveUsage(uint32_t usage) const;
 
diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp
index ecc7894..8003d22 100644
--- a/libs/surfaceflinger/LayerBase.cpp
+++ b/libs/surfaceflinger/LayerBase.cpp
@@ -617,6 +617,63 @@
     }
 }
 
+status_t LayerBase::initializeEglImage(
+        const sp<GraphicBuffer>& buffer, Texture* texture)
+{
+    status_t err = NO_ERROR;
+
+    // we need to recreate the texture
+    EGLDisplay dpy(mFlinger->graphicPlane(0).getEGLDisplay());
+
+    // free the previous image
+    if (texture->image != EGL_NO_IMAGE_KHR) {
+        eglDestroyImageKHR(dpy, texture->image);
+        texture->image = EGL_NO_IMAGE_KHR;
+    }
+
+    // construct an EGL_NATIVE_BUFFER_ANDROID
+    android_native_buffer_t* clientBuf = buffer->getNativeBuffer();
+
+    // create the new EGLImageKHR
+    const EGLint attrs[] = {
+            EGL_IMAGE_PRESERVED_KHR,    EGL_TRUE,
+            EGL_NONE,                   EGL_NONE
+    };
+    texture->image = eglCreateImageKHR(
+            dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+            (EGLClientBuffer)clientBuf, attrs);
+
+    LOGE_IF(texture->image == EGL_NO_IMAGE_KHR,
+            "eglCreateImageKHR() failed. err=0x%4x",
+            eglGetError());
+
+    if (texture->image != EGL_NO_IMAGE_KHR) {
+        glBindTexture(GL_TEXTURE_2D, texture->name);
+        glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,
+                (GLeglImageOES)texture->image);
+        GLint error = glGetError();
+        if (UNLIKELY(error != GL_NO_ERROR)) {
+            // this failed, for instance, because we don't support NPOT.
+            // FIXME: do something!
+            LOGE("layer=%p, glEGLImageTargetTexture2DOES(%p) "
+                 "failed err=0x%04x",
+                 this, texture->image, error);
+            mFlags &= ~DisplayHardware::DIRECT_TEXTURE;
+            err = INVALID_OPERATION;
+        } else {
+            // Everything went okay!
+            texture->NPOTAdjust = false;
+            texture->dirty  = false;
+            texture->width  = clientBuf->width;
+            texture->height = clientBuf->height;
+        }
+    } else {
+        err = INVALID_OPERATION;
+    }
+    return err;
+}
+
+
 // ---------------------------------------------------------------------------
 
 int32_t LayerBaseClient::sIdentity = 0;
diff --git a/libs/surfaceflinger/LayerBase.h b/libs/surfaceflinger/LayerBase.h
index efa4f8c..ed07b3f 100644
--- a/libs/surfaceflinger/LayerBase.h
+++ b/libs/surfaceflinger/LayerBase.h
@@ -261,6 +261,8 @@
           void drawWithOpenGL(const Region& clip, const Texture& texture) const;
           void loadTexture(Texture* texture, 
                   const Region& dirty, const GGLSurface& t) const;
+          status_t initializeEglImage(
+                  const sp<GraphicBuffer>& buffer, Texture* texture);
 
           
                 sp<SurfaceFlinger> mFlinger;
diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp
index 7e27a02..6590503 100644
--- a/libs/surfaceflinger/LayerBuffer.cpp
+++ b/libs/surfaceflinger/LayerBuffer.cpp
@@ -339,12 +339,6 @@
     mLayer.setNeedsBlending((info.h_alpha - info.l_alpha) > 0);    
     mBufferSize = info.getScanlineSize(buffers.hor_stride)*buffers.ver_stride;
     mLayer.forceVisibilityTransaction();
-
-    hw_module_t const* module;
-    mBlitEngine = NULL;
-    if (hw_get_module(COPYBIT_HARDWARE_MODULE_ID, &module) == 0) {
-        copybit_open(module, &mBlitEngine);
-    }
 }
 
 LayerBuffer::BufferSource::~BufferSource()
@@ -352,8 +346,9 @@
     if (mTexture.name != -1U) {
         glDeleteTextures(1, &mTexture.name);
     }
-    if (mBlitEngine) {
-        copybit_close(mBlitEngine);
+    if (mTexture.image != EGL_NO_IMAGE_KHR) {
+        EGLDisplay dpy(mLayer.mFlinger->graphicPlane(0).getEGLDisplay());
+        eglDestroyImageKHR(dpy, mTexture.image);
     }
 }
 
@@ -421,122 +416,28 @@
     status_t err = NO_ERROR;
     NativeBuffer src(ourBuffer->getBuffer());
     const Rect transformedBounds(mLayer.getTransformedBounds());
-    copybit_device_t* copybit = mBlitEngine;
 
-    if (copybit)  {
-        const int src_width  = src.crop.r - src.crop.l;
-        const int src_height = src.crop.b - src.crop.t;
-        int W = transformedBounds.width();
-        int H = transformedBounds.height();
-        if (mLayer.getOrientation() & Transform::ROT_90) {
-            int t(W); W=H; H=t;
-        }
+    if (UNLIKELY(mTexture.name == -1LU)) {
+        mTexture.name = mLayer.createTexture();
+    }
 
-#ifdef EGL_ANDROID_get_render_buffer
-        EGLDisplay dpy = eglGetCurrentDisplay();
-        EGLSurface draw = eglGetCurrentSurface(EGL_DRAW); 
-        EGLClientBuffer clientBuf = eglGetRenderBufferANDROID(dpy, draw);
-        android_native_buffer_t* nb = (android_native_buffer_t*)clientBuf;
-        if (nb == 0) {
-            err = BAD_VALUE;
-        } else {
-            copybit_image_t dst;
-            dst.w       = nb->width;
-            dst.h       = nb->height;
-            dst.format  = nb->format;
-            dst.base    = NULL; // unused by copybit on msm7k
-            dst.handle  = (native_handle_t *)nb->handle;
+#if defined(EGL_ANDROID_image_native_buffer)
+    if (mLayer.mFlags & DisplayHardware::DIRECT_TEXTURE) {
+         // NOTE: Assume the buffer is  allocated with the proper USAGE flags
+        sp<GraphicBuffer> graphicBuffer = new GraphicBuffer(
+                src.crop.r, src.crop.b, src.img.format, 
+                GraphicBuffer::USAGE_HW_TEXTURE,
+                src.img.w, src.img.handle, false);
 
-            /* With LayerBuffer, it is likely that we'll have to rescale the
-             * surface, because this is often used for video playback or
-             * camera-preview. Since we want these operation as fast as possible
-             * we make sure we can use the 2D H/W even if it doesn't support
-             * the requested scale factor, in which case we perform the scaling
-             * in several passes. */
-
-            const float min = copybit->get(copybit, COPYBIT_MINIFICATION_LIMIT);
-            const float mag = copybit->get(copybit, COPYBIT_MAGNIFICATION_LIMIT);
-
-            float xscale = 1.0f;
-            if (src_width > W*min)          xscale = 1.0f / min;
-            else if (src_width*mag < W)     xscale = mag;
-
-            float yscale = 1.0f;
-            if (src_height > H*min)         yscale = 1.0f / min;
-            else if (src_height*mag < H)    yscale = mag;
-
-            if (UNLIKELY(xscale!=1.0f || yscale!=1.0f)) {
-                const int tmp_w = floorf(src_width  * xscale);
-                const int tmp_h = floorf(src_height * yscale);
-                
-                if (mTempBitmap==0 || 
-                        mTempBitmap->getWidth() < size_t(tmp_w) || 
-                        mTempBitmap->getHeight() < size_t(tmp_h)) {
-                    mTempBitmap.clear();
-                    mTempBitmap = new GraphicBuffer(
-                            tmp_w, tmp_h, src.img.format, 
-                            GraphicBuffer::USAGE_HW_2D);
-                    err = mTempBitmap->initCheck();
-                }
-
-                if (LIKELY(err == NO_ERROR)) {
-                    NativeBuffer tmp;
-                    tmp.img.w = tmp_w;
-                    tmp.img.h = tmp_h;
-                    tmp.img.format = src.img.format;
-                    tmp.img.handle = (native_handle_t*)mTempBitmap->getNativeBuffer()->handle;
-                    tmp.crop.l = 0;
-                    tmp.crop.t = 0;
-                    tmp.crop.r = tmp.img.w;
-                    tmp.crop.b = tmp.img.h;
-
-                    region_iterator tmp_it(Region(Rect(tmp.crop.r, tmp.crop.b)));
-                    copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
-                    copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
-                    copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE);
-                    err = copybit->stretch(copybit,
-                            &tmp.img, &src.img, &tmp.crop, &src.crop, &tmp_it);
-                    src = tmp;
-                }
-            }
-
-            const Rect transformedBounds(mLayer.getTransformedBounds());
-            const copybit_rect_t& drect =
-                reinterpret_cast<const copybit_rect_t&>(transformedBounds);
-            const State& s(mLayer.drawingState());
-            region_iterator it(clip);
-
-            // pick the right orientation for this buffer
-            int orientation = mLayer.getOrientation();
-            if (UNLIKELY(mBufferHeap.transform)) {
-                Transform rot90;
-                GraphicPlane::orientationToTransfrom(
-                        ISurfaceComposer::eOrientation90, 0, 0, &rot90);
-                const Transform& planeTransform(mLayer.graphicPlane(0).transform());
-                const Layer::State& s(mLayer.drawingState());
-                Transform tr(planeTransform * s.transform * rot90);
-                orientation = tr.getOrientation();
-            }
-
-            copybit->set_parameter(copybit, COPYBIT_TRANSFORM, orientation);
-            copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, s.alpha);
-            copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_ENABLE);
-
-            err = copybit->stretch(copybit,
-                    &dst, &src.img, &drect, &src.crop, &it);
-            if (err != NO_ERROR) {
-                LOGE("copybit failed (%s)", strerror(err));
-            }
-        }
+        err = mLayer.initializeEglImage(graphicBuffer, &mTexture);
     }
 #endif
-    
-    if (!copybit || err) 
-    {
+    else {
+        err = INVALID_OPERATION;
+    }
+
+    if (err != NO_ERROR) {
         // OpenGL fall-back
-        if (UNLIKELY(mTexture.name == -1LU)) {
-            mTexture.name = mLayer.createTexture();
-        }
         GLuint w = 0;
         GLuint h = 0;
         GGLSurface t;
@@ -549,11 +450,11 @@
         t.data = (GGLubyte*)src.img.base;
         const Region dirty(Rect(t.width, t.height));
         mLayer.loadTexture(&mTexture, dirty, t);
-        mTexture.transform = mBufferHeap.transform;
-        mLayer.drawWithOpenGL(clip, mTexture);
     }
-}
 
+    mTexture.transform = mBufferHeap.transform;
+    mLayer.drawWithOpenGL(clip, mTexture);
+}
 
 // ---------------------------------------------------------------------------
 
diff --git a/libs/surfaceflinger/LayerBuffer.h b/libs/surfaceflinger/LayerBuffer.h
index 5eb472c..438b711 100644
--- a/libs/surfaceflinger/LayerBuffer.h
+++ b/libs/surfaceflinger/LayerBuffer.h
@@ -132,7 +132,6 @@
         size_t                          mBufferSize;
         mutable sp<GraphicBuffer>       mTempBitmap;
         mutable LayerBase::Texture      mTexture;
-        copybit_device_t*               mBlitEngine;
     };
     
     class OverlaySource : public Source {
diff --git a/libs/surfaceflinger/LayerDim.cpp b/libs/surfaceflinger/LayerDim.cpp
index 538dc77..fd61e30 100644
--- a/libs/surfaceflinger/LayerDim.cpp
+++ b/libs/surfaceflinger/LayerDim.cpp
@@ -55,8 +55,8 @@
     sHeight = h;
     sUseTexture = false;
     
-#ifdef DIM_WITH_TEXTURE
-    
+#if defined(DIM_WITH_TEXTURE) && defined(EGL_ANDROID_image_native_buffer)
+
 #warning "using a texture to implement LayerDim"
     
     /* On some h/w like msm7K, it is faster to use a texture because the
@@ -69,7 +69,6 @@
     uint32_t flags = hw.getFlags();
 
     if (LIKELY(flags & DisplayHardware::DIRECT_TEXTURE)) {
-        // TODO: api to pass the usage flags
         sp<GraphicBuffer> buffer = new GraphicBuffer(w, h, PIXEL_FORMAT_RGB_565,
                  GraphicBuffer::USAGE_SW_WRITE_OFTEN |
                  GraphicBuffer::USAGE_HW_TEXTURE);
@@ -123,7 +122,7 @@
         glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
         glColor4x(0, 0, 0, alpha);
         
-#ifdef DIM_WITH_TEXTURE
+#if defined(DIM_WITH_TEXTURE) && defined(EGL_ANDROID_image_native_buffer)
         if (sUseTexture) {
             glBindTexture(GL_TEXTURE_2D, sTexId);
             glEnable(GL_TEXTURE_2D);
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 1cf20d7..efe2d78 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -37,7 +37,7 @@
 // ===========================================================================
 
 GraphicBuffer::GraphicBuffer()
-    : BASE(), mOwner(false), mBufferMapper(GraphicBufferMapper::get()),
+    : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),
       mInitCheck(NO_ERROR),  mVStride(0), mIndex(-1)
 {
     width  = 
@@ -50,7 +50,7 @@
 
 GraphicBuffer::GraphicBuffer(uint32_t w, uint32_t h, 
         PixelFormat reqFormat, uint32_t reqUsage)
-    : BASE(), mOwner(false), mBufferMapper(GraphicBufferMapper::get()),
+    : BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),
       mInitCheck(NO_ERROR),  mVStride(0), mIndex(-1)
 {
     width  = 
@@ -62,8 +62,23 @@
     mInitCheck = initSize(w, h, reqFormat, reqUsage);
 }
 
+GraphicBuffer::GraphicBuffer(uint32_t w, uint32_t h,
+        PixelFormat inFormat, uint32_t inUsage,
+        uint32_t inStride, native_handle_t* inHandle, bool keepOwnership)
+    : BASE(), mOwner(keepOwnership ? ownHandle : ownNone),
+      mBufferMapper(GraphicBufferMapper::get()),
+      mInitCheck(NO_ERROR),  mVStride(0), mIndex(-1)
+{
+    width  = w;
+    height = h;
+    stride = inStride;
+    format = inFormat;
+    usage  = inUsage;
+    handle = inHandle;
+}
+
 GraphicBuffer::GraphicBuffer(const Parcel& data) 
-    : BASE(), mOwner(true), mBufferMapper(GraphicBufferMapper::get()),
+    : BASE(), mOwner(ownHandle), mBufferMapper(GraphicBufferMapper::get()),
       mInitCheck(NO_ERROR),  mVStride(0), mIndex(-1)
 {
     // we own the handle in this case
@@ -83,10 +98,10 @@
 GraphicBuffer::~GraphicBuffer()
 {
     if (handle) {
-        if (mOwner) {
+        if (mOwner == ownHandle) {
             native_handle_close(handle);
             native_handle_delete(const_cast<native_handle*>(handle));
-        } else {
+        } else if (mOwner == ownData) {
             GraphicBufferAllocator& allocator(GraphicBufferAllocator::get());
             allocator.free(handle);
         }
@@ -106,6 +121,9 @@
 status_t GraphicBuffer::reallocate(uint32_t w, uint32_t h, PixelFormat f,
         uint32_t reqUsage)
 {
+    if (mOwner != ownData)
+        return INVALID_OPERATION;
+
     if (handle) {
         GraphicBufferAllocator& allocator(GraphicBufferAllocator::get());
         allocator.free(handle);
diff --git a/media/java/android/media/AsyncPlayer.java b/media/java/android/media/AsyncPlayer.java
index 35f0409..e1e09b9 100644
--- a/media/java/android/media/AsyncPlayer.java
+++ b/media/java/android/media/AsyncPlayer.java
@@ -19,10 +19,12 @@
 import android.content.Context;
 import android.net.Uri;
 import android.os.PowerManager;
+import android.os.SystemClock;
 import android.util.Log;
 
 import java.io.IOException;
 import java.lang.IllegalStateException;
+import java.util.LinkedList;
 
 /**
  * Plays a series of audio URIs, but does all the hard work on another thread
@@ -31,14 +33,15 @@
 public class AsyncPlayer {
     private static final int PLAY = 1;
     private static final int STOP = 2;
+    private static final boolean mDebug = false;
 
     private static final class Command {
-        Command next;
         int code;
         Context context;
         Uri uri;
         boolean looping;
         int stream;
+        long requestTime;
 
         public String toString() {
             return "{ code=" + code + " looping=" + looping + " stream=" + stream
@@ -46,6 +49,36 @@
         }
     }
 
+    private LinkedList<Command> mCmdQueue = new LinkedList();
+
+    private void startSound(Command cmd) {
+        // Preparing can be slow, so if there is something else
+        // is playing, let it continue until we're done, so there
+        // is less of a glitch.
+        try {
+            if (mDebug) Log.d(mTag, "Starting playback");
+            MediaPlayer player = new MediaPlayer();
+            player.setAudioStreamType(cmd.stream);
+            player.setDataSource(cmd.context, cmd.uri);
+            player.setLooping(cmd.looping);
+            player.prepare();
+            player.start();
+            if (mPlayer != null) {
+                mPlayer.release();
+            }
+            mPlayer = player;
+            long delay = SystemClock.uptimeMillis() - cmd.requestTime;
+            if (delay > 1000) {
+                Log.w(mTag, "Notification sound delayed by " + delay + "msecs");
+            }
+        }
+        catch (IOException e) {
+            Log.w(mTag, "error loading sound for " + cmd.uri, e);
+        } catch (IllegalStateException e) {
+            Log.w(mTag, "IllegalStateException (content provider died?) " + cmd.uri, e);
+        }
+    }
+
     private final class Thread extends java.lang.Thread {
         Thread() {
             super("AsyncPlayer-" + mTag);
@@ -55,41 +88,23 @@
             while (true) {
                 Command cmd = null;
 
-                synchronized (mLock) {
-                    if (mHead != null) {
-                        cmd = mHead;
-                        mHead = cmd.next;
-                        if (mTail == cmd) {
-                            mTail = null;
-                        }
-                    }
+                synchronized (mCmdQueue) {
+                    if (mDebug) Log.d(mTag, "RemoveFirst");
+                    cmd = mCmdQueue.removeFirst();
                 }
 
                 switch (cmd.code) {
                 case PLAY:
-                    try {
-                        // Preparing can be slow, so if there is something else
-                        // is playing, let it continue until we're done, so there
-                        // is less of a glitch.
-                        MediaPlayer player = new MediaPlayer();
-                        player.setAudioStreamType(cmd.stream);
-                        player.setDataSource(cmd.context, cmd.uri);
-                        player.setLooping(cmd.looping);
-                        player.prepare();
-                        player.start();
-                        if (mPlayer != null) {
-                            mPlayer.release();
-                        }
-                        mPlayer = player;
-                    }
-                    catch (IOException e) {
-                        Log.w(mTag, "error loading sound for " + cmd.uri, e);
-                    } catch (IllegalStateException e) {
-                        Log.w(mTag, "IllegalStateException (content provider died?) " + cmd.uri, e);
-                    }
+                    if (mDebug) Log.d(mTag, "PLAY");
+                    startSound(cmd);
                     break;
                 case STOP:
+                    if (mDebug) Log.d(mTag, "STOP");
                     if (mPlayer != null) {
+                        long delay = SystemClock.uptimeMillis() - cmd.requestTime;
+                        if (delay > 1000) {
+                            Log.w(mTag, "Notification stop delayed by " + delay + "msecs");
+                        }
                         mPlayer.stop();
                         mPlayer.release();
                         mPlayer = null;
@@ -99,8 +114,8 @@
                     break;
                 }
 
-                synchronized (mLock) {
-                    if (mHead == null) {
+                synchronized (mCmdQueue) {
+                    if (mCmdQueue.size() == 0) {
                         // nothing left to do, quit
                         // doing this check after we're done prevents the case where they
                         // added it during the operation from spawning two threads and
@@ -115,11 +130,8 @@
     }
 
     private String mTag;
-    private Command mHead;
-    private Command mTail;
     private Thread mThread;
     private MediaPlayer mPlayer;
-    private Object mLock = new Object();
     private PowerManager.WakeLock mWakeLock;
 
     // The current state according to the caller.  Reality lags behind
@@ -154,12 +166,13 @@
      */
     public void play(Context context, Uri uri, boolean looping, int stream) {
         Command cmd = new Command();
+        cmd.requestTime = SystemClock.uptimeMillis();
         cmd.code = PLAY;
         cmd.context = context;
         cmd.uri = uri;
         cmd.looping = looping;
         cmd.stream = stream;
-        synchronized (mLock) {
+        synchronized (mCmdQueue) {
             enqueueLocked(cmd);
             mState = PLAY;
         }
@@ -170,11 +183,12 @@
      * at this point.  Calling this multiple times has no ill effects.
      */
     public void stop() {
-        synchronized (mLock) {
+        synchronized (mCmdQueue) {
             // This check allows stop to be called multiple times without starting
             // a thread that ends up doing nothing.
             if (mState != STOP) {
                 Command cmd = new Command();
+                cmd.requestTime = SystemClock.uptimeMillis();
                 cmd.code = STOP;
                 enqueueLocked(cmd);
                 mState = STOP;
@@ -183,12 +197,7 @@
     }
 
     private void enqueueLocked(Command cmd) {
-        if (mTail == null) {
-            mHead = cmd;
-        } else {
-            mTail.next = cmd;
-        }
-        mTail = cmd;
+        mCmdQueue.add(cmd);
         if (mThread == null) {
             acquireWakeLock();
             mThread = new Thread();
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index d90871e..58a0bba 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -959,10 +959,10 @@
     ///////////////////////////////////////////////////////////////////////////
 
     public class VolumeStreamState {
-        private final String mVolumeIndexSettingName;
-        private final String mLastAudibleVolumeIndexSettingName;
         private final int mStreamType;
 
+        private String mVolumeIndexSettingName;
+        private String mLastAudibleVolumeIndexSettingName;
         private int mIndexMax;
         private int mIndex;
         private int mLastAudibleIndex;
@@ -970,8 +970,7 @@
 
         private VolumeStreamState(String settingName, int streamType) {
 
-            mVolumeIndexSettingName = settingName;
-            mLastAudibleVolumeIndexSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE;
+            setVolumeIndexSettingName(settingName);
 
             mStreamType = streamType;
 
@@ -991,6 +990,11 @@
             mDeathHandlers = new ArrayList<VolumeDeathHandler>();
         }
 
+        public void setVolumeIndexSettingName(String settingName) {
+            mVolumeIndexSettingName = settingName;
+            mLastAudibleVolumeIndexSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE;
+        }
+
         public boolean adjustIndex(int deltaIndex) {
             return setIndex(mIndex + deltaIndex * 10, true);
         }
@@ -1370,11 +1374,17 @@
                     mNotificationsUseRingVolume = notificationsUseRingVolume;
                     if (mNotificationsUseRingVolume == 1) {
                         STREAM_VOLUME_ALIAS[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_RING;
+                        mStreamStates[AudioSystem.STREAM_NOTIFICATION].setVolumeIndexSettingName(
+                                System.VOLUME_SETTINGS[AudioSystem.STREAM_RING]);
                     } else {
                         STREAM_VOLUME_ALIAS[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_NOTIFICATION;
+                        mStreamStates[AudioSystem.STREAM_NOTIFICATION].setVolumeIndexSettingName(
+                                System.VOLUME_SETTINGS[AudioSystem.STREAM_NOTIFICATION]);
                         // Persist notification volume volume as it was not persisted while aliased to ring volume
+                        //  and persist with no delay as there might be registered observers of the persisted
+                        //  notification volume.
                         sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, AudioSystem.STREAM_NOTIFICATION,
-                                SENDMSG_REPLACE, 0, 0, mStreamStates[AudioSystem.STREAM_NOTIFICATION], PERSIST_DELAY);
+                                SENDMSG_REPLACE, 0, 0, mStreamStates[AudioSystem.STREAM_NOTIFICATION], 0);
                     }
                 }
             }
diff --git a/opengl/libagl/Android.mk b/opengl/libagl/Android.mk
index 2522656..9837845 100644
--- a/opengl/libagl/Android.mk
+++ b/opengl/libagl/Android.mk
@@ -25,6 +25,13 @@
 	primitives.cpp.arm	        \
 	vertex.cpp.arm
 
+LOCAL_CFLAGS += -DLOG_TAG=\"libagl\"
+LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+LOCAL_CFLAGS += -fvisibility=hidden
+
+LOCAL_SHARED_LIBRARIES := libcutils libhardware libutils libpixelflinger
+LOCAL_LDLIBS := -lpthread -ldl
+
 ifeq ($(TARGET_ARCH),arm)
 	LOCAL_SRC_FILES += fixed_asm.S iterators.S
 	LOCAL_CFLAGS += -fstrict-aliasing
@@ -38,15 +45,9 @@
 ifeq ($(LIBAGL_USE_GRALLOC_COPYBITS),1)
     LOCAL_CFLAGS += -DLIBAGL_USE_GRALLOC_COPYBITS
     LOCAL_SRC_FILES += copybit.cpp
+    LOCAL_SHARED_LIBRARIES += libui
 endif
 
-LOCAL_CFLAGS += -DLOG_TAG=\"libagl\"
-LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
-
-LOCAL_SHARED_LIBRARIES := libcutils libhardware libutils libpixelflinger
-LOCAL_CFLAGS += -fvisibility=hidden
-
-LOCAL_LDLIBS := -lpthread -ldl
 
 LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/egl
 LOCAL_MODULE:= libGLES_android
diff --git a/opengl/libagl/copybit.cpp b/opengl/libagl/copybit.cpp
index 73b2355..0c3d0ee 100644
--- a/opengl/libagl/copybit.cpp
+++ b/opengl/libagl/copybit.cpp
@@ -33,6 +33,10 @@
 #include <hardware/copybit.h>
 #include <private/ui/android_natives_priv.h>
 
+#include <ui/GraphicBuffer.h>
+#include <ui/Region.h>
+#include <ui/Rect.h>
+
 
 #define DEBUG_COPYBIT true
 
@@ -175,16 +179,6 @@
         dtdy /= screen_h;
     }
     dtdy = -dtdy; // see equation of dtdy above
-    if (dsdx < c->copybits.minScale || dsdx > c->copybits.maxScale
-            || dtdy < c->copybits.minScale || dtdy > c->copybits.maxScale) {
-        // The requested scale is out of the range the hardware
-        // can support.
-        LOGD_IF(DEBUG_COPYBIT,
-                "scale out of range dsdx=%08x (Wcr=%d / w=%d), "
-                "dtdy=%08x (Hcr=%d / h=%d), Ucr=%d, Vcr=%d", 
-                dsdx, Wcr, w, dtdy, Hcr, h, Ucr, Vcr);
-        return false;
-    }
 
     // copybit doesn't say anything about filtering, so we can't
     // discriminate. On msm7k, copybit will always filter.
@@ -278,21 +272,93 @@
         return false;
     }
 
-
-    // LOGW("calling copybits");
-
     copybit_device_t* copybit = c->copybits.blitEngine;
+    copybit_image_t src;
+    buffer_handle_t source_hnd = textureObject->buffer->handle;
+    textureToCopyBitImage(&textureObject->surface, opFormat, source_hnd, &src);
+    copybit_rect_t srect = { Ucr, Vcr + Hcr, Ucr + Wcr, Vcr };
+
+    /*
+     *  Below we perform extra passes needed to emulate things the h/w
+     * cannot do.
+     */
+
+    const GLfixed minScaleInv = gglDivQ(0x10000, c->copybits.minScale, 16);
+    const GLfixed maxScaleInv = gglDivQ(0x10000, c->copybits.maxScale, 16);
+
+    sp<GraphicBuffer> tempBitmap;
+
+    if (dsdx < maxScaleInv || dsdx > minScaleInv ||
+        dtdy < maxScaleInv || dtdy > minScaleInv)
+    {
+        // The requested scale is out of the range the hardware
+        // can support.
+        LOGD_IF(DEBUG_COPYBIT,
+                "scale out of range dsdx=%08x (Wcr=%d / w=%d), "
+                "dtdy=%08x (Hcr=%d / h=%d), Ucr=%d, Vcr=%d",
+                dsdx, Wcr, w, dtdy, Hcr, h, Ucr, Vcr);
+
+        int32_t xscale=0x10000, yscale=0x10000;
+        if (dsdx > minScaleInv)         xscale = c->copybits.minScale;
+        else if (dsdx < maxScaleInv)    xscale = c->copybits.maxScale;
+        if (dtdy > minScaleInv)         yscale = c->copybits.minScale;
+        else if (dtdy < maxScaleInv)    yscale = c->copybits.maxScale;
+        dsdx = gglMulx(dsdx, xscale);
+        dtdy = gglMulx(dtdy, yscale);
+
+        /* we handle only one step of resizing below. Handling an arbitrary
+         * number is relatively easy (replace "if" above by "while"), but requires
+         * two intermediate buffers and so far we never had the need.
+         */
+
+        if (dsdx < maxScaleInv || dsdx > minScaleInv ||
+            dtdy < maxScaleInv || dtdy > minScaleInv) {
+            LOGD_IF(DEBUG_COPYBIT,
+                    "scale out of range dsdx=%08x (Wcr=%d / w=%d), "
+                    "dtdy=%08x (Hcr=%d / h=%d), Ucr=%d, Vcr=%d",
+                    dsdx, Wcr, w, dtdy, Hcr, h, Ucr, Vcr);
+            return false;
+        }
+
+        const int tmp_w = gglMulx(srect.r - srect.l, xscale, 16);
+        const int tmp_h = gglMulx(srect.b - srect.t, yscale, 16);
+
+        LOGD_IF(DEBUG_COPYBIT,
+                "xscale=%08x, yscale=%08x, dsdx=%08x, dtdy=%08x, tmp_w=%d, tmp_h=%d",
+                xscale, yscale, dsdx, dtdy, tmp_w, tmp_h);
+
+        tempBitmap = new GraphicBuffer(
+                    tmp_w, tmp_h, src.format,
+                    GraphicBuffer::USAGE_HW_2D);
+
+        status_t err = tempBitmap->initCheck();
+        if (err == NO_ERROR) {
+            copybit_image_t tmp_dst;
+            copybit_rect_t tmp_rect;
+            tmp_dst.w = tmp_w;
+            tmp_dst.h = tmp_h;
+            tmp_dst.format = src.format;
+            tmp_dst.handle = (native_handle_t*)tempBitmap->getNativeBuffer()->handle;
+            tmp_rect.l = 0;
+            tmp_rect.t = 0;
+            tmp_rect.r = tmp_dst.w;
+            tmp_rect.b = tmp_dst.h;
+            region_iterator tmp_it(Region(Rect(tmp_rect.r, tmp_rect.b)));
+            copybit->set_parameter(copybit, COPYBIT_TRANSFORM, 0);
+            copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 0xFF);
+            copybit->set_parameter(copybit, COPYBIT_DITHER, COPYBIT_DISABLE);
+            err = copybit->stretch(copybit,
+                    &tmp_dst, &src, &tmp_rect, &srect, &tmp_it);
+            src = tmp_dst;
+            srect = tmp_rect;
+        }
+    }
 
     copybit_image_t dst;
     buffer_handle_t target_hnd = c->copybits.drawSurfaceBuffer;
     textureToCopyBitImage(&cbSurface, cbSurface.format, target_hnd, &dst);
     copybit_rect_t drect = {x, y, x+w, y+h};
 
-    copybit_image_t src;
-    buffer_handle_t source_hnd = textureObject->buffer->handle;
-    textureToCopyBitImage(&textureObject->surface, opFormat, source_hnd, &src);
-    copybit_rect_t srect = { Ucr, Vcr + Hcr, Ucr + Wcr, Vcr };
-
     copybit->set_parameter(copybit, COPYBIT_TRANSFORM, transform);
     copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, planeAlpha);
     copybit->set_parameter(copybit, COPYBIT_DITHER,
diff --git a/opengl/tests/linetex/Android.mk b/opengl/tests/linetex/Android.mk
new file mode 100644
index 0000000..6ff248d
--- /dev/null
+++ b/opengl/tests/linetex/Android.mk
@@ -0,0 +1,17 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	linetex.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils \
+    libEGL \
+    libGLESv1_CM \
+    libui
+
+LOCAL_MODULE:= test-opengl-linetex
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_EXECUTABLE)
diff --git a/opengl/tests/linetex/linetex.cpp b/opengl/tests/linetex/linetex.cpp
new file mode 100644
index 0000000..e62fe03
--- /dev/null
+++ b/opengl/tests/linetex/linetex.cpp
@@ -0,0 +1,117 @@
+/*
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+
+#define LOG_TAG "fillrate"
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <EGL/egl.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <utils/StopWatch.h>
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/EGLUtils.h>
+
+using namespace android;
+
+int main(int argc, char** argv)
+{
+    EGLint configAttribs[] = {
+         EGL_DEPTH_SIZE, 0,
+         EGL_NONE
+     };
+     
+     EGLint majorVersion;
+     EGLint minorVersion;
+     EGLContext context;
+     EGLConfig config;
+     EGLSurface surface;
+     EGLint w, h;
+     EGLDisplay dpy;
+
+     EGLNativeWindowType window = android_createDisplaySurface();
+     
+     dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+     eglInitialize(dpy, &majorVersion, &minorVersion);
+          
+     status_t err = EGLUtils::selectConfigForNativeWindow(
+             dpy, configAttribs, window, &config);
+     if (err) {
+         fprintf(stderr, "couldn't find an EGLConfig matching the screen format\n");
+         return 0;
+     }
+
+     surface = eglCreateWindowSurface(dpy, config, window, NULL);
+     context = eglCreateContext(dpy, config, NULL, NULL);
+     eglMakeCurrent(dpy, surface, surface, context);   
+     eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
+     eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
+     
+     printf("w=%d, h=%d\n", w, h);
+     
+     glBindTexture(GL_TEXTURE_2D, 0);
+     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+     glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+     glDisable(GL_DITHER);
+     glDisable(GL_BLEND);
+     glEnable(GL_TEXTURE_2D);
+     glColor4f(1,1,1,1);
+
+     const uint32_t t32[] = {
+             0xFFFFFFFF, 0xFF0000FF, 0xFF00FF00, 0xFFFF0000,
+             0xFFFFFF00, 0xFFFF00FF, 0xFF00FFFF, 0xFF000000
+     };
+
+     const GLfloat vertices[4][2] = {
+             { 0,  0 },
+             { w,  h }
+     };
+
+     const GLfloat texCoords[4][2] = {
+             { 0,  0 },
+             { 1,  0 }
+     };
+
+     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 8, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, t32);
+
+     glViewport(0, 0, w, h);
+     glMatrixMode(GL_PROJECTION);
+     glLoadIdentity();
+     glOrthof(0, w, 0, h, 0, 1);
+
+     glEnableClientState(GL_VERTEX_ARRAY);
+     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+     glVertexPointer(2, GL_FLOAT, 0, vertices);
+     glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
+
+     glClearColor(0,0,0,0);
+     glClear(GL_COLOR_BUFFER_BIT);
+     glDrawArrays(GL_LINES, 0, 2);
+     eglSwapBuffers(dpy, surface);
+
+     usleep(5*1000000);
+
+     eglTerminate(dpy);
+     
+     return 0;
+}
diff --git a/services/java/com/android/server/DropBoxService.java b/services/java/com/android/server/DropBoxService.java
index 6c96a46..f4e5ebc 100644
--- a/services/java/com/android/server/DropBoxService.java
+++ b/services/java/com/android/server/DropBoxService.java
@@ -23,8 +23,7 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.net.Uri;
-import android.os.DropBoxEntry;
-import android.os.IDropBox;
+import android.os.DropBox;
 import android.os.ParcelFileDescriptor;
 import android.os.StatFs;
 import android.os.SystemClock;
@@ -32,11 +31,13 @@
 import android.text.format.DateFormat;
 import android.util.Log;
 
+import com.android.internal.os.IDropBoxService;
+
 import java.io.File;
 import java.io.FileDescriptor;
-import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
@@ -53,11 +54,12 @@
 import java.util.zip.GZIPOutputStream;
 
 /**
- * Implementation of {@link IDropBox} using the filesystem.
+ * Implementation of {@link IDropBoxService} using the filesystem.
+ * Clients use {@link DropBox} to access this service.
  *
  * {@hide}
  */
-public final class DropBoxService extends IDropBox.Stub {
+public final class DropBoxService extends IDropBoxService.Stub {
     private static final String TAG = "DropBoxService";
     private static final int DEFAULT_RESERVE_PERCENT = 10;
     private static final int DEFAULT_QUOTA_PERCENT = 10;
@@ -129,50 +131,13 @@
         mContext.unregisterReceiver(mReceiver);
     }
 
-    public void addText(String tag, String data) {
-        addData(tag, data.getBytes(), DropBoxEntry.IS_TEXT);
-    }
-
-    public void addData(String tag, byte[] data, int flags) {
-        File temp = null;
-        OutputStream out = null;
-        try {
-            if ((flags & DropBoxEntry.IS_EMPTY) != 0) throw new IllegalArgumentException();
-
-            init();
-            if (!isTagEnabled(tag)) return;
-
-            long max = trimToFit();
-            if (data.length > max) {
-                Log.w(TAG, "Dropping: " + tag + " (" + data.length + " > " + max + " bytes)");
-                // Pass temp = null to createEntry() to leave a tombstone
-            } else {
-                temp = new File(mDropBoxDir, "drop" + Thread.currentThread().getId() + ".tmp");
-                out = new FileOutputStream(temp);
-                if (data.length > mBlockSize && ((flags & DropBoxEntry.IS_GZIPPED) == 0)) {
-                    flags = flags | DropBoxEntry.IS_GZIPPED;
-                    out = new GZIPOutputStream(out);
-                }
-                out.write(data);
-                out.close();
-                out = null;
-            }
-
-            createEntry(temp, tag, flags);
-            temp = null;
-        } catch (IOException e) {
-            Log.e(TAG, "Can't write: " + tag, e);
-        } finally {
-            try { if (out != null) out.close(); } catch (IOException e) {}
-            if (temp != null) temp.delete();
-        }
-    }
-
-    public void addFile(String tag, ParcelFileDescriptor data, int flags) {
+    public void add(DropBox.Entry entry) {
         File temp = null;
         OutputStream output = null;
+        final String tag = entry.getTag();
         try {
-            if ((flags & DropBoxEntry.IS_EMPTY) != 0) throw new IllegalArgumentException();
+            int flags = entry.getFlags();
+            if ((flags & DropBox.IS_EMPTY) != 0) throw new IllegalArgumentException();
 
             init();
             if (!isTagEnabled(tag)) return;
@@ -180,7 +145,7 @@
             long lastTrim = System.currentTimeMillis();
 
             byte[] buffer = new byte[mBlockSize];
-            FileInputStream input = new FileInputStream(data.getFileDescriptor());
+            InputStream input = entry.getInputStream();
 
             // First, accumulate up to one block worth of data in memory before
             // deciding whether to compress the data or not.
@@ -197,9 +162,9 @@
 
             temp = new File(mDropBoxDir, "drop" + Thread.currentThread().getId() + ".tmp");
             output = new FileOutputStream(temp);
-            if (read == buffer.length && ((flags & DropBoxEntry.IS_GZIPPED) == 0)) {
+            if (read == buffer.length && ((flags & DropBox.IS_GZIPPED) == 0)) {
                 output = new GZIPOutputStream(output);
-                flags = flags | DropBoxEntry.IS_GZIPPED;
+                flags = flags | DropBox.IS_GZIPPED;
             }
 
             do {
@@ -234,7 +199,7 @@
             Log.e(TAG, "Can't write: " + tag, e);
         } finally {
             try { if (output != null) output.close(); } catch (IOException e) {}
-            try { data.close(); } catch (IOException e) {}
+            entry.close();
             if (temp != null) temp.delete();
         }
     }
@@ -244,7 +209,7 @@
                 mContentResolver, Settings.Gservices.DROPBOX_TAG_PREFIX + tag));
     }
 
-    public synchronized DropBoxEntry getNextEntry(String tag, long millis) {
+    public synchronized DropBox.Entry getNextEntry(String tag, long millis) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.READ_LOGS)
                 != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("READ_LOGS permission required");
@@ -262,9 +227,11 @@
 
         for (EntryFile entry : list.contents.tailSet(new EntryFile(millis + 1))) {
             if (entry.tag == null) continue;
+            if ((entry.flags & DropBox.IS_EMPTY) != 0) {
+                return new DropBox.Entry(entry.tag, entry.timestampMillis);
+            }
             try {
-                File file = (entry.flags & DropBoxEntry.IS_EMPTY) != 0 ? null : entry.file;
-                return new DropBoxEntry(entry.tag, entry.timestampMillis, file, entry.flags);
+                return new DropBox.Entry(entry.tag, entry.timestampMillis, entry.file, entry.flags);
             } catch (IOException e) {
                 Log.e(TAG, "Can't read: " + entry.file, e);
                 // Continue to next file
@@ -331,25 +298,25 @@
             if (entry.file == null) {
                 pw.println(" (no file)");
                 continue;
-            } else if ((entry.flags & DropBoxEntry.IS_EMPTY) != 0) {
+            } else if ((entry.flags & DropBox.IS_EMPTY) != 0) {
                 pw.println(" (contents lost)");
                 continue;
             } else {
-                pw.print((entry.flags & DropBoxEntry.IS_GZIPPED) != 0 ? " (comopressed " : " (");
-                pw.print((entry.flags & DropBoxEntry.IS_TEXT) != 0 ? "text" : "data");
+                pw.print((entry.flags & DropBox.IS_GZIPPED) != 0 ? " (comopressed " : " (");
+                pw.print((entry.flags & DropBox.IS_TEXT) != 0 ? "text" : "data");
                 pw.format(", %d bytes)", entry.file.length());
                 pw.println();
             }
 
-            if (doFile || (doPrint && (entry.flags & DropBoxEntry.IS_TEXT) == 0)) {
+            if (doFile || (doPrint && (entry.flags & DropBox.IS_TEXT) == 0)) {
                 if (!doPrint) pw.print("    ");
                 pw.println(entry.file.getPath());
             }
 
-            if ((entry.flags & DropBoxEntry.IS_TEXT) != 0 && (doPrint || !doFile)) {
-                DropBoxEntry dbe = null;
+            if ((entry.flags & DropBox.IS_TEXT) != 0 && (doPrint || !doFile)) {
+                DropBox.Entry dbe = null;
                 try {
-                    dbe = new DropBoxEntry(
+                    dbe = new DropBox.Entry(
                              entry.tag, entry.timestampMillis, entry.file, entry.flags);
 
                     if (doPrint) {
@@ -435,20 +402,20 @@
          * @param dir to store file in
          * @param tag to use for new log file name
          * @param timestampMillis of log entry
-         * @param flags for the entry data (from {@link DropBoxEntry})
+         * @param flags for the entry data
          * @param blockSize to use for space accounting
          * @throws IOException if the file can't be moved
          */
         public EntryFile(File temp, File dir, String tag,long timestampMillis,
                          int flags, int blockSize) throws IOException {
-            if ((flags & DropBoxEntry.IS_EMPTY) != 0) throw new IllegalArgumentException();
+            if ((flags & DropBox.IS_EMPTY) != 0) throw new IllegalArgumentException();
 
             this.tag = tag;
             this.timestampMillis = timestampMillis;
             this.flags = flags;
             this.file = new File(dir, Uri.encode(tag) + "@" + timestampMillis +
-                    ((flags & DropBoxEntry.IS_TEXT) != 0 ? ".txt" : ".dat") +
-                    ((flags & DropBoxEntry.IS_GZIPPED) != 0 ? ".gz" : ""));
+                    ((flags & DropBox.IS_TEXT) != 0 ? ".txt" : ".dat") +
+                    ((flags & DropBox.IS_GZIPPED) != 0 ? ".gz" : ""));
 
             if (!temp.renameTo(this.file)) {
                 throw new IOException("Can't rename " + temp + " to " + this.file);
@@ -466,7 +433,7 @@
         public EntryFile(File dir, String tag, long timestampMillis) throws IOException {
             this.tag = tag;
             this.timestampMillis = timestampMillis;
-            this.flags = DropBoxEntry.IS_EMPTY;
+            this.flags = DropBox.IS_EMPTY;
             this.file = new File(dir, Uri.encode(tag) + "@" + timestampMillis + ".lost");
             this.blocks = 0;
             new FileOutputStream(this.file).close();
@@ -486,26 +453,26 @@
             if (at < 0) {
                 this.tag = null;
                 this.timestampMillis = 0;
-                this.flags = DropBoxEntry.IS_EMPTY;
+                this.flags = DropBox.IS_EMPTY;
                 return;
             }
 
             int flags = 0;
             this.tag = Uri.decode(name.substring(0, at));
             if (name.endsWith(".gz")) {
-                flags |= DropBoxEntry.IS_GZIPPED;
+                flags |= DropBox.IS_GZIPPED;
                 name = name.substring(0, name.length() - 3);
             }
             if (name.endsWith(".lost")) {
-                flags |= DropBoxEntry.IS_EMPTY;
+                flags |= DropBox.IS_EMPTY;
                 name = name.substring(at + 1, name.length() - 5);
             } else if (name.endsWith(".txt")) {
-                flags |= DropBoxEntry.IS_TEXT;
+                flags |= DropBox.IS_TEXT;
                 name = name.substring(at + 1, name.length() - 4);
             } else if (name.endsWith(".dat")) {
                 name = name.substring(at + 1, name.length() - 4);
             } else {
-                this.flags = DropBoxEntry.IS_EMPTY;
+                this.flags = DropBox.IS_EMPTY;
                 this.timestampMillis = 0;
                 return;
             }
@@ -523,7 +490,7 @@
         public EntryFile(long millis) {
             this.tag = null;
             this.timestampMillis = millis;
-            this.flags = DropBoxEntry.IS_EMPTY;
+            this.flags = DropBox.IS_EMPTY;
             this.file = null;
             this.blocks = 0;
         }
@@ -618,7 +585,7 @@
                 mAllFiles.blocks -= late.blocks;
                 FileList tagFiles = mFilesByTag.get(late.tag);
                 if (tagFiles.contents.remove(late)) tagFiles.blocks -= late.blocks;
-                if ((late.flags & DropBoxEntry.IS_EMPTY) == 0) {
+                if ((late.flags & DropBox.IS_EMPTY) == 0) {
                     enrollEntry(new EntryFile(
                             late.file, mDropBoxDir, late.tag, t++, late.flags, mBlockSize));
                 } else {
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 5c4aa79..4bf606d 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -131,6 +131,8 @@
     static final boolean ANIMATE_KEYBOARD_LIGHTS = false;
     
     static final int ANIM_STEPS = 60/4;
+    // Slower animation for autobrightness changes
+    static final int AUTOBRIGHTNESS_ANIM_STEPS = 60;
 
     // These magic numbers are the initial state of the LEDs at boot.  Ideally
     // we should read them from the driver, but our current hardware returns 0
@@ -156,7 +158,6 @@
     private int mProximityCount = 0;
     private int mPowerState;
     private boolean mOffBecauseOfUser;
-    private boolean mAnimatingScreenOff;
     private int mUserState;
     private boolean mKeyboardVisible = false;
     private boolean mUserActivityAllowed = true;
@@ -224,7 +225,7 @@
 
     // could be either static or controllable at runtime
     private static final boolean mSpew = false;
-    private static final boolean mDebugLightSensor = false;
+    private static final boolean mDebugLightSensor = (false || mSpew);
 
     /*
     static PrintStream mLog;
@@ -1230,7 +1231,6 @@
                         Log.d(TAG,
                               "preventScreenOn: turning on after a prior preventScreenOn(true)!");
                     }
-                    mAnimatingScreenOff = false;
                     int err = setScreenStateLocked(true);
                     if (err != 0) {
                         Log.w(TAG, "preventScreenOn: error from setScreenStateLocked(): " + err);
@@ -1392,7 +1392,6 @@
                         reallyTurnScreenOn = false;
                     }
                     if (reallyTurnScreenOn) {
-                        mAnimatingScreenOff = false;
                         err = setScreenStateLocked(true);
                         long identity = Binder.clearCallingIdentity();
                         try {
@@ -1434,7 +1433,6 @@
                     if (!mScreenBrightness.animating) {
                         err = screenOffFinishedAnimatingLocked(becauseOfUser);
                     } else {
-                        mAnimatingScreenOff = true;
                         mOffBecauseOfUser = becauseOfUser;
                         err = 0;
                         mLastTouchDown = 0;
@@ -1452,7 +1450,6 @@
                 mTotalTouchDownTime, mTouchCycles);
         mLastTouchDown = 0;
         int err = setScreenStateLocked(false);
-        mAnimatingScreenOff = false;
         if (mScreenOnStartTime != 0) {
             mScreenOnTime += SystemClock.elapsedRealtime() - mScreenOnStartTime;
             mScreenOnStartTime = 0;
@@ -1825,9 +1822,6 @@
             return;
         }
 
-        if (mAnimatingScreenOff) {
-            return;
-        }
         if (false) {
             if (((mPokey & POKE_LOCK_IGNORE_CHEEK_EVENTS) != 0)) {
                 Log.d(TAG, "userActivity !!!");//, new RuntimeException());
@@ -1845,6 +1839,11 @@
                         + " mProximitySensorActive=" + mProximitySensorActive
                         + " force=" + force);
             }
+            // ignore user activity if we are in the process of turning off the screen
+            if (mScreenBrightness.animating && mScreenBrightness.targetValue == 0) {
+                Log.d(TAG, "ignoring user activity while turning off screen");
+                return;
+            }
             if (mLastEventTime <= time || force) {
                 mLastEventTime = time;
                 if ((mUserActivityAllowed && !mProximitySensorActive) || force) {
@@ -1925,27 +1924,45 @@
                     Log.d(TAG, "keyboardValue " + keyboardValue);
                 }
 
+                boolean startAnimation = false;
                 if (mScreenBrightnessOverride < 0) {
-                    mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BACKLIGHT,
-                            lcdValue);
-                }
-                mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BUTTONS,
-                        buttonValue);
-                mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_KEYBOARD,
-                        keyboardValue);
-
-                // update our animation state
-                if (ANIMATE_SCREEN_LIGHTS) {
-                    mScreenBrightness.curValue = lcdValue;
-                    mScreenBrightness.animating = false;
+                    if (ANIMATE_SCREEN_LIGHTS) {
+                        if (mScreenBrightness.setTargetLocked(lcdValue,
+                                AUTOBRIGHTNESS_ANIM_STEPS, INITIAL_SCREEN_BRIGHTNESS,
+                                (int)mScreenBrightness.curValue)) {
+                            startAnimation = true;
+                        }
+                    } else {
+                        mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BACKLIGHT,
+                                lcdValue);
+                    }
                 }
                 if (ANIMATE_BUTTON_LIGHTS) {
-                    mButtonBrightness.curValue = buttonValue;
-                    mButtonBrightness.animating = false;
+                    if (mButtonBrightness.setTargetLocked(buttonValue,
+                            AUTOBRIGHTNESS_ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS,
+                            (int)mButtonBrightness.curValue)) {
+                        startAnimation = true;
+                    }
+                } else {
+                    mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_BUTTONS,
+                            buttonValue);
                 }
                 if (ANIMATE_KEYBOARD_LIGHTS) {
-                    mKeyboardBrightness.curValue = keyboardValue;
-                    mKeyboardBrightness.animating = false;
+                    if (mKeyboardBrightness.setTargetLocked(keyboardValue,
+                            AUTOBRIGHTNESS_ANIM_STEPS, INITIAL_BUTTON_BRIGHTNESS,
+                            (int)mKeyboardBrightness.curValue)) {
+                        startAnimation = true;
+                    }
+                } else {
+                    mHardware.setLightBrightness_UNCHECKED(HardwareService.LIGHT_ID_KEYBOARD,
+                            keyboardValue);
+                }
+                if (startAnimation) {
+                    if (mDebugLightSensor) {
+                        Log.i(TAG, "lightSensorChangedLocked scheduling light animator");
+                    }
+                    mHandler.removeCallbacks(mLightAnimator);
+                    mHandler.post(mLightAnimator);
                 }
             }
         }
@@ -2041,6 +2058,7 @@
         if (mAutoBrightessEnabled != enabled) {
             mAutoBrightessEnabled = enabled;
             // reset computed brightness
+            mLightSensorValue = -1;
             mLightSensorBrightness = -1;
 
             if (mHasHardwareAutoBrightness) {
@@ -2263,14 +2281,17 @@
         if (ANIMATE_SCREEN_LIGHTS) {
             mScreenBrightness.curValue = brightness;
             mScreenBrightness.animating = false;
+            mScreenBrightness.targetValue = -1;
         }
         if (ANIMATE_KEYBOARD_LIGHTS) {
             mKeyboardBrightness.curValue = brightness;
             mKeyboardBrightness.animating = false;
+            mKeyboardBrightness.targetValue = -1;
         }
         if (ANIMATE_BUTTON_LIGHTS) {
             mButtonBrightness.curValue = brightness;
             mButtonBrightness.animating = false;
+            mButtonBrightness.targetValue = -1;
         }
     }
 
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 1a7416a..5f30710 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -296,7 +296,7 @@
 
             try {
                 Log.i(TAG, "DropBox Service");
-                ServiceManager.addService("dropbox",
+                ServiceManager.addService(Context.DROPBOX_SERVICE,
                         new DropBoxService(context, new File("/data/system/dropbox")));
             } catch (Throwable e) {
                 Log.e(TAG, "Failure starting DropBox Service", e);
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index ad1926e..56270f4 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -2705,13 +2705,31 @@
 
             // Have the window manager re-evaluate the orientation of
             // the screen based on the new activity order.
-            Configuration config = mWindowManager.updateOrientationFromAppTokens(
-                    mConfiguration,
-                    next.mayFreezeScreenLocked(next.app) ? next : null);
-            if (config != null) {
-                next.frozenBeforeDestroy = true;
+            boolean updated;
+            synchronized (this) {
+                Configuration config = mWindowManager.updateOrientationFromAppTokens(
+                        mConfiguration,
+                        next.mayFreezeScreenLocked(next.app) ? next : null);
+                if (config != null) {
+                    /*
+                     * Explicitly restore the locale to the one from the
+                     * old configuration, since the one that comes back from
+                     * the window manager has the default (boot) locale.
+                     *
+                     * It looks like previously the locale picker only worked
+                     * by coincidence: usually it would do its setting of
+                     * the locale after the activity transition, so it didn't
+                     * matter that this lost it.  With the synchronized
+                     * block now keeping them from happening at the same time,
+                     * this one always would happen second and undo what the
+                     * locale picker had just done.
+                     */
+                    config.locale = mConfiguration.locale;
+                    next.frozenBeforeDestroy = true;
+                }
+                updated = updateConfigurationLocked(config, next);
             }
-            if (!updateConfigurationLocked(config, next)) {
+            if (!updated) {
                 // The configuration update wasn't able to keep the existing
                 // instance of the activity, and instead started a new one.
                 // We should be all done, but let's just make sure our activity
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 6b33f52aa..586f63f 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -1060,8 +1060,8 @@
      * Breaks the given number down and formats it according to the rules
      * for the country the number is from.
      *
-     * @param source the phone number to format
-     * @return a locally acceptable formatting of the input, or the raw input if
+     * @param source The phone number to format
+     * @return A locally acceptable formatting of the input, or the raw input if
      *  formatting rules aren't known for the number
      */
     public static String formatNumber(String source) {
@@ -1071,10 +1071,27 @@
     }
 
     /**
+     * Formats the given number with the given formatting type. Currently
+     * {@link #FORMAT_NANP} and {@link #FORMAT_JAPAN} are supported as a formating type.
+     *
+     * @param source the phone number to format
+     * @param defaultFormattingType The default formatting rules to apply if the number does
+     * not begin with +<country_code>
+     * @return The phone number formatted with the given formatting type.
+     *
+     * @hide TODO:Shuold be unhidden.
+     */
+    public static String formatNumber(String source, int defaultFormattingType) {
+        SpannableStringBuilder text = new SpannableStringBuilder(source);
+        formatNumber(text, defaultFormattingType);
+        return text.toString();
+    }
+
+    /**
      * Returns the phone number formatting type for the given locale.
      *
      * @param locale The locale of interest, usually {@link Locale#getDefault()}
-     * @return the formatting type for the given locale, or FORMAT_UNKNOWN if the formatting
+     * @return The formatting type for the given locale, or FORMAT_UNKNOWN if the formatting
      * rules are not known for the given locale
      */
     public static int getFormatTypeForLocale(Locale locale) {
@@ -1084,7 +1101,8 @@
     }
 
     /**
-     * Formats a phone number in-place. Currently only supports NANP formatting.
+     * Formats a phone number in-place. Currently {@link #FORMAT_JAPAN} and {@link #FORMAT_NANP}
+     * is supported as a second argument.
      *
      * @param text The number to be formatted, will be modified with the formatting
      * @param defaultFormattingType The default formatting rules to apply if the number does
diff --git a/tests/AndroidTests/src/com/android/unit_tests/DropBoxTest.java b/tests/AndroidTests/src/com/android/unit_tests/DropBoxTest.java
index 439e0d8..286f702 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/DropBoxTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/DropBoxTest.java
@@ -19,8 +19,7 @@
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
-import android.os.DropBoxEntry;
-import android.os.IDropBox;
+import android.os.DropBox;
 import android.os.ParcelFileDescriptor;
 import android.os.ServiceManager;
 import android.os.StatFs;
@@ -36,7 +35,7 @@
 import java.util.Random;
 import java.util.zip.GZIPOutputStream;
 
-/** Test {@link IDropBox} functionality. */
+/** Test {@link DropBox} functionality. */
 public class DropBoxTest extends AndroidTestCase {
     public void tearDown() throws Exception {
         Intent override = new Intent(Settings.Gservices.OVERRIDE_ACTION);
@@ -47,7 +46,7 @@
     }
 
     public void testAddText() throws Exception {
-        IDropBox dropbox = IDropBox.Stub.asInterface(ServiceManager.getService("dropbox"));
+        DropBox dropbox = (DropBox) getContext().getSystemService(Context.DROPBOX_SERVICE);
         long before = System.currentTimeMillis();
         Thread.sleep(5);
         dropbox.addText("DropBoxTest", "TEST0");
@@ -59,9 +58,9 @@
         Thread.sleep(5);
         long after = System.currentTimeMillis();
 
-        DropBoxEntry e0 = dropbox.getNextEntry("DropBoxTest", before);
-        DropBoxEntry e1 = dropbox.getNextEntry("DropBoxTest", e0.getTimeMillis());
-        DropBoxEntry e2 = dropbox.getNextEntry("DropBoxTest", e1.getTimeMillis());
+        DropBox.Entry e0 = dropbox.getNextEntry("DropBoxTest", before);
+        DropBox.Entry e1 = dropbox.getNextEntry("DropBoxTest", e0.getTimeMillis());
+        DropBox.Entry e2 = dropbox.getNextEntry("DropBoxTest", e1.getTimeMillis());
         assertTrue(null == dropbox.getNextEntry("DropBoxTest", e2.getTimeMillis()));
 
         assertTrue(e0.getTimeMillis() > before);
@@ -80,12 +79,12 @@
     }
 
     public void testAddData() throws Exception {
-        IDropBox dropbox = IDropBox.Stub.asInterface(ServiceManager.getService("dropbox"));
+        DropBox dropbox = (DropBox) getContext().getSystemService(Context.DROPBOX_SERVICE);
         long before = System.currentTimeMillis();
         dropbox.addData("DropBoxTest", "TEST".getBytes(), 0);
         long after = System.currentTimeMillis();
 
-        DropBoxEntry e = dropbox.getNextEntry("DropBoxTest", before);
+        DropBox.Entry e = dropbox.getNextEntry("DropBoxTest", before);
         assertTrue(null == dropbox.getNextEntry("DropBoxTest", e.getTimeMillis()));
 
         assertEquals("DropBoxTest", e.getTag());
@@ -123,7 +122,7 @@
         os2.close();
         gz3.close();
 
-        IDropBox dropbox = IDropBox.Stub.asInterface(ServiceManager.getService("dropbox"));
+        DropBox dropbox = (DropBox) getContext().getSystemService(Context.DROPBOX_SERVICE);
         int mode = ParcelFileDescriptor.MODE_READ_ONLY;
 
         ParcelFileDescriptor pfd0 = ParcelFileDescriptor.open(f0, mode);
@@ -131,20 +130,20 @@
         ParcelFileDescriptor pfd2 = ParcelFileDescriptor.open(f2, mode);
         ParcelFileDescriptor pfd3 = ParcelFileDescriptor.open(f3, mode);
 
-        dropbox.addFile("DropBoxTest", pfd0, DropBoxEntry.IS_TEXT);
-        dropbox.addFile("DropBoxTest", pfd1, DropBoxEntry.IS_TEXT | DropBoxEntry.IS_GZIPPED);
+        dropbox.addFile("DropBoxTest", pfd0, DropBox.IS_TEXT);
+        dropbox.addFile("DropBoxTest", pfd1, DropBox.IS_TEXT | DropBox.IS_GZIPPED);
         dropbox.addFile("DropBoxTest", pfd2, 0);
-        dropbox.addFile("DropBoxTest", pfd3, DropBoxEntry.IS_GZIPPED);
+        dropbox.addFile("DropBoxTest", pfd3, DropBox.IS_GZIPPED);
 
         pfd0.close();
         pfd1.close();
         pfd2.close();
         pfd3.close();
 
-        DropBoxEntry e0 = dropbox.getNextEntry("DropBoxTest", before);
-        DropBoxEntry e1 = dropbox.getNextEntry("DropBoxTest", e0.getTimeMillis());
-        DropBoxEntry e2 = dropbox.getNextEntry("DropBoxTest", e1.getTimeMillis());
-        DropBoxEntry e3 = dropbox.getNextEntry("DropBoxTest", e2.getTimeMillis());
+        DropBox.Entry e0 = dropbox.getNextEntry("DropBoxTest", before);
+        DropBox.Entry e1 = dropbox.getNextEntry("DropBoxTest", e0.getTimeMillis());
+        DropBox.Entry e2 = dropbox.getNextEntry("DropBoxTest", e1.getTimeMillis());
+        DropBox.Entry e3 = dropbox.getNextEntry("DropBoxTest", e2.getTimeMillis());
         assertTrue(null == dropbox.getNextEntry("DropBoxTest", e3.getTimeMillis()));
 
         assertTrue(e0.getTimeMillis() > before);
@@ -152,8 +151,8 @@
         assertTrue(e2.getTimeMillis() > e1.getTimeMillis());
         assertTrue(e3.getTimeMillis() > e2.getTimeMillis());
 
-        assertEquals(DropBoxEntry.IS_TEXT, e0.getFlags());
-        assertEquals(DropBoxEntry.IS_TEXT, e1.getFlags());
+        assertEquals(DropBox.IS_TEXT, e0.getFlags());
+        assertEquals(DropBox.IS_TEXT, e1.getFlags());
         assertEquals(0, e2.getFlags());
         assertEquals(0, e3.getFlags());
 
@@ -199,13 +198,14 @@
         // Tombstone in the far future
         new FileOutputStream(new File(dir, "DropBoxTest@" + (before + 100002) + ".lost")).close();
 
-        DropBoxService dropbox = new DropBoxService(getContext(), dir);
+        DropBoxService service = new DropBoxService(getContext(), dir);
+        DropBox dropbox = new DropBox(service);
 
         // Until a write, the timestamps are taken at face value
-        DropBoxEntry e0 = dropbox.getNextEntry(null, before);
-        DropBoxEntry e1 = dropbox.getNextEntry(null, e0.getTimeMillis());
-        DropBoxEntry e2 = dropbox.getNextEntry(null, e1.getTimeMillis());
-        DropBoxEntry e3 = dropbox.getNextEntry(null, e2.getTimeMillis());
+        DropBox.Entry e0 = dropbox.getNextEntry(null, before);
+        DropBox.Entry e1 = dropbox.getNextEntry(null, e0.getTimeMillis());
+        DropBox.Entry e2 = dropbox.getNextEntry(null, e1.getTimeMillis());
+        DropBox.Entry e3 = dropbox.getNextEntry(null, e2.getTimeMillis());
         assertTrue(null == dropbox.getNextEntry(null, e3.getTimeMillis()));
 
         assertEquals("FUTURE0", e0.getText(80));
@@ -245,11 +245,11 @@
         e1.close();
         e2.close();
         e3.close();
-        dropbox.stop();
+        service.stop();
     }
 
     public void testIsTagEnabled() throws Exception {
-        IDropBox dropbox = IDropBox.Stub.asInterface(ServiceManager.getService("dropbox"));
+        DropBox dropbox = (DropBox) getContext().getSystemService(Context.DROPBOX_SERVICE);
         long before = System.currentTimeMillis();
         dropbox.addText("DropBoxTest", "TEST-ENABLED");
         assertTrue(dropbox.isTagEnabled("DropBoxTest"));
@@ -268,8 +268,8 @@
         dropbox.addText("DropBoxTest", "TEST-ENABLED-AGAIN");
         assertTrue(dropbox.isTagEnabled("DropBoxTest"));
 
-        DropBoxEntry e0 = dropbox.getNextEntry("DropBoxTest", before);
-        DropBoxEntry e1 = dropbox.getNextEntry("DropBoxTest", e0.getTimeMillis());
+        DropBox.Entry e0 = dropbox.getNextEntry("DropBoxTest", before);
+        DropBox.Entry e1 = dropbox.getNextEntry("DropBoxTest", e0.getTimeMillis());
         assertTrue(null == dropbox.getNextEntry("DropBoxTest", e1.getTimeMillis()));
 
         assertEquals("TEST-ENABLED", e0.getText(80));
@@ -281,23 +281,24 @@
 
     public void testGetNextEntry() throws Exception {
         File dir = getEmptyDir("testGetNextEntry");
-        DropBoxService dropbox = new DropBoxService(getContext(), dir);
+        DropBoxService service = new DropBoxService(getContext(), dir);
+        DropBox dropbox = new DropBox(service);
 
         long before = System.currentTimeMillis();
         dropbox.addText("DropBoxTest.A", "A0");
         dropbox.addText("DropBoxTest.B", "B0");
         dropbox.addText("DropBoxTest.A", "A1");
 
-        DropBoxEntry a0 = dropbox.getNextEntry("DropBoxTest.A", before);
-        DropBoxEntry a1 = dropbox.getNextEntry("DropBoxTest.A", a0.getTimeMillis());
+        DropBox.Entry a0 = dropbox.getNextEntry("DropBoxTest.A", before);
+        DropBox.Entry a1 = dropbox.getNextEntry("DropBoxTest.A", a0.getTimeMillis());
         assertTrue(null == dropbox.getNextEntry("DropBoxTest.A", a1.getTimeMillis()));
 
-        DropBoxEntry b0 = dropbox.getNextEntry("DropBoxTest.B", before);
+        DropBox.Entry b0 = dropbox.getNextEntry("DropBoxTest.B", before);
         assertTrue(null == dropbox.getNextEntry("DropBoxTest.B", b0.getTimeMillis()));
 
-        DropBoxEntry x0 = dropbox.getNextEntry(null, before);
-        DropBoxEntry x1 = dropbox.getNextEntry(null, x0.getTimeMillis());
-        DropBoxEntry x2 = dropbox.getNextEntry(null, x1.getTimeMillis());
+        DropBox.Entry x0 = dropbox.getNextEntry(null, before);
+        DropBox.Entry x1 = dropbox.getNextEntry(null, x0.getTimeMillis());
+        DropBox.Entry x2 = dropbox.getNextEntry(null, x1.getTimeMillis());
         assertTrue(null == dropbox.getNextEntry(null, x2.getTimeMillis()));
 
         assertEquals("DropBoxTest.A", a0.getTag());
@@ -321,7 +322,7 @@
         x0.close();
         x1.close();
         x2.close();
-        dropbox.stop();
+        service.stop();
     }
 
     public void testSizeLimits() throws Exception {
@@ -344,7 +345,9 @@
 
         final int overhead = 64;
         long before = System.currentTimeMillis();
-        DropBoxService dropbox = new DropBoxService(getContext(), dir);
+        DropBoxService service = new DropBoxService(getContext(), dir);
+        DropBox dropbox = new DropBox(service);
+
         addRandomEntry(dropbox, "DropBoxTest0", blockSize - overhead);
         addRandomEntry(dropbox, "DropBoxTest0", blockSize - overhead);
 
@@ -358,16 +361,16 @@
         addRandomEntry(dropbox, "DropBoxTest2", blockSize - overhead);
         addRandomEntry(dropbox, "DropBoxTest2", blockSize - overhead);
 
-        DropBoxEntry e0 = dropbox.getNextEntry(null, before);
-        DropBoxEntry e1 = dropbox.getNextEntry(null, e0.getTimeMillis());
-        DropBoxEntry e2 = dropbox.getNextEntry(null, e1.getTimeMillis());
-        DropBoxEntry e3 = dropbox.getNextEntry(null, e2.getTimeMillis());
-        DropBoxEntry e4 = dropbox.getNextEntry(null, e3.getTimeMillis());
-        DropBoxEntry e5 = dropbox.getNextEntry(null, e4.getTimeMillis());
-        DropBoxEntry e6 = dropbox.getNextEntry(null, e5.getTimeMillis());
-        DropBoxEntry e7 = dropbox.getNextEntry(null, e6.getTimeMillis());
-        DropBoxEntry e8 = dropbox.getNextEntry(null, e7.getTimeMillis());
-        DropBoxEntry e9 = dropbox.getNextEntry(null, e8.getTimeMillis());
+        DropBox.Entry e0 = dropbox.getNextEntry(null, before);
+        DropBox.Entry e1 = dropbox.getNextEntry(null, e0.getTimeMillis());
+        DropBox.Entry e2 = dropbox.getNextEntry(null, e1.getTimeMillis());
+        DropBox.Entry e3 = dropbox.getNextEntry(null, e2.getTimeMillis());
+        DropBox.Entry e4 = dropbox.getNextEntry(null, e3.getTimeMillis());
+        DropBox.Entry e5 = dropbox.getNextEntry(null, e4.getTimeMillis());
+        DropBox.Entry e6 = dropbox.getNextEntry(null, e5.getTimeMillis());
+        DropBox.Entry e7 = dropbox.getNextEntry(null, e6.getTimeMillis());
+        DropBox.Entry e8 = dropbox.getNextEntry(null, e7.getTimeMillis());
+        DropBox.Entry e9 = dropbox.getNextEntry(null, e8.getTimeMillis());
         assertTrue(null == dropbox.getNextEntry(null, e9.getTimeMillis()));
 
         assertEquals("DropBoxTest0", e0.getTag());
@@ -406,9 +409,9 @@
 
         // Specifying a tag name skips tombstone records.
 
-        DropBoxEntry t0 = dropbox.getNextEntry("DropBoxTest1", before);
-        DropBoxEntry t1 = dropbox.getNextEntry("DropBoxTest1", t0.getTimeMillis());
-        DropBoxEntry t2 = dropbox.getNextEntry("DropBoxTest1", t1.getTimeMillis());
+        DropBox.Entry t0 = dropbox.getNextEntry("DropBoxTest1", before);
+        DropBox.Entry t1 = dropbox.getNextEntry("DropBoxTest1", t0.getTimeMillis());
+        DropBox.Entry t2 = dropbox.getNextEntry("DropBoxTest1", t1.getTimeMillis());
         assertTrue(null == dropbox.getNextEntry("DropBoxTest1", t2.getTimeMillis()));
 
         assertEquals("DropBoxTest1", t0.getTag());
@@ -422,7 +425,7 @@
         t0.close();
         t1.close();
         t2.close();
-        dropbox.stop();
+        service.stop();
     }
 
     public void testAgeLimits() throws Exception {
@@ -438,13 +441,15 @@
 
         // Write one normal entry and another so big that it is instantly tombstoned
         long before = System.currentTimeMillis();
-        DropBoxService dropbox = new DropBoxService(getContext(), dir);
+        DropBoxService service = new DropBoxService(getContext(), dir);
+        DropBox dropbox = new DropBox(service);
+
         dropbox.addText("DropBoxTest", "TEST");
         addRandomEntry(dropbox, "DropBoxTest", blockSize * 20);
 
         // Verify that things are as expected
-        DropBoxEntry e0 = dropbox.getNextEntry(null, before);
-        DropBoxEntry e1 = dropbox.getNextEntry(null, e0.getTimeMillis());
+        DropBox.Entry e0 = dropbox.getNextEntry(null, before);
+        DropBox.Entry e1 = dropbox.getNextEntry(null, e0.getTimeMillis());
         assertTrue(null == dropbox.getNextEntry(null, e1.getTimeMillis()));
 
         assertEquals("TEST", e0.getText(80));
@@ -471,7 +476,8 @@
 
         File dir = new File(getEmptyDir("testCreateDropBoxWith"), "InvalidDirectory");
         new FileOutputStream(dir).close();  // Create an empty file
-        DropBoxService dropbox = new DropBoxService(getContext(), dir);
+        DropBoxService service = new DropBoxService(getContext(), dir);
+        DropBox dropbox = new DropBox(service);
 
         dropbox.addText("DropBoxTest", "should be ignored");
         dropbox.addData("DropBoxTest", "should be ignored".getBytes(), 0);
@@ -479,15 +485,15 @@
 
         dir.delete();  // Remove the file so a directory can be created
         dropbox.addText("DropBoxTest", "TEST");
-        DropBoxEntry e = dropbox.getNextEntry("DropBoxTest", 0);
+        DropBox.Entry e = dropbox.getNextEntry("DropBoxTest", 0);
         assertTrue(null == dropbox.getNextEntry("DropBoxTest", e.getTimeMillis()));
         assertEquals("DropBoxTest", e.getTag());
         assertEquals("TEST", e.getText(80));
         e.close();
-        dropbox.stop();
+        service.stop();
     }
 
-    private void addRandomEntry(IDropBox dropbox, String tag, int size) throws Exception {
+    private void addRandomEntry(DropBox dropbox, String tag, int size) throws Exception {
         byte[] bytes = new byte[size];
         new Random(System.currentTimeMillis()).nextBytes(bytes);
 
@@ -501,7 +507,7 @@
         fd.close();
     }
 
-    private int getEntrySize(DropBoxEntry e) throws Exception {
+    private int getEntrySize(DropBox.Entry e) throws Exception {
         InputStream is = e.getInputStream();
         if (is == null) return -1;
         int length = 0;
diff --git a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardExporterTests.java b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardExporterTests.java
index d0097c4..cfa9ab3 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardExporterTests.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/vcard/VCardExporterTests.java
@@ -643,9 +643,6 @@
         testStructuredNameUseSuperPrimaryCommon(V30);
     }
 
-    /**
-     * There's no property for nickname in vCard 2.1, so we don't have any requirement on it.
-     */
     public void testNickNameV30() {
         ExportTestResolver resolver = new ExportTestResolver();
         ContentValues contentValues = resolver.buildData(Nickname.CONTENT_ITEM_TYPE);
@@ -1269,4 +1266,23 @@
 
         verifyOneComposition(resolver, handler, version);
     }
+
+    /**
+     * There's no "NICKNAME" property in vCard 2.1, while there is in vCard 3.0.
+     * We use Android-specific "X-ANDROID-CUSTOM" property.
+     * This test verifies the functionality.
+     */
+    public void testNickNameV21() {
+        ExportTestResolver resolver = new ExportTestResolver();
+        ContentValues contentValues = resolver.buildData(Nickname.CONTENT_ITEM_TYPE);
+        contentValues.put(Nickname.NAME, "Nicky");
+
+        VCardVerificationHandler handler = new VCardVerificationHandler(this, V21);
+        handler.addNewVerifierWithEmptyName()
+            .addNodeWithOrder("X-ANDROID-CUSTOM", Nickname.CONTENT_ITEM_TYPE + ";Nicky;;;;;;;;;;;;;;");
+
+        // TODO: also test import part.
+
+        verifyOneComposition(resolver, handler, V21);
+    }
 }
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTest.java
index 50b7c3f..9bc0962 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTest.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTest.java
@@ -74,6 +74,8 @@
 
         Intent intent = new Intent(runner.getContext(), ReliabilityTestActivity.class);
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        ReliabilityTestActivity activity = (ReliabilityTestActivity)runner.startActivitySync(
+            intent);
         //read from BufferedReader instead of populating a list in advance,
         //this will avoid excessive memory usage in case of a large list
         while((url = listReader.readLine()) != null) {
@@ -83,8 +85,6 @@
             start = System.currentTimeMillis();
             Log.v(LOGTAG, "Testing URL: " + url);
             FsUtils.updateTestStatus(TEST_STATUS_FILE, url);
-            ReliabilityTestActivity activity = (ReliabilityTestActivity)runner.startActivitySync(
-                    intent);
             activity.reset();
             //use message to send new URL to avoid interacting with
             //WebView in non-UI thread
@@ -110,11 +110,11 @@
             if(runner.mLogtime) {
                 writeLoadTime(url, activity.getPageLoadTime());
             }
-            activity.finish();
             System.runFinalization();
             System.gc();
             System.gc();
         }
+        activity.finish();
         FsUtils.updateTestStatus(TEST_STATUS_FILE, TEST_DONE);
 //        activity.finish();
         listReader.close();