Merge "Turn off media time adjustment by default" into gingerbread
diff --git a/api/current.xml b/api/current.xml
index 524d296..8c164c1 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -63056,146 +63056,6 @@
 >
 </field>
 </class>
-<class name="BitmapRegionDecoder"
- extends="java.lang.Object"
- abstract="false"
- static="false"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-<method name="decodeRegion"
- return="android.graphics.Bitmap"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="rect" type="android.graphics.Rect">
-</parameter>
-<parameter name="options" type="android.graphics.BitmapFactory.Options">
-</parameter>
-</method>
-<method name="getHeight"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="getWidth"
- return="int"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="isRecycled"
- return="boolean"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-<method name="newInstance"
- return="android.graphics.BitmapRegionDecoder"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="data" type="byte[]">
-</parameter>
-<parameter name="offset" type="int">
-</parameter>
-<parameter name="length" type="int">
-</parameter>
-<parameter name="isShareable" type="boolean">
-</parameter>
-<exception name="IOException" type="java.io.IOException">
-</exception>
-</method>
-<method name="newInstance"
- return="android.graphics.BitmapRegionDecoder"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="fd" type="java.io.FileDescriptor">
-</parameter>
-<parameter name="isShareable" type="boolean">
-</parameter>
-<exception name="IOException" type="java.io.IOException">
-</exception>
-</method>
-<method name="newInstance"
- return="android.graphics.BitmapRegionDecoder"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="is" type="java.io.InputStream">
-</parameter>
-<parameter name="isShareable" type="boolean">
-</parameter>
-<exception name="IOException" type="java.io.IOException">
-</exception>
-</method>
-<method name="newInstance"
- return="android.graphics.BitmapRegionDecoder"
- abstract="false"
- native="false"
- synchronized="false"
- static="true"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="pathName" type="java.lang.String">
-</parameter>
-<parameter name="isShareable" type="boolean">
-</parameter>
-<exception name="IOException" type="java.io.IOException">
-</exception>
-</method>
-<method name="recycle"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
-</class>
 <class name="BitmapShader"
  extends="android.graphics.Shader"
  abstract="false"
@@ -79357,7 +79217,7 @@
  type="float"
  transient="false"
  volatile="false"
- value="0.0010f"
+ value="0.001f"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -128720,7 +128580,7 @@
  visibility="public"
 >
 <method name="allowThreadDiskReads"
- return="int"
+ return="android.os.StrictMode.ThreadPolicy"
  abstract="false"
  native="false"
  synchronized="false"
@@ -128731,7 +128591,7 @@
 >
 </method>
 <method name="allowThreadDiskWrites"
- return="int"
+ return="android.os.StrictMode.ThreadPolicy"
  abstract="false"
  native="false"
  synchronized="false"
@@ -128742,7 +128602,18 @@
 >
 </method>
 <method name="getThreadPolicy"
- return="int"
+ return="android.os.StrictMode.ThreadPolicy"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getVmPolicy"
+ return="android.os.StrictMode.VmPolicy"
  abstract="false"
  native="false"
  synchronized="false"
@@ -128762,86 +128633,313 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="policyMask" type="int">
+<parameter name="policy" type="android.os.StrictMode.ThreadPolicy">
 </parameter>
 </method>
-<field name="DISALLOW_DISK_READ"
- type="int"
+<method name="setVmPolicy"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="policy" type="android.os.StrictMode.VmPolicy">
+</parameter>
+</method>
+</class>
+<class name="StrictMode.ThreadPolicy"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<field name="LAX"
+ type="android.os.StrictMode.ThreadPolicy"
  transient="false"
  volatile="false"
- value="2"
  static="true"
  final="true"
  deprecated="not deprecated"
  visibility="public"
 >
 </field>
-<field name="DISALLOW_DISK_WRITE"
- type="int"
+</class>
+<class name="StrictMode.ThreadPolicy.Builder"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="StrictMode.ThreadPolicy.Builder"
+ type="android.os.StrictMode.ThreadPolicy.Builder"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="StrictMode.ThreadPolicy.Builder"
+ type="android.os.StrictMode.ThreadPolicy.Builder"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="policy" type="android.os.StrictMode.ThreadPolicy">
+</parameter>
+</constructor>
+<method name="build"
+ return="android.os.StrictMode.ThreadPolicy"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="detectAll"
+ return="android.os.StrictMode.ThreadPolicy.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="detectDiskReads"
+ return="android.os.StrictMode.ThreadPolicy.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="detectDiskWrites"
+ return="android.os.StrictMode.ThreadPolicy.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="detectNetwork"
+ return="android.os.StrictMode.ThreadPolicy.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="penaltyDeath"
+ return="android.os.StrictMode.ThreadPolicy.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="penaltyDialog"
+ return="android.os.StrictMode.ThreadPolicy.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="penaltyDropBox"
+ return="android.os.StrictMode.ThreadPolicy.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="penaltyLog"
+ return="android.os.StrictMode.ThreadPolicy.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="permitAll"
+ return="android.os.StrictMode.ThreadPolicy.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="permitDiskReads"
+ return="android.os.StrictMode.ThreadPolicy.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="permitDiskWrites"
+ return="android.os.StrictMode.ThreadPolicy.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="permitNetwork"
+ return="android.os.StrictMode.ThreadPolicy.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="StrictMode.VmPolicy"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<field name="LAX"
+ type="android.os.StrictMode.VmPolicy"
  transient="false"
  volatile="false"
- value="1"
  static="true"
  final="true"
  deprecated="not deprecated"
  visibility="public"
 >
 </field>
-<field name="DISALLOW_NETWORK"
- type="int"
- transient="false"
- volatile="false"
- value="4"
+</class>
+<class name="StrictMode.VmPolicy.Builder"
+ extends="java.lang.Object"
+ abstract="false"
  static="true"
  final="true"
  deprecated="not deprecated"
  visibility="public"
 >
-</field>
-<field name="PENALTY_DEATH"
- type="int"
- transient="false"
- volatile="false"
- value="64"
- static="true"
- final="true"
+<constructor name="StrictMode.VmPolicy.Builder"
+ type="android.os.StrictMode.VmPolicy.Builder"
+ static="false"
+ final="false"
  deprecated="not deprecated"
  visibility="public"
 >
-</field>
-<field name="PENALTY_DIALOG"
- type="int"
- transient="false"
- volatile="false"
- value="32"
- static="true"
- final="true"
+</constructor>
+<method name="build"
+ return="android.os.StrictMode.VmPolicy"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
  deprecated="not deprecated"
  visibility="public"
 >
-</field>
-<field name="PENALTY_DROPBOX"
- type="int"
- transient="false"
- volatile="false"
- value="128"
- static="true"
- final="true"
+</method>
+<method name="detectAll"
+ return="android.os.StrictMode.VmPolicy.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
  deprecated="not deprecated"
  visibility="public"
 >
-</field>
-<field name="PENALTY_LOG"
- type="int"
- transient="false"
- volatile="false"
- value="16"
- static="true"
- final="true"
+</method>
+<method name="detectLeakedSqlLiteObjects"
+ return="android.os.StrictMode.VmPolicy.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
  deprecated="not deprecated"
  visibility="public"
 >
-</field>
+</method>
+<method name="penaltyDeath"
+ return="android.os.StrictMode.VmPolicy.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="penaltyDropBox"
+ return="android.os.StrictMode.VmPolicy.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="penaltyLog"
+ return="android.os.StrictMode.VmPolicy.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 </class>
 <class name="SystemClock"
  extends="java.lang.Object"
@@ -225068,7 +225166,7 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="t" type="T">
+<parameter name="arg0" type="T">
 </parameter>
 </method>
 </interface>
@@ -232827,7 +232925,7 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="n" type="long">
+<parameter name="byteCount" type="long">
 </parameter>
 <exception name="IOException" type="java.io.IOException">
 </exception>
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index 39b3a20..37c8ad0 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -34,7 +34,6 @@
 
     private String[] mArgs;
     private int mNextArg;
-    private String mCurArgData;
 
     public static void main(String[] args) {
         try {
@@ -274,6 +273,10 @@
     }
 
     private void printRestoreSets(RestoreSet[] sets) {
+        if (sets == null || sets.length == 0) {
+            System.out.println("No restore sets");
+            return;
+        }
         for (RestoreSet s : sets) {
             System.out.println("  " + Long.toHexString(s.token) + " : " + s.name);
         }
diff --git a/cmds/keystore/keystore.c b/cmds/keystore/keystore.c
index 971a177..afa64f8 100644
--- a/cmds/keystore/keystore.c
+++ b/cmds/keystore/keystore.c
@@ -143,15 +143,20 @@
     send(the_socket, message, length, 0);
 }
 
-/* Here is the file format. Values are encrypted by AES CBC, and MD5 is used to
- * compute their checksums. To make the files portable, the length is stored in
- * network order. Note that the first four bytes are reserved for future use and
- * are always set to zero in this implementation. */
+/* Here is the file format. There are two parts in blob.value, the secret and
+ * the description. The secret is stored in ciphertext, and its original size
+ * can be found in blob.length. The description is stored after the secret in
+ * plaintext, and its size is specified in blob.info. The total size of the two
+ * parts must be no more than VALUE_SIZE bytes. The first three bytes of the
+ * file are reserved for future use and are always set to zero. Fields other
+ * than blob.info, blob.length, and blob.value are modified by encrypt_blob()
+ * and decrypt_blob(). Thus they should not be accessed from outside. */
 
 static int the_entropy = -1;
 
 static struct __attribute__((packed)) {
-    uint32_t reserved;
+    uint8_t reserved[3];
+    uint8_t info;
     uint8_t vector[AES_BLOCK_SIZE];
     uint8_t encrypted[0];
     uint8_t digest[MD5_DIGEST_LENGTH];
@@ -170,9 +175,13 @@
         return SYSTEM_ERROR;
     }
 
-    length = blob.length + blob.value - blob.encrypted;
+    length = blob.length + (blob.value - blob.encrypted);
     length = (length + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE * AES_BLOCK_SIZE;
 
+    if (blob.info != 0) {
+        memmove(&blob.encrypted[length], &blob.value[blob.length], blob.info);
+    }
+
     blob.length = htonl(blob.length);
     MD5(blob.digested, length - (blob.digested - blob.encrypted), blob.digest);
 
@@ -180,8 +189,8 @@
     AES_cbc_encrypt(blob.encrypted, blob.encrypted, length, aes_key, vector,
                     AES_ENCRYPT);
 
-    blob.reserved = 0;
-    length += blob.encrypted - (uint8_t *)&blob;
+    memset(blob.reserved, 0, sizeof(blob.reserved));
+    length += (blob.encrypted - (uint8_t *)&blob) + blob.info;
 
     fd = open(".tmp", O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
     length -= write(fd, &blob, length);
@@ -200,7 +209,7 @@
     length = read(fd, &blob, sizeof(blob));
     close(fd);
 
-    length -= blob.encrypted - (uint8_t *)&blob;
+    length -= (blob.encrypted - (uint8_t *)&blob) + blob.info;
     if (length < blob.value - blob.encrypted || length % AES_BLOCK_SIZE != 0) {
         return VALUE_CORRUPTED;
     }
@@ -215,8 +224,13 @@
 
     length -= blob.value - blob.digested;
     blob.length = ntohl(blob.length);
-    return (blob.length < 0 || blob.length > length) ? VALUE_CORRUPTED :
-           NO_ERROR;
+    if (blob.length < 0 || blob.length > length) {
+        return VALUE_CORRUPTED;
+    }
+    if (blob.info != 0) {
+        memmove(&blob.value[blob.length], &blob.value[length], blob.info);
+    }
+    return NO_ERROR;
 }
 
 /* Here are the actions. Each of them is a function without arguments. All
@@ -266,6 +280,7 @@
     char name[NAME_MAX];
     int n = sprintf(name, "%u_", uid);
     encode_key(&name[n], params[0].value, params[0].length);
+    blob.info = 0;
     blob.length = params[1].length;
     memcpy(blob.value, params[1].value, params[1].length);
     return encrypt_blob(name, &encryption_key);
@@ -336,56 +351,88 @@
 
 #define MASTER_KEY_FILE ".masterkey"
 #define MASTER_KEY_SIZE 16
+#define SALT_SIZE       16
 
-static void generate_key(uint8_t *key, uint8_t *password, int length)
+static void set_key(uint8_t *key, uint8_t *password, int length, uint8_t *salt)
 {
-    PKCS5_PBKDF2_HMAC_SHA1((char *)password, length, (uint8_t *)"keystore",
-                           sizeof("keystore"), 1024, MASTER_KEY_SIZE, key);
+    if (salt) {
+        PKCS5_PBKDF2_HMAC_SHA1((char *)password, length, salt, SALT_SIZE,
+                               8192, MASTER_KEY_SIZE, key);
+    } else {
+        PKCS5_PBKDF2_HMAC_SHA1((char *)password, length, (uint8_t *)"keystore",
+                               sizeof("keystore"), 1024, MASTER_KEY_SIZE, key);
+    }
 }
 
+/* Here is the history. To improve the security, the parameters to generate the
+ * master key has been changed. To make a seamless transition, we update the
+ * file using the same password when the user unlock it for the first time. If
+ * any thing goes wrong during the transition, the new file will not overwrite
+ * the old one. This avoids permanent damages of the existing data. */
+
 static int8_t password()
 {
     uint8_t key[MASTER_KEY_SIZE];
     AES_KEY aes_key;
-    int n;
+    int8_t response = SYSTEM_ERROR;
 
     if (state == UNINITIALIZED) {
-        blob.length = MASTER_KEY_SIZE;
         if (read(the_entropy, blob.value, MASTER_KEY_SIZE) != MASTER_KEY_SIZE) {
            return SYSTEM_ERROR;
         }
     } else {
-        generate_key(key, params[0].value, params[0].length);
+        int fd = open(MASTER_KEY_FILE, O_RDONLY);
+        uint8_t *salt = NULL;
+        if (fd != -1) {
+            int length = read(fd, &blob, sizeof(blob));
+            close(fd);
+            if (length > SALT_SIZE && blob.info == SALT_SIZE) {
+                salt = (uint8_t *)&blob + length - SALT_SIZE;
+            }
+        }
+
+        set_key(key, params[0].value, params[0].length, salt);
         AES_set_decrypt_key(key, MASTER_KEY_SIZE * 8, &aes_key);
-        n = decrypt_blob(MASTER_KEY_FILE, &aes_key);
-        if (n == SYSTEM_ERROR) {
+        response = decrypt_blob(MASTER_KEY_FILE, &aes_key);
+        if (response == SYSTEM_ERROR) {
             return SYSTEM_ERROR;
         }
-        if (n != NO_ERROR || blob.length != MASTER_KEY_SIZE) {
+        if (response != NO_ERROR || blob.length != MASTER_KEY_SIZE) {
             if (retry <= 0) {
                 reset();
                 return UNINITIALIZED;
             }
             return WRONG_PASSWORD + --retry;
         }
+
+        if (!salt && params[1].length == -1) {
+            params[1] = params[0];
+        }
     }
 
     if (params[1].length == -1) {
         memcpy(key, blob.value, MASTER_KEY_SIZE);
     } else {
-        generate_key(key, params[1].value, params[1].length);
+        uint8_t *salt = &blob.value[MASTER_KEY_SIZE];
+        if (read(the_entropy, salt, SALT_SIZE) != SALT_SIZE) {
+            return SYSTEM_ERROR;
+        }
+
+        set_key(key, params[1].value, params[1].length, salt);
         AES_set_encrypt_key(key, MASTER_KEY_SIZE * 8, &aes_key);
         memcpy(key, blob.value, MASTER_KEY_SIZE);
-        n = encrypt_blob(MASTER_KEY_FILE, &aes_key);
+        blob.info = SALT_SIZE;
+        blob.length = MASTER_KEY_SIZE;
+        response = encrypt_blob(MASTER_KEY_FILE, &aes_key);
     }
 
-    if (n == NO_ERROR) {
+    if (response == NO_ERROR) {
         AES_set_encrypt_key(key, MASTER_KEY_SIZE * 8, &encryption_key);
         AES_set_decrypt_key(key, MASTER_KEY_SIZE * 8, &decryption_key);
         state = NO_ERROR;
         retry = MAX_RETRY;
     }
-    return n;
+    return response;
 }
 
 static int8_t lock()
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index 9d559d4..c476b8f 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -47,6 +47,10 @@
  * Instances of this class should be obtained through
  * {@link android.content.Context#getSystemService(String)} by passing
  * {@link android.content.Context#DOWNLOAD_SERVICE}.
+ *
+ * Apps that request downloads through this API should register a broadcast receiver for
+ * {@link #ACTION_NOTIFICATION_CLICKED} to appropriately handle when the user clicks on a running
+ * download in a notification or from the downloads UI.
  */
 public class DownloadManager {
     /**
@@ -239,8 +243,8 @@
     public final static String ACTION_DOWNLOAD_COMPLETE = "android.intent.action.DOWNLOAD_COMPLETE";
 
     /**
-     * Broadcast intent action sent by the download manager when a running download notification is
-     * clicked.
+     * Broadcast intent action sent by the download manager when the user clicks on a running
+     * download, either from a system notification or from the downloads UI.
      */
     public final static String ACTION_NOTIFICATION_CLICKED =
             "android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED";
@@ -413,7 +417,9 @@
         }
 
         /**
-         * Set the title of this download, to be displayed in notifications (if enabled)
+         * Set the title of this download, to be displayed in notifications (if enabled).  If no
+         * title is given, a default one will be assigned based on the download filename, once the
+         * download starts.
          * @return this object
          */
         public Request setTitle(CharSequence title) {
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index cb6b708..7346561 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -27,8 +27,6 @@
 import android.content.res.XmlResourceParser;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
-import android.os.Environment;
-import android.os.StatFs;
 import android.util.AndroidException;
 import android.util.DisplayMetrics;
 
@@ -1388,11 +1386,18 @@
      * {@link Intent#resolveActivity} finds an activity if a class has not
      * been explicitly specified.
      *
+     * <p><em>Note: if using an implicit Intent (without an explicit ComponentName
+     * specified), be sure to consider whether to set the {@link #MATCH_DEFAULT_ONLY}
+     * only flag.  You need to do so to resolve the activity in the same way
+     * that {@link android.content.Context#startActivity(Intent)} and
+     * {@link android.content.Intent#resolveActivity(PackageManager)
+     * Intent.resolveActivity(PackageManager)} do.</p>
+     * 
      * @param intent An intent containing all of the desired specification
      *               (action, data, type, category, and/or component).
      * @param flags Additional option flags.  The most important is
-     *                    MATCH_DEFAULT_ONLY, to limit the resolution to only
-     *                    those activities that support the CATEGORY_DEFAULT.
+     * {@link #MATCH_DEFAULT_ONLY}, to limit the resolution to only
+     * those activities that support the {@link android.content.Intent#CATEGORY_DEFAULT}.
      *
      * @return Returns a ResolveInfo containing the final activity intent that
      *         was determined to be the best action.  Returns null if no
@@ -1411,13 +1416,13 @@
      *
      * @param intent The desired intent as per resolveActivity().
      * @param flags Additional option flags.  The most important is
-     *                    MATCH_DEFAULT_ONLY, to limit the resolution to only
-     *                    those activities that support the CATEGORY_DEFAULT.
+     * {@link #MATCH_DEFAULT_ONLY}, to limit the resolution to only
+     * those activities that support the {@link android.content.Intent#CATEGORY_DEFAULT}.
      *
-     * @return A List<ResolveInfo> containing one entry for each matching
+     * @return A List&lt;ResolveInfo&gt; containing one entry for each matching
      *         Activity. These are ordered from best to worst match -- that
      *         is, the first item in the list is what is returned by
-     *         resolveActivity().  If there are no matching activities, an empty
+     *         {@link #resolveActivity}.  If there are no matching activities, an empty
      *         list is returned.
      *
      * @see #MATCH_DEFAULT_ONLY
@@ -1442,10 +1447,10 @@
      *                  first specific results.  Can be null.
      * @param intent The desired intent as per resolveActivity().
      * @param flags Additional option flags.  The most important is
-     *                    MATCH_DEFAULT_ONLY, to limit the resolution to only
-     *                    those activities that support the CATEGORY_DEFAULT.
+     * {@link #MATCH_DEFAULT_ONLY}, to limit the resolution to only
+     * those activities that support the {@link android.content.Intent#CATEGORY_DEFAULT}.
      *
-     * @return A List<ResolveInfo> containing one entry for each matching
+     * @return A List&lt;ResolveInfo&gt; containing one entry for each matching
      *         Activity. These are ordered first by all of the intents resolved
      *         in <var>specifics</var> and then any additional activities that
      *         can handle <var>intent</var> but did not get included by one of
@@ -1463,11 +1468,9 @@
      * Retrieve all receivers that can handle a broadcast of the given intent.
      *
      * @param intent The desired intent as per resolveActivity().
-     * @param flags Additional option flags.  The most important is
-     *                    MATCH_DEFAULT_ONLY, to limit the resolution to only
-     *                    those activities that support the CATEGORY_DEFAULT.
+     * @param flags Additional option flags.
      *
-     * @return A List<ResolveInfo> containing one entry for each matching
+     * @return A List&lt;ResolveInfo&gt; containing one entry for each matching
      *         Receiver. These are ordered from first to last in priority.  If
      *         there are no matching receivers, an empty list is returned.
      *
@@ -1500,7 +1503,7 @@
      * @param intent The desired intent as per resolveService().
      * @param flags Additional option flags.
      *
-     * @return A List<ResolveInfo> containing one entry for each matching
+     * @return A List&lt;ResolveInfo&gt; containing one entry for each matching
      *         ServiceInfo. These are ordered from best to worst match -- that
      *         is, the first item in the list is what is returned by
      *         resolveService().  If there are no matching services, an empty
@@ -1537,7 +1540,7 @@
      *        uid owning the requested content providers.
      * @param flags Additional option flags.  Currently should always be 0.
      *
-     * @return A List<ContentProviderInfo> containing one entry for each
+     * @return A List&lt;ContentProviderInfo&gt; containing one entry for each
      *         content provider either patching <var>processName</var> or, if
      *         <var>processName</var> is null, all known content providers.
      *         <em>If there are no matching providers, null is returned.</em>
@@ -1573,7 +1576,7 @@
      *                      returned.
      * @param flags Additional option flags.  Currently should always be 0.
      *
-     * @return A List<InstrumentationInfo> containing one entry for each
+     * @return A List&lt;InstrumentationInfo&gt; containing one entry for each
      *         matching available Instrumentation.  Returns an empty list if
      *         there is no instrumentation available for the given package.
      */
diff --git a/core/java/android/database/sqlite/SQLiteCompiledSql.java b/core/java/android/database/sqlite/SQLiteCompiledSql.java
index 25aa9b3..003d0f2 100644
--- a/core/java/android/database/sqlite/SQLiteCompiledSql.java
+++ b/core/java/android/database/sqlite/SQLiteCompiledSql.java
@@ -16,6 +16,7 @@
 
 package android.database.sqlite;
 
+import android.os.StrictMode;
 import android.util.Log;
 
 /**
@@ -145,10 +146,14 @@
             if (SQLiteDebug.DEBUG_ACTIVE_CURSOR_FINALIZATION) {
                 Log.v(TAG, "** warning ** Finalized DbObj (id#" + nStatement + ")");
             }
-            int len = mSqlStmt.length();
-            Log.w(TAG, "Releasing statement in a finalizer. Please ensure " +
+            if (StrictMode.vmSqliteObjectLeaksEnabled()) {
+                int len = mSqlStmt.length();
+                StrictMode.onSqliteObjectLeaked(
+                    "Releasing statement in a finalizer. Please ensure " +
                     "that you explicitly call close() on your cursor: " +
-                    mSqlStmt.substring(0, (len > 100) ? 100 : len), mStackTrace);
+                    mSqlStmt.substring(0, (len > 100) ? 100 : len),
+                    mStackTrace);
+            }
             releaseSqlStatement();
         } finally {
             super.finalize();
diff --git a/core/java/android/database/sqlite/SQLiteCursor.java b/core/java/android/database/sqlite/SQLiteCursor.java
index c7e58fa..d8dcaf7 100644
--- a/core/java/android/database/sqlite/SQLiteCursor.java
+++ b/core/java/android/database/sqlite/SQLiteCursor.java
@@ -24,6 +24,7 @@
 import android.os.Handler;
 import android.os.Message;
 import android.os.Process;
+import android.os.StrictMode;
 import android.text.TextUtils;
 import android.util.Config;
 import android.util.Log;
@@ -582,11 +583,14 @@
         try {
             // if the cursor hasn't been closed yet, close it first
             if (mWindow != null) {
-                int len = mQuery.mSql.length();
-                Log.e(TAG, "Finalizing a Cursor that has not been deactivated or closed. " +
+                if (StrictMode.vmSqliteObjectLeaksEnabled()) {
+                    int len = mQuery.mSql.length();
+                    StrictMode.onSqliteObjectLeaked(
+                        "Finalizing a Cursor that has not been deactivated or closed. " +
                         "database = " + mDatabase.getPath() + ", table = " + mEditTable +
                         ", query = " + mQuery.mSql.substring(0, (len > 100) ? 100 : len),
                         mStackTrace);
+                }
                 close();
                 SQLiteDebug.notifyActiveCursorFinalized();
             } else {
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 3ddaad9..9494a06 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -30,8 +30,9 @@
 import java.util.HashMap;
 
 /**
- * <p>StrictMode is a developer tool which lets you impose stricter
- * rules under which your application runs.
+ * <p>StrictMode is a developer tool which detects things you might be
+ * doing by accident and brings them to your attention so you can fix
+ * them.
  *
  * <p>StrictMode is most commonly used to catch accidental disk or
  * network access on the application's main thread, where UI
@@ -55,24 +56,33 @@
  * <pre>
  * public void onCreate() {
  *     if (DEVELOPER_MODE) {
- *         StrictMode.setThreadPolicy(StrictMode.DISALLOW_DISK_WRITE |
- *                 StrictMode.DISALLOW_DISK_READ |
- *                 StrictMode.DISALLOW_NETWORK |
- *                 StrictMode.PENALTY_LOG);
+ *         StrictMode.setThreadPolicy(new {@link ThreadPolicy.Builder StrictMode.ThreadPolicy.Builder}()
+ *                 .detectDiskReads()
+ *                 .detectDiskWrites()
+ *                 .detectNetwork()   // or .detectAll() for all detectable problems
+ *                 .penaltyLog()
+ *                 .build());
+ *         StrictMode.setVmPolicy(new {@link VmPolicy.Builder StrictMode.VmPolicy.Builder}()
+ *                 .detectLeakedSqlLiteCursors()
+ *                 .penaltyLog()
+ *                 .penaltyDeath()
+ *                 .build());
  *     }
  *     super.onCreate();
  * }
  * </pre>
  *
- * <p>Then you can watch the output of <code>adb logcat</code> while you
- * use your application.
+ * <p>You can decide what should happen when a violation is detected.
+ * For example, using {@link ThreadPolicy.Builder#penaltyLog} you can
+ * watch the output of <code>adb logcat</code> while you use your
+ * application to see the violations as they happen.
  *
  * <p>If you find violations that you feel are problematic, there are
  * a variety of tools to help solve them: threads, {@link android.os.Handler},
  * {@link android.os.AsyncTask}, {@link android.app.IntentService}, etc.
  * But don't feel compelled to fix everything that StrictMode finds.  In particular,
- * a lot of disk accesses are often necessary during the normal activity lifecycle.  Use
- * StrictMode to find things you did on accident.  Network requests on the UI thread
+ * many cases of disk access are often necessary during the normal activity lifecycle.  Use
+ * StrictMode to find things you did by accident.  Network requests on the UI thread
  * are almost always a problem, though.
  *
  * <p class="note">StrictMode is not a security mechanism and is not
@@ -94,55 +104,50 @@
     // Only show an annoying dialog at most every 30 seconds
     private static final long MIN_DIALOG_INTERVAL_MS = 30000;
 
-    private StrictMode() {}
+    // Thread-policy:
 
     /**
-     * Flag for {@link #setThreadPolicy} to signal that you don't intend for this
-     * thread to write to disk.
+     * @hide
      */
-    public static final int DISALLOW_DISK_WRITE = 0x01;
+    public static final int DETECT_DISK_WRITE = 0x01;  // for ThreadPolicy
 
     /**
-     * Flag for {@link #setThreadPolicy} to signal that you don't intend for this
-     * thread to read from disk.
+      * @hide
      */
-    public static final int DISALLOW_DISK_READ = 0x02;
+    public static final int DETECT_DISK_READ = 0x02;  // for ThreadPolicy
 
     /**
-     * Flag for {@link #setThreadPolicy} to signal that you don't intend for this
-     * thread to access the network.
+     * @hide
      */
-    public static final int DISALLOW_NETWORK = 0x04;
+    public static final int DETECT_NETWORK = 0x04;  // for ThreadPolicy
 
-    /** @hide */
-    public static final int DISALLOW_MASK =
-            DISALLOW_DISK_WRITE | DISALLOW_DISK_READ | DISALLOW_NETWORK;
+    // Process-policy:
 
     /**
-     * Penalty flag for {@link #setThreadPolicy} to log violations to
-     * the system log, visible with <code>adb logcat</code>.
+     * Note, a "VM_" bit, not thread.
+     * @hide
+     */
+    public static final int DETECT_VM_CURSOR_LEAKS = 0x200;  // for ProcessPolicy
+
+    /**
+     * @hide
      */
     public static final int PENALTY_LOG = 0x10;  // normal android.util.Log
 
+    // Used for both process and thread policy:
+
     /**
-     * Penalty flag for {@link #setThreadPolicy} to show an annoying
-     * dialog to the developer, rate-limited to be only a little
-     * annoying.
+     * @hide
      */
     public static final int PENALTY_DIALOG = 0x20;
 
     /**
-     * Penalty flag for {@link #setThreadPolicy} to crash hard if
-     * policy is violated.
+     * @hide
      */
     public static final int PENALTY_DEATH = 0x40;
 
     /**
-     * Penalty flag for {@link #setThreadPolicy} to log a stacktrace
-     * and timing data to the
-     * {@link android.os.DropBoxManager DropBox} on policy violation.
-     * Intended mostly for platform integrators doing beta user field
-     * data collection.
+     * @hide
      */
     public static final int PENALTY_DROPBOX = 0x80;
 
@@ -159,10 +164,321 @@
      */
     public static final int PENALTY_GATHER = 0x100;
 
-    /** @hide */
-    public static final int PENALTY_MASK =
-            PENALTY_LOG | PENALTY_DIALOG |
-            PENALTY_DROPBOX | PENALTY_DEATH;
+    /**
+     * The current VmPolicy in effect.
+     */
+    private static volatile int sVmPolicyMask = 0;
+
+    private StrictMode() {}
+
+    /**
+     * {@link StrictMode} policy applied to a certain thread.
+     *
+     * <p>The policy is enabled by {@link #setThreadPolicy}.  The current policy
+     * can be retrieved with {@link #getThreadPolicy}.
+     *
+     * <p>Note that multiple penalties may be provided and they're run
+     * in order from least to most severe (logging before process
+     * death, for example).  There's currently no mechanism to choose
+     * different penalties for different detected actions.
+     */
+    public static final class ThreadPolicy {
+        /**
+         * The default, lax policy which doesn't catch anything.
+         */
+        public static final ThreadPolicy LAX = new ThreadPolicy(0);
+
+        final int mask;
+
+        private ThreadPolicy(int mask) {
+            this.mask = mask;
+        }
+
+        @Override
+        public String toString() {
+            return "[StrictMode.ThreadPolicy; mask=" + mask + "]";
+        }
+
+        /**
+         * Creates ThreadPolicy instances.  Methods whose names start
+         * with {@code detect} specify what problems we should look
+         * for.  Methods whose names start with {@code penalty} specify what
+         * we should do when we detect a problem.
+         *
+         * <p>You can call as many {@code detect} and {@code penalty}
+         * methods as you like. Currently order is insignificant: all
+         * penalties apply to all detected problems.
+         *
+         * <p>For example, detect everything and log anything that's found:
+         * <pre>
+         * StrictMode.VmPolicy policy = new StrictMode.VmPolicy.Builder()
+         *     .detectAll()
+         *     .penaltyLog()
+         *     .build();
+         * StrictMode.setVmPolicy(policy);
+         * </pre>
+         */
+        public static final class Builder {
+            private int mMask = 0;
+
+            /**
+             * Create a Builder that detects nothing and has no
+             * violations.  (but note that {@link #build} will default
+             * to enabling {@link #penaltyLog} if no other penalties
+             * are specified)
+             */
+            public Builder() {
+                mMask = 0;
+            }
+
+            /**
+             * Initialize a Builder from an existing ThreadPolicy.
+             */
+            public Builder(ThreadPolicy policy) {
+                mMask = policy.mask;
+            }
+
+            /**
+             * Detect everything that's potentially suspect.
+             *
+             * <p>As of the Gingerbread release this includes network and
+             * disk operations but will likely expand in future releases.
+             */
+            public Builder detectAll() {
+                return enable(DETECT_DISK_WRITE | DETECT_DISK_READ | DETECT_NETWORK);
+            }
+
+            /**
+             * Disable the detection of everything.
+             */
+            public Builder permitAll() {
+                return disable(DETECT_DISK_WRITE | DETECT_DISK_READ | DETECT_NETWORK);
+            }
+
+            /**
+             * Enable detection of network operations.
+             */
+            public Builder detectNetwork() {
+                return enable(DETECT_NETWORK);
+            }
+
+            /**
+             * Disable detection of network operations.
+             */
+            public Builder permitNetwork() {
+                return disable(DETECT_NETWORK);
+            }
+
+            /**
+             * Enable detection of disk reads.
+             */
+            public Builder detectDiskReads() {
+                return enable(DETECT_DISK_READ);
+            }
+
+            /**
+             * Disable detection of disk reads.
+             */
+            public Builder permitDiskReads() {
+                return disable(DETECT_DISK_READ);
+            }
+
+            /**
+             * Enable detection of disk writes.
+             */
+            public Builder detectDiskWrites() {
+                return enable(DETECT_DISK_WRITE);
+            }
+
+            /**
+             * Disable detection of disk writes.
+             */
+            public Builder permitDiskWrites() {
+                return disable(DETECT_DISK_WRITE);
+            }
+
+            /**
+             * Show an annoying dialog to the developer on detected
+             * violations, rate-limited to be only a little annoying.
+             */
+            public Builder penaltyDialog() {
+                return enable(PENALTY_DIALOG);
+            }
+
+            /**
+             * Crash the whole process on violation.  This penalty runs at
+             * the end of all enabled penalties so you'll still get
+             * see logging or other violations before the process dies.
+             */
+            public Builder penaltyDeath() {
+                return enable(PENALTY_DEATH);
+            }
+
+            /**
+             * Log detected violations to the system log.
+             */
+            public Builder penaltyLog() {
+                return enable(PENALTY_LOG);
+            }
+
+            /**
+             * Enable detected violations log a stacktrace and timing data
+             * to the {@link android.os.DropBoxManager DropBox} on policy
+             * violation.  Intended mostly for platform integrators doing
+             * beta user field data collection.
+             */
+            public Builder penaltyDropBox() {
+                return enable(PENALTY_DROPBOX);
+            }
+
+            private Builder enable(int bit) {
+                mMask |= bit;
+                return this;
+            }
+
+            private Builder disable(int bit) {
+                mMask &= ~bit;
+                return this;
+            }
+
+            /**
+             * Construct the ThreadPolicy instance.
+             *
+             * <p>Note: if no penalties are enabled before calling
+             * <code>build</code>, {@link #penaltyLog} is implicitly
+             * set.
+             */
+            public ThreadPolicy build() {
+                // If there are detection bits set but no violation bits
+                // set, enable simple logging.
+                if (mMask != 0 &&
+                    (mMask & (PENALTY_DEATH | PENALTY_LOG |
+                              PENALTY_DROPBOX | PENALTY_DIALOG)) == 0) {
+                    penaltyLog();
+                }
+                return new ThreadPolicy(mMask);
+            }
+        }
+    }
+
+    /**
+     * {@link StrictMode} policy applied to all threads in the virtual machine's process.
+     *
+     * <p>The policy is enabled by {@link #setVmPolicy}.
+     */
+    public static final class VmPolicy {
+        /**
+         * The default, lax policy which doesn't catch anything.
+         */
+        public static final VmPolicy LAX = new VmPolicy(0);
+
+        final int mask;
+
+        private VmPolicy(int mask) {
+            this.mask = mask;
+        }
+
+        @Override
+        public String toString() {
+            return "[StrictMode.VmPolicy; mask=" + mask + "]";
+        }
+
+        /**
+         * Creates {@link VmPolicy} instances.  Methods whose names start
+         * with {@code detect} specify what problems we should look
+         * for.  Methods whose names start with {@code penalty} specify what
+         * we should do when we detect a problem.
+         *
+         * <p>You can call as many {@code detect} and {@code penalty}
+         * methods as you like. Currently order is insignificant: all
+         * penalties apply to all detected problems.
+         *
+         * <p>For example, detect everything and log anything that's found:
+         * <pre>
+         * StrictMode.VmPolicy policy = new StrictMode.VmPolicy.Builder()
+         *     .detectAll()
+         *     .penaltyLog()
+         *     .build();
+         * StrictMode.setVmPolicy(policy);
+         * </pre>
+         */
+        public static final class Builder {
+            private int mMask;
+
+            /**
+             * Detect everything that's potentially suspect.
+             *
+             * <p>As of the Gingerbread release this only includes
+             * SQLite cursor leaks but will likely expand in future
+             * releases.
+             */
+            public Builder detectAll() {
+                return enable(DETECT_VM_CURSOR_LEAKS);
+            }
+
+            /**
+             * Detect when an
+             * {@link android.database.sqlite.SQLiteCursor} or other
+             * SQLite object is finalized without having been closed.
+             *
+             * <p>You always want to explicitly close your SQLite
+             * cursors to avoid unnecessary database contention and
+             * temporary memory leaks.
+             */
+            public Builder detectLeakedSqlLiteObjects() {
+                return enable(DETECT_VM_CURSOR_LEAKS);
+            }
+
+            /**
+             * Crashes the whole process on violation.  This penalty runs at
+             * the end of all enabled penalties so yo you'll still get
+             * your logging or other violations before the process dies.
+             */
+            public Builder penaltyDeath() {
+                return enable(PENALTY_DEATH);
+            }
+
+            /**
+             * Log detected violations to the system log.
+             */
+            public Builder penaltyLog() {
+                return enable(PENALTY_LOG);
+            }
+
+            /**
+             * Enable detected violations log a stacktrace and timing data
+             * to the {@link android.os.DropBoxManager DropBox} on policy
+             * violation.  Intended mostly for platform integrators doing
+             * beta user field data collection.
+             */
+            public Builder penaltyDropBox() {
+                return enable(PENALTY_DROPBOX);
+            }
+
+            private Builder enable(int bit) {
+                mMask |= bit;
+                return this;
+            }
+
+            /**
+             * Construct the VmPolicy instance.
+             *
+             * <p>Note: if no penalties are enabled before calling
+             * <code>build</code>, {@link #penaltyLog} is implicitly
+             * set.
+             */
+            public VmPolicy build() {
+                // If there are detection bits set but no violation bits
+                // set, enable simple logging.
+                if (mMask != 0 &&
+                    (mMask & (PENALTY_DEATH | PENALTY_LOG |
+                              PENALTY_DROPBOX | PENALTY_DIALOG)) == 0) {
+                    penaltyLog();
+                }
+                return new VmPolicy(mMask);
+            }
+        }
+    }
 
     /**
      * Log of strict mode violation stack traces that have occurred
@@ -181,19 +497,21 @@
     };
 
     /**
-     * Sets the policy for what actions the current thread isn't
-     * expected to do, as well as the penalty if it does.
+     * Sets the policy for what actions on the current thread should
+     * be detected, as well as the penalty if such actions occur.
      *
-     * <p>Internally this sets a thread-local integer which is
+     * <p>Internally this sets a thread-local variable which is
      * propagated across cross-process IPC calls, meaning you can
      * catch violations when a system service or another process
      * accesses the disk or network on your behalf.
      *
-     * @param policyMask a bitmask of DISALLOW_* and PENALTY_* values,
-     *     e.g. {@link #DISALLOW_DISK_READ}, {@link #DISALLOW_DISK_WRITE},
-     *     {@link #DISALLOW_NETWORK}, {@link #PENALTY_LOG}.
+     * @param policy the policy to put into place
      */
-    public static void setThreadPolicy(final int policyMask) {
+    public static void setThreadPolicy(final ThreadPolicy policy) {
+        setThreadPolicyMask(policy.mask);
+    }
+
+    private static void setThreadPolicyMask(final int policyMask) {
         // In addition to the Java-level thread-local in Dalvik's
         // BlockGuard, we also need to keep a native thread-local in
         // Binder in order to propagate the value across Binder calls,
@@ -222,65 +540,76 @@
 
     private static class StrictModeNetworkViolation extends BlockGuard.BlockGuardPolicyException {
         public StrictModeNetworkViolation(int policyMask) {
-            super(policyMask, DISALLOW_NETWORK);
+            super(policyMask, DETECT_NETWORK);
         }
     }
 
     private static class StrictModeDiskReadViolation extends BlockGuard.BlockGuardPolicyException {
         public StrictModeDiskReadViolation(int policyMask) {
-            super(policyMask, DISALLOW_DISK_READ);
+            super(policyMask, DETECT_DISK_READ);
         }
     }
 
     private static class StrictModeDiskWriteViolation extends BlockGuard.BlockGuardPolicyException {
         public StrictModeDiskWriteViolation(int policyMask) {
-            super(policyMask, DISALLOW_DISK_WRITE);
+            super(policyMask, DETECT_DISK_WRITE);
         }
     }
 
     /**
      * Returns the bitmask of the current thread's policy.
      *
-     * @return the bitmask of all the DISALLOW_* and PENALTY_* bits currently enabled
+     * @return the bitmask of all the DETECT_* and PENALTY_* bits currently enabled
+     *
+     * @hide
      */
-    public static int getThreadPolicy() {
+    public static int getThreadPolicyMask() {
         return BlockGuard.getThreadPolicy().getPolicyMask();
     }
 
     /**
-     * A convenience wrapper around {@link #getThreadPolicy} and
-     * {@link #setThreadPolicy}.  Updates the current thread's policy
-     * mask to allow both reading &amp; writing to disk, returning the
-     * old policy so you can restore it at the end of a block.
-     *
-     * @return the old policy mask, to be passed to setThreadPolicy to
-     *         restore the policy.
+     * Returns the current thread's policy.
      */
-    public static int allowThreadDiskWrites() {
-        int oldPolicy = getThreadPolicy();
-        int newPolicy = oldPolicy & ~(DISALLOW_DISK_WRITE | DISALLOW_DISK_READ);
-        if (newPolicy != oldPolicy) {
-            setThreadPolicy(newPolicy);
-        }
-        return oldPolicy;
+    public static ThreadPolicy getThreadPolicy() {
+        return new ThreadPolicy(getThreadPolicyMask());
     }
 
     /**
-     * A convenience wrapper around {@link #getThreadPolicy} and
-     * {@link #setThreadPolicy}.  Updates the current thread's policy
-     * mask to allow reading from disk, returning the old
-     * policy so you can restore it at the end of a block.
+     * A convenience wrapper that takes the current
+     * {@link ThreadPolicy} from {@link #getThreadPolicy}, modifies it
+     * to permit both disk reads &amp; writes, and sets the new policy
+     * with {@link #setThreadPolicy}, returning the old policy so you
+     * can restore it at the end of a block.
      *
-     * @return the old policy mask, to be passed to setThreadPolicy to
+     * @return the old policy, to be passed to {@link #setThreadPolicy} to
+     *         restore the policy at the end of a block
+     */
+    public static ThreadPolicy allowThreadDiskWrites() {
+        int oldPolicyMask = getThreadPolicyMask();
+        int newPolicyMask = oldPolicyMask & ~(DETECT_DISK_WRITE | DETECT_DISK_READ);
+        if (newPolicyMask != oldPolicyMask) {
+            setThreadPolicyMask(newPolicyMask);
+        }
+        return new ThreadPolicy(oldPolicyMask);
+    }
+
+    /**
+     * A convenience wrapper that takes the current
+     * {@link ThreadPolicy} from {@link #getThreadPolicy}, modifies it
+     * to permit disk reads, and sets the new policy
+     * with {@link #setThreadPolicy}, returning the old policy so you
+     * can restore it at the end of a block.
+     *
+     * @return the old policy, to be passed to setThreadPolicy to
      *         restore the policy.
      */
-    public static int allowThreadDiskReads() {
-        int oldPolicy = getThreadPolicy();
-        int newPolicy = oldPolicy & ~(DISALLOW_DISK_READ);
-        if (newPolicy != oldPolicy) {
-            setThreadPolicy(newPolicy);
+    public static ThreadPolicy allowThreadDiskReads() {
+        int oldPolicyMask = getThreadPolicyMask();
+        int newPolicyMask = oldPolicyMask & ~(DETECT_DISK_READ);
+        if (newPolicyMask != oldPolicyMask) {
+            setThreadPolicyMask(newPolicyMask);
         }
-        return oldPolicy;
+        return new ThreadPolicy(oldPolicyMask);
     }
 
     /**
@@ -294,11 +623,14 @@
         if ("user".equals(Build.TYPE)) {
             return false;
         }
-        StrictMode.setThreadPolicy(
-            StrictMode.DISALLOW_DISK_WRITE |
-            StrictMode.DISALLOW_DISK_READ |
-            StrictMode.DISALLOW_NETWORK |
+        StrictMode.setThreadPolicyMask(
+            StrictMode.DETECT_DISK_WRITE |
+            StrictMode.DETECT_DISK_READ |
+            StrictMode.DETECT_NETWORK |
             StrictMode.PENALTY_DROPBOX);
+        sVmPolicyMask = StrictMode.DETECT_VM_CURSOR_LEAKS |
+                StrictMode.PENALTY_DROPBOX |
+                StrictMode.PENALTY_LOG;
         return true;
     }
 
@@ -372,7 +704,7 @@
 
         // Part of BlockGuard.Policy interface:
         public void onWriteToDisk() {
-            if ((mPolicyMask & DISALLOW_DISK_WRITE) == 0) {
+            if ((mPolicyMask & DETECT_DISK_WRITE) == 0) {
                 return;
             }
             BlockGuard.BlockGuardPolicyException e = new StrictModeDiskWriteViolation(mPolicyMask);
@@ -382,7 +714,7 @@
 
         // Part of BlockGuard.Policy interface:
         public void onReadFromDisk() {
-            if ((mPolicyMask & DISALLOW_DISK_READ) == 0) {
+            if ((mPolicyMask & DETECT_DISK_READ) == 0) {
                 return;
             }
             BlockGuard.BlockGuardPolicyException e = new StrictModeDiskReadViolation(mPolicyMask);
@@ -392,7 +724,7 @@
 
         // Part of BlockGuard.Policy interface:
         public void onNetwork() {
-            if ((mPolicyMask & DISALLOW_NETWORK) == 0) {
+            if ((mPolicyMask & DETECT_NETWORK) == 0) {
                 return;
             }
             BlockGuard.BlockGuardPolicyException e = new StrictModeNetworkViolation(mPolicyMask);
@@ -547,13 +879,13 @@
             if (violationMaskSubset != 0) {
                 int violationBit = parseViolationFromMessage(info.crashInfo.exceptionMessage);
                 violationMaskSubset |= violationBit;
-                final int savedPolicy = getThreadPolicy();
+                final int savedPolicyMask = getThreadPolicyMask();
                 try {
                     // First, remove any policy before we call into the Activity Manager,
                     // otherwise we'll infinite recurse as we try to log policy violations
                     // to disk, thus violating policy, thus requiring logging, etc...
                     // We restore the current policy below, in the finally block.
-                    setThreadPolicy(0);
+                    setThreadPolicyMask(0);
 
                     ActivityManagerNative.getDefault().handleApplicationStrictModeViolation(
                         RuntimeInit.getApplicationObject(),
@@ -563,7 +895,7 @@
                     Log.e(TAG, "RemoteException trying to handle StrictMode violation", e);
                 } finally {
                     // Restore the policy.
-                    setThreadPolicy(savedPolicy);
+                    setThreadPolicyMask(savedPolicyMask);
                 }
             }
 
@@ -592,6 +924,74 @@
     }
 
     /**
+     * Sets the policy for what actions in the VM process (on any
+     * thread) should be detected, as well as the penalty if such
+     * actions occur.
+     *
+     * @param policy the policy to put into place
+     */
+    public static void setVmPolicy(final VmPolicy policy) {
+        sVmPolicyMask = policy.mask;
+    }
+
+    /**
+     * Gets the current VM policy.
+     */
+    public static VmPolicy getVmPolicy() {
+        return new VmPolicy(sVmPolicyMask);
+    }
+
+    /**
+     * @hide
+     */
+    public static boolean vmSqliteObjectLeaksEnabled() {
+        return (sVmPolicyMask & DETECT_VM_CURSOR_LEAKS) != 0;
+    }
+
+    /**
+     * @hide
+     */
+    public static void onSqliteObjectLeaked(String message, Throwable originStack) {
+        if ((sVmPolicyMask & PENALTY_LOG) != 0) {
+            Log.e(TAG, message, originStack);
+        }
+
+        if ((sVmPolicyMask & PENALTY_DROPBOX) != 0) {
+            final ViolationInfo info = new ViolationInfo(originStack, sVmPolicyMask);
+
+            // The violationMask, passed to ActivityManager, is a
+            // subset of the original StrictMode policy bitmask, with
+            // only the bit violated and penalty bits to be executed
+            // by the ActivityManagerService remaining set.
+            int violationMaskSubset = PENALTY_DROPBOX | DETECT_VM_CURSOR_LEAKS;
+            final int savedPolicyMask = getThreadPolicyMask();
+            try {
+                // First, remove any policy before we call into the Activity Manager,
+                // otherwise we'll infinite recurse as we try to log policy violations
+                // to disk, thus violating policy, thus requiring logging, etc...
+                // We restore the current policy below, in the finally block.
+                setThreadPolicyMask(0);
+
+                ActivityManagerNative.getDefault().handleApplicationStrictModeViolation(
+                    RuntimeInit.getApplicationObject(),
+                    violationMaskSubset,
+                    info);
+            } catch (RemoteException e) {
+                Log.e(TAG, "RemoteException trying to handle StrictMode violation", e);
+            } finally {
+                // Restore the policy.
+                setThreadPolicyMask(savedPolicyMask);
+            }
+        }
+
+        if ((sVmPolicyMask & PENALTY_DEATH) != 0) {
+            System.err.println("StrictMode VmPolicy violation with POLICY_DEATH; shutting down.");
+            Process.killProcess(Process.myPid());
+            System.exit(10);
+        }
+    }
+
+    /**
      * Called from Parcel.writeNoException()
      */
     /* package */ static void writeGatheredViolationsToParcel(Parcel p) {
@@ -621,7 +1021,7 @@
         new LogStackTrace().printStackTrace(new PrintWriter(sw));
         String ourStack = sw.toString();
 
-        int policyMask = getThreadPolicy();
+        int policyMask = getThreadPolicyMask();
         boolean currentlyGathering = (policyMask & PENALTY_GATHER) != 0;
 
         int numViolations = p.readInt();
diff --git a/core/java/android/util/CalendarUtils.java b/core/java/android/util/CalendarUtils.java
index 3d340d9..1b2a894 100644
--- a/core/java/android/util/CalendarUtils.java
+++ b/core/java/android/util/CalendarUtils.java
@@ -146,6 +146,9 @@
          * This formats a date/time range using Calendar's time zone and the
          * local conventions for the region of the device.
          *
+         * If the {@link DateUtils#FORMAT_UTC} flag is used it will pass in
+         * the UTC time zone instead.
+         *
          * @param context the context is required only if the time is shown
          * @param startMillis the start time in UTC milliseconds
          * @param endMillis the end time in UTC milliseconds
@@ -156,10 +159,16 @@
         public String formatDateRange(Context context, long startMillis,
                 long endMillis, int flags) {
             String date;
+            String tz;
+            if ((flags & DateUtils.FORMAT_UTC) != 0) {
+                tz = Time.TIMEZONE_UTC;
+            } else {
+                tz = getTimeZone(context, null);
+            }
             synchronized (mSB) {
                 mSB.setLength(0);
                 date = DateUtils.formatDateRange(context, mF, startMillis, endMillis, flags,
-                        getTimeZone(context, null)).toString();
+                        tz).toString();
             }
             return date;
         }
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 76701a9..954b3e7 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -73,6 +73,7 @@
     public final static int FLAG_ALT_GR = 0x00000020;
     public final static int FLAG_MENU = 0x00000040;
     public final static int FLAG_LAUNCHER = 0x00000080;
+    public final static int FLAG_VIRTUAL = 0x00000100;
 
     public final static int FLAG_INJECTED = 0x01000000;
 
@@ -261,24 +262,6 @@
         boolean isDisplayedLw();
 
         /**
-         * Returns true if the window is both full screen and opaque.  Must be
-         * called with the window manager lock held.
-         * 
-         * @param width The width of the screen
-         * @param height The height of the screen 
-         * @param shownFrame If true, this is based on the actual shown frame of 
-         *                   the window (taking into account animations); if
-         *                   false, this is based on the currently requested
-         *                   frame, which any current animation will be moving
-         *                   towards.
-         * @param onlyOpaque If true, this will only pass if the window is
-         * also opaque.
-         * @return Returns true if the window is both full screen and opaque
-         */
-        public boolean fillsScreenLw(int width, int height, boolean shownFrame,
-                boolean onlyOpaque);
-
-        /**
          * Returns true if this window has been shown on screen at some time in 
          * the past.  Must be called with the window manager lock held.
          * 
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index f4d1b6e..d51c0b7 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -101,7 +101,6 @@
 	android_graphics_PixelFormat.cpp \
 	android/graphics/Picture.cpp \
 	android/graphics/PorterDuff.cpp \
-	android/graphics/BitmapRegionDecoder.cpp \
 	android/graphics/Rasterizer.cpp \
 	android/graphics/Region.cpp \
 	android/graphics/Shader.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index e5d5d8a..5f73443 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -53,7 +53,6 @@
 extern int register_android_os_Process(JNIEnv* env);
 extern int register_android_graphics_Bitmap(JNIEnv*);
 extern int register_android_graphics_BitmapFactory(JNIEnv*);
-extern int register_android_graphics_BitmapRegionDecoder(JNIEnv*);
 extern int register_android_graphics_Camera(JNIEnv* env);
 extern int register_android_graphics_Graphics(JNIEnv* env);
 extern int register_android_graphics_Interpolator(JNIEnv* env);
@@ -1220,7 +1219,6 @@
 
     REG_JNI(register_android_graphics_Bitmap),
     REG_JNI(register_android_graphics_BitmapFactory),
-    REG_JNI(register_android_graphics_BitmapRegionDecoder),
     REG_JNI(register_android_graphics_Camera),
     REG_JNI(register_android_graphics_Canvas),
     REG_JNI(register_android_graphics_ColorFilter),
diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp
deleted file mode 100644
index 4503852..0000000
--- a/core/jni/android/graphics/BitmapRegionDecoder.cpp
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "BitmapRegionDecoder"
-
-#include "SkBitmap.h"
-#include "SkImageEncoder.h"
-#include "GraphicsJNI.h"
-#include "SkUtils.h"
-#include "SkTemplates.h"
-#include "SkPixelRef.h"
-#include "SkStream.h"
-#include "BitmapFactory.h"
-#include "AutoDecodeCancel.h"
-#include "SkBitmapRegionDecoder.h"
-#include "CreateJavaOutputStreamAdaptor.h"
-#include "Utils.h"
-
-#include <android_runtime/AndroidRuntime.h>
-#include "android_util_Binder.h"
-#include "android_nio_utils.h"
-#include "CreateJavaOutputStreamAdaptor.h"
-
-#include <binder/Parcel.h>
-#include <jni.h>
-#include <utils/Asset.h>
-#include <sys/stat.h>
-
-static jclass gFileDescriptor_class;
-static jfieldID gFileDescriptor_descriptor;
-
-#if 0
-    #define TRACE_BITMAP(code)  code
-#else
-    #define TRACE_BITMAP(code)
-#endif
-
-using namespace android;
-
-static SkMemoryStream* buildSkMemoryStream(SkStream *stream) {
-    size_t bufferSize = 4096;
-    size_t streamLen = 0;
-    size_t len;
-    char* data = (char*)sk_malloc_throw(bufferSize);
-
-    while ((len = stream->read(data + streamLen,
-                    bufferSize - streamLen)) != 0) {
-        streamLen += len;
-        if (streamLen == bufferSize) {
-            bufferSize *= 2;
-            data = (char*)sk_realloc_throw(data, bufferSize);
-        }
-    }
-    data = (char*)sk_realloc_throw(data, streamLen);
-    SkMemoryStream* streamMem = new SkMemoryStream();
-    streamMem->setMemoryOwned(data, streamLen);
-    return streamMem;
-}
-
-static jobject doBuildTileIndex(JNIEnv* env, SkStream* stream) {
-    SkImageDecoder* decoder = SkImageDecoder::Factory(stream);
-    int width, height;
-    if (NULL == decoder) {
-        doThrowIOE(env, "Image format not supported");
-        return nullObjectReturn("SkImageDecoder::Factory returned null");
-    }
-
-    JavaPixelAllocator *javaAllocator = new JavaPixelAllocator(env, true);
-    decoder->setAllocator(javaAllocator);
-    JavaMemoryUsageReporter *javaMemoryReporter = new JavaMemoryUsageReporter(env);
-    decoder->setReporter(javaMemoryReporter);
-    javaAllocator->unref();
-    javaMemoryReporter->unref();
-
-    if (!decoder->buildTileIndex(stream, &width, &height)) {
-        char msg[100];
-        snprintf(msg, sizeof(msg), "Image failed to decode using %s decoder",
-                decoder->getFormatName());
-        doThrowIOE(env, msg);
-        return nullObjectReturn("decoder->buildTileIndex returned false");
-    }
-
-    SkBitmapRegionDecoder *bm = new SkBitmapRegionDecoder(decoder, width, height);
-
-    return GraphicsJNI::createBitmapRegionDecoder(env, bm);
-}
-
-static jobject nativeNewInstanceFromByteArray(JNIEnv* env, jobject, jbyteArray byteArray,
-                                     int offset, int length, jboolean isShareable) {
-    /*  If isShareable we could decide to just wrap the java array and
-        share it, but that means adding a globalref to the java array object
-        For now we just always copy the array's data if isShareable.
-     */
-    AutoJavaByteArray ar(env, byteArray);
-    SkStream* stream = new SkMemoryStream(ar.ptr() + offset, length, true);
-    return doBuildTileIndex(env, stream);
-}
-
-static jobject nativeNewInstanceFromFileDescriptor(JNIEnv* env, jobject clazz,
-                                          jobject fileDescriptor, jboolean isShareable) {
-    NPE_CHECK_RETURN_ZERO(env, fileDescriptor);
-
-    jint descriptor = env->GetIntField(fileDescriptor,
-                                       gFileDescriptor_descriptor);
-    SkStream *stream = NULL;
-    struct stat fdStat;
-    int newFD;
-    if (fstat(descriptor, &fdStat) == -1) {
-        doThrowIOE(env, "broken file descriptor");
-        return nullObjectReturn("fstat return -1");
-    }
-
-    if (isShareable &&
-            S_ISREG(fdStat.st_mode) &&
-            (newFD = ::dup(descriptor)) != -1) {
-        SkFDStream* fdStream = new SkFDStream(newFD, true);
-        if (!fdStream->isValid()) {
-            fdStream->unref();
-            return NULL;
-        }
-        stream = fdStream;
-    } else {
-        SkFDStream* fdStream = new SkFDStream(descriptor, false);
-        if (!fdStream->isValid()) {
-            fdStream->unref();
-            return NULL;
-        }
-        stream = buildSkMemoryStream(fdStream);
-        fdStream->unref();
-    }
-
-    /* Restore our offset when we leave, so we can be called more than once
-       with the same descriptor. This is only required if we didn't dup the
-       file descriptor, but it is OK to do it all the time.
-    */
-    AutoFDSeek as(descriptor);
-
-    return doBuildTileIndex(env, stream);
-}
-
-static jobject nativeNewInstanceFromStream(JNIEnv* env, jobject clazz,
-                                  jobject is,       // InputStream
-                                  jbyteArray storage, // byte[]
-                                  jboolean isShareable) {
-    jobject largeBitmap = NULL;
-    SkStream* stream = CreateJavaInputStreamAdaptor(env, is, storage, 1024);
-
-    if (stream) {
-        // for now we don't allow shareable with java inputstreams
-        SkMemoryStream *mStream = buildSkMemoryStream(stream);
-        largeBitmap = doBuildTileIndex(env, mStream);
-        stream->unref();
-    }
-    return largeBitmap;
-}
-
-static jobject nativeNewInstanceFromAsset(JNIEnv* env, jobject clazz,
-                                 jint native_asset, // Asset
-                                 jboolean isShareable) {
-    SkStream* stream, *assStream;
-    Asset* asset = reinterpret_cast<Asset*>(native_asset);
-    assStream = new AssetStreamAdaptor(asset);
-    stream = buildSkMemoryStream(assStream);
-    assStream->unref();
-    return doBuildTileIndex(env, stream);
-}
-
-/*
- * nine patch not supported
- *
- * purgeable not supported
- * reportSizeToVM not supported
- */
-static jobject nativeDecodeRegion(JNIEnv* env, jobject, SkBitmapRegionDecoder *brd,
-        int start_x, int start_y, int width, int height, jobject options) {
-    SkImageDecoder *decoder = brd->getDecoder();
-    int sampleSize = 1;
-    SkBitmap::Config prefConfig = SkBitmap::kNo_Config;
-    bool doDither = true;
-
-    if (NULL != options) {
-        sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID);
-        // initialize these, in case we fail later on
-        env->SetIntField(options, gOptions_widthFieldID, -1);
-        env->SetIntField(options, gOptions_heightFieldID, -1);
-        env->SetObjectField(options, gOptions_mimeFieldID, 0);
-
-        jobject jconfig = env->GetObjectField(options, gOptions_configFieldID);
-        prefConfig = GraphicsJNI::getNativeBitmapConfig(env, jconfig);
-        doDither = env->GetBooleanField(options, gOptions_ditherFieldID);
-    }
-
-    decoder->setDitherImage(doDither);
-    SkBitmap*           bitmap = new SkBitmap;
-    SkAutoTDelete<SkBitmap>       adb(bitmap);
-    AutoDecoderCancel   adc(options, decoder);
-
-    // To fix the race condition in case "requestCancelDecode"
-    // happens earlier than AutoDecoderCancel object is added
-    // to the gAutoDecoderCancelMutex linked list.
-    if (NULL != options && env->GetBooleanField(options, gOptions_mCancelID)) {
-        return nullObjectReturn("gOptions_mCancelID");;
-    }
-
-    SkIRect region;
-    region.fLeft = start_x;
-    region.fTop = start_y;
-    region.fRight = start_x + width;
-    region.fBottom = start_y + height;
-
-    if (!brd->decodeRegion(bitmap, region, prefConfig, sampleSize)) {
-        return nullObjectReturn("decoder->decodeRegion returned false");
-    }
-
-    // update options (if any)
-    if (NULL != options) {
-        env->SetIntField(options, gOptions_widthFieldID, bitmap->width());
-        env->SetIntField(options, gOptions_heightFieldID, bitmap->height());
-        // TODO: set the mimeType field with the data from the codec.
-        // but how to reuse a set of strings, rather than allocating new one
-        // each time?
-        env->SetObjectField(options, gOptions_mimeFieldID,
-                            getMimeTypeString(env, decoder->getFormat()));
-    }
-
-    // detach bitmap from its autotdeleter, since we want to own it now
-    adb.detach();
-
-    SkPixelRef* pr;
-    pr = bitmap->pixelRef();
-    // promise we will never change our pixels (great for sharing and pictures)
-    pr->setImmutable();
-    // now create the java bitmap
-    return GraphicsJNI::createBitmap(env, bitmap, false, NULL);
-}
-
-static int nativeGetHeight(JNIEnv* env, jobject, SkBitmapRegionDecoder *brd) {
-    return brd->getHeight();
-}
-
-static int nativeGetWidth(JNIEnv* env, jobject, SkBitmapRegionDecoder *brd) {
-    return brd->getWidth();
-}
-
-static void nativeClean(JNIEnv* env, jobject, SkBitmapRegionDecoder *brd) {
-    delete brd;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-#include <android_runtime/AndroidRuntime.h>
-
-static JNINativeMethod gBitmapRegionDecoderMethods[] = {
-    {   "nativeDecodeRegion",
-        "(IIIIILandroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
-        (void*)nativeDecodeRegion},
-
-    {   "nativeGetHeight", "(I)I", (void*)nativeGetHeight},
-
-    {   "nativeGetWidth", "(I)I", (void*)nativeGetWidth},
-
-    {   "nativeClean", "(I)V", (void*)nativeClean},
-
-    {   "nativeNewInstance",
-        "([BIIZ)Landroid/graphics/BitmapRegionDecoder;",
-        (void*)nativeNewInstanceFromByteArray
-    },
-
-    {   "nativeNewInstance",
-        "(Ljava/io/InputStream;[BZ)Landroid/graphics/BitmapRegionDecoder;",
-        (void*)nativeNewInstanceFromStream
-    },
-
-    {   "nativeNewInstance",
-        "(Ljava/io/FileDescriptor;Z)Landroid/graphics/BitmapRegionDecoder;",
-        (void*)nativeNewInstanceFromFileDescriptor
-    },
-
-    {   "nativeNewInstance",
-        "(IZ)Landroid/graphics/BitmapRegionDecoder;",
-        (void*)nativeNewInstanceFromAsset
-    },
-};
-
-#define kClassPathName  "android/graphics/BitmapRegionDecoder"
-
-int register_android_graphics_BitmapRegionDecoder(JNIEnv* env);
-int register_android_graphics_BitmapRegionDecoder(JNIEnv* env)
-{
-    return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
-            gBitmapRegionDecoderMethods, SK_ARRAY_COUNT(gBitmapRegionDecoderMethods));
-}
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 1ebe14b..195f4d2 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -168,9 +168,6 @@
 static jclass   gBitmapConfig_class;
 static jfieldID gBitmapConfig_nativeInstanceID;
 
-static jclass   gBitmapRegionDecoder_class;
-static jmethodID gBitmapRegionDecoder_constructorMethodID;
-
 static jclass   gCanvas_class;
 static jfieldID gCanvas_nativeInstanceID;
 
@@ -377,24 +374,6 @@
     return obj;
 }
 
-jobject GraphicsJNI::createBitmapRegionDecoder(JNIEnv* env, SkBitmapRegionDecoder* bitmap)
-{
-    SkASSERT(bitmap != NULL);
-
-    jobject obj = env->AllocObject(gBitmapRegionDecoder_class);
-    if (hasException(env)) {
-        obj = NULL;
-        return obj;
-    }
-    if (obj) {
-        env->CallVoidMethod(obj, gBitmapRegionDecoder_constructorMethodID, (jint)bitmap);
-        if (hasException(env)) {
-            obj = NULL;
-        }
-    }
-    return obj;
-}
-
 jobject GraphicsJNI::createRegion(JNIEnv* env, SkRegion* region)
 {
     SkASSERT(region != NULL);
@@ -613,9 +592,6 @@
     gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>",
                                             "(IZ[BI)V");
 
-    gBitmapRegionDecoder_class = make_globalref(env, "android/graphics/BitmapRegionDecoder");
-    gBitmapRegionDecoder_constructorMethodID = env->GetMethodID(gBitmapRegionDecoder_class, "<init>", "(I)V");
-
     gBitmapConfig_class = make_globalref(env, "android/graphics/Bitmap$Config");
     gBitmapConfig_nativeInstanceID = getFieldIDCheck(env, gBitmapConfig_class,
                                                      "nativeInt", "I");    
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index d0f9125..1f94418 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -4,7 +4,6 @@
 #include "SkPoint.h"
 #include "SkRect.h"
 #include "SkBitmap.h"
-#include "../images/SkBitmapRegionDecoder.h"
 #include "../images/SkImageDecoder.h"
 #include <jni.h>
 
@@ -56,8 +55,6 @@
     
     static jobject createRegion(JNIEnv* env, SkRegion* region);
 
-    static jobject createBitmapRegionDecoder(JNIEnv* env, SkBitmapRegionDecoder* bitmap);
-
     /** Set a pixelref for the bitmap (needs setConfig to already be called)
         Returns true on success. If it returns false, then it failed, and the
         appropriate exception will have been raised.
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 4cdf4f6f..02524bf 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -244,6 +244,7 @@
         <item name="android:clickable">true</item>
         <item name="android:textAppearance">?android:attr/textAppearanceSmallInverse</item>
         <item name="android:textColor">@android:color/primary_text_light</item>
+        <item name="android:textStyle">bold</item>
         <item name="android:gravity">center_vertical|center_horizontal</item>
     </style>
 
diff --git a/docs/html/resources/dashboard/platform-versions.jd b/docs/html/resources/dashboard/platform-versions.jd
index 92d4e15..3b4ccb0e 100644
--- a/docs/html/resources/dashboard/platform-versions.jd
+++ b/docs/html/resources/dashboard/platform-versions.jd
@@ -52,7 +52,7 @@
 <div class="dashboard-panel">
 
 <img alt="" height="250" width="460"
-src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:12.0,17.5,0.1,41.7,28.7&chl=
+src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:9.7,16.4,0.1,40.4,33.4&chl=
 Android%201.5|Android%201.6|Other*|Android%202.1|Android%202.2&chco=c4df9b,
 6fad0c" />
 
@@ -62,13 +62,13 @@
   <th>API Level</th>
   <th>Distribution</th>
 </tr>
-<tr><td>Android 1.5</td><td>3</td><td>12.0%</td></tr>
-<tr><td>Android 1.6</td><td>4</td><td>17.5%</td></tr>
-<tr><td>Android 2.1</td><td>7</td><td>41.7%</td></tr>
-<tr><td>Android 2.2</td><td>8</td><td>28.7%</td></tr>
+<tr><td>Android 1.5</td><td>3</td><td>9.7%</td></tr>
+<tr><td>Android 1.6</td><td>4</td><td>16.4%</td></tr>
+<tr><td>Android 2.1</td><td>7</td><td>40.4%</td></tr>
+<tr><td>Android 2.2</td><td>8</td><td>33.4%</td></tr>
 </table>
 
-<p><em>Data collected during two weeks ending on September 1, 2010</em></p>
+<p><em>Data collected during two weeks ending on October 1, 2010</em></p>
 <p style="font-size:.9em">* <em>Other: 0.1% of devices running obsolete versions</em></p>
 
 </div><!-- end dashboard-panel -->
@@ -96,19 +96,19 @@
 <div class="dashboard-panel">
 
 <img alt="" height="250" width="660" style="padding:5px;background:#fff"
-src="http://chart.apis.google.com/chart?&cht=lc&chs=660x250&chxt=x,y,r&chxr=0,0,12|1,0,100|2,0,100&
-chxl=0%3A%7C2010/03/01%7C03/15%7C04/01%7C04/15%7C05/01%7C05/15%7C06/01%7C06/15%7C07/01%7C07/15%7C08/
-01%7C08/15%7C2010/09/01%7C1%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25%7C2%3A%7C0%25%7C25%25%7C50%25
-%7C75%25%7C100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10,11,12&chxtc=0,5&chd=t:99.4,99.5,99.6,99.6,99.6,99.7,
-100.6,101.1,99.9,100.0,100.0,99.8,99.9|61.6,60.6,61.5,61.7,62.3,63.5,73.0,76.4,78.6,81.1,84.5,86.6,
-88.0|24.3,25.4,29.4,30.2,32.7,35.3,46.2,51.3,55.1,59.0,64.1,68.2,70.4|0.0,0.0,4.0,28.3,32.0,34.9,45.
-9,51.0,54.9,58.8,64.0,68.1,70.3|0.0,0.0,0.0,0.0,0.0,0.0,0.8,1.2,1.8,3.3,4.3,11.3,27.8&chm=tAndroid%
-201.5,7caa36,0,0,15,,t::-5|b,c3df9b,0,1,0|tAndroid%201.6,638d23,1,0,15,,t::-5|b,b0db6e,1,2,0|
-tAndroid%202.0.1,496c13,2,0,15,,t::-5|b,9ddb3d,2,3,0|tAndroid%202.1,2f4708,3,3,15,,t::-5|b,89cf19,3,
-4,0|tAndroid%202.2,131d02,4,11,15,,t::-5|B,6fad0c,4,5,0&chg=7,25&chdl=Android%201.5|Android%201.6|
-Android%202.0.1|Android%202.1|Android%202.2&chco=add274,9ad145,84c323,6ba213,507d08" />
+src="http://chart.apis.google.com/chart?cht=lc&chs=660x250&chxt=x,y,r&chxr=0,0,12|1,0,100|2,0,100&
+chxl=0:|2010/04/01|04/15|05/01|05/15|06/01|06/15|07/01|07/15|08/01|08/15|09/01|09/15|2010/10/01|1:|0
+%25|25%25|50%25|75%25|100%25|2:|0%25|25%25|50%25|75%25|100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10,11,12&
+chxtc=0,5&chd=t:99.6,99.6,99.6,99.7,100.6,101.1,99.9,100.0,100.0,99.8,99.9,100.0,100.0|61.5,61.7,62.
+3,63.5,73.0,76.4,78.6,81.1,84.5,86.6,88.0,89.3,90.3|29.4,30.2,32.7,35.3,46.2,51.3,55.1,59.0,64.1,68.
+2,70.4,72.2,73.9|4.0,28.3,32.0,34.9,45.9,51.0,54.9,58.8,64.0,68.1,70.3,72.1,73.8|0.0,0.0,0.0,0.0,0.8
+,1.2,1.8,3.3,4.3,11.3,27.8,32.1,33.4&chm=tAndroid+1.5,7caa36,0,0,15,,t::-5|b,c3df9b,0,1,0|tAndroid+1
+.6,638d23,1,0,15,,t::-5|b,b0db6e,1,2,0|tAndroid+2.0.1,496c13,2,0,15,,t::-5|b,9ddb3d,2,3,0|tAndroid+2
+.1,2f4708,3,1,15,,t:-30:-40|b,89cf19,3,4,0|tAndroid+2.2,131d02,4,9,15,,t::-5|B,6fad0c,4,5,0&chg=7,25
+&chdl=Android+1.5|Android+1.6|Android+2.0.1|Android+2.1|Android+2.2&chco=add274,9ad145,84c323,6ba213
+,507d08" />
 
-<p><em>Last historical dataset collected during two weeks ending on September 1, 2010</em></p>
+<p><em>Last historical dataset collected during two weeks ending on October 1, 2010</em></p>
 
 
 </div><!-- end dashboard-panel -->
diff --git a/graphics/java/android/graphics/BitmapRegionDecoder.java b/graphics/java/android/graphics/BitmapRegionDecoder.java
deleted file mode 100644
index 454eb4a..0000000
--- a/graphics/java/android/graphics/BitmapRegionDecoder.java
+++ /dev/null
@@ -1,263 +0,0 @@
-/* Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.graphics;
-
-import android.content.res.AssetManager;
-
-import java.io.BufferedInputStream;
-import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * BitmapRegionDecoder can be used to decode a rectangle region from an image.
- * BitmapRegionDecoder is particularly useful when an original image is large and
- * you only need parts of the image.
- *
- * <p>To create a BitmapRegionDecoder, call newInstance(...).
- * Given a BitmapRegionDecoder, users can call decodeRegion() repeatedly
- * to get a decoded Bitmap of the specified region.
- *
- */
-public final class BitmapRegionDecoder {
-    private int mNativeBitmapRegionDecoder;
-    private boolean mRecycled;
-
-    /**
-     * Create a BitmapRegionDecoder from the specified byte array.
-     * Currently only the Jpeg format is supported.
-     *
-     * @param data byte array of compressed image data.
-     * @param offset offset into data for where the decoder should begin
-     *               parsing.
-     * @param length the number of bytes, beginning at offset, to parse
-     * @param isShareable If this is true, then the BitmapRegionDecoder may keep a
-     *                    shallow reference to the input. If this is false,
-     *                    then the BitmapRegionDecoder will explicitly make a copy of the
-     *                    input data, and keep that. Even if sharing is allowed,
-     *                    the implementation may still decide to make a deep
-     *                    copy of the input data. If an image is progressively encoded,
-     *                    allowing sharing may degrade the decoding speed.
-     * @return BitmapRegionDecoder, or null if the image data could not be decoded.
-     * @throws IOException if the image format is not supported or can not be decoded.
-     */
-    public static BitmapRegionDecoder newInstance(byte[] data,
-            int offset, int length, boolean isShareable) throws IOException {
-        if ((offset | length) < 0 || data.length < offset + length) {
-            throw new ArrayIndexOutOfBoundsException();
-        }
-        return nativeNewInstance(data, offset, length, isShareable);
-    }
-
-    /**
-     * Create a BitmapRegionDecoder from the file descriptor.
-     * The position within the descriptor will not be changed when
-     * this returns, so the descriptor can be used again as is.
-     * Currently only the Jpeg format is supported.
-     *
-     * @param fd The file descriptor containing the data to decode
-     * @param isShareable If this is true, then the BitmapRegionDecoder may keep a
-     *                    shallow reference to the input. If this is false,
-     *                    then the BitmapRegionDecoder will explicitly make a copy of the
-     *                    input data, and keep that. Even if sharing is allowed,
-     *                    the implementation may still decide to make a deep
-     *                    copy of the input data. If an image is progressively encoded,
-     *                    allowing sharing may degrade the decoding speed.
-     * @return BitmapRegionDecoder, or null if the image data could not be decoded.
-     * @throws IOException if the image format is not supported or can not be decoded.
-     */
-    public static BitmapRegionDecoder newInstance(
-            FileDescriptor fd, boolean isShareable) throws IOException {
-        return nativeNewInstance(fd, isShareable);
-    }
-
-    /**
-     * Create a BitmapRegionDecoder from an input stream.
-     * The stream's position will be where ever it was after the encoded data
-     * was read.
-     * Currently only the Jpeg format is supported.
-     *
-     * @param is The input stream that holds the raw data to be decoded into a
-     *           BitmapRegionDecoder.
-     * @param isShareable If this is true, then the BitmapRegionDecoder may keep a
-     *                    shallow reference to the input. If this is false,
-     *                    then the BitmapRegionDecoder will explicitly make a copy of the
-     *                    input data, and keep that. Even if sharing is allowed,
-     *                    the implementation may still decide to make a deep
-     *                    copy of the input data. If an image is progressively encoded,
-     *                    allowing sharing may degrade the decoding speed.
-     * @return BitmapRegionDecoder, or null if the image data could not be decoded.
-     * @throws IOException if the image format is not supported or can not be decoded.
-     */
-    public static BitmapRegionDecoder newInstance(InputStream is,
-            boolean isShareable) throws IOException {
-        // we need mark/reset to work properly in JNI
-
-        if (!is.markSupported()) {
-            is = new BufferedInputStream(is, 16 * 1024);
-        }
-
-        if (is instanceof AssetManager.AssetInputStream) {
-            return nativeNewInstance(
-                    ((AssetManager.AssetInputStream) is).getAssetInt(),
-                    isShareable);
-        } else {
-            // pass some temp storage down to the native code. 1024 is made up,
-            // but should be large enough to avoid too many small calls back
-            // into is.read(...).
-            byte [] tempStorage = new byte[16 * 1024];
-            return nativeNewInstance(is, tempStorage, isShareable);
-        }
-    }
-
-    /**
-     * Create a BitmapRegionDecoder from a file path.
-     * Currently only the Jpeg format is supported.
-     *
-     * @param pathName complete path name for the file to be decoded.
-     * @param isShareable If this is true, then the BitmapRegionDecoder may keep a
-     *                    shallow reference to the input. If this is false,
-     *                    then the BitmapRegionDecoder will explicitly make a copy of the
-     *                    input data, and keep that. Even if sharing is allowed,
-     *                    the implementation may still decide to make a deep
-     *                    copy of the input data. If an image is progressively encoded,
-     *                    allowing sharing may degrade the decoding speed.
-     * @return BitmapRegionDecoder, or null if the image data could not be decoded.
-     * @throws IOException if the image format is not supported or can not be decoded.
-     */
-    public static BitmapRegionDecoder newInstance(String pathName,
-            boolean isShareable) throws IOException {
-        BitmapRegionDecoder decoder = null;
-        InputStream stream = null;
-
-        try {
-            stream = new FileInputStream(pathName);
-            decoder = newInstance(stream, isShareable);
-        } finally {
-            if (stream != null) {
-                try {
-                    stream.close();
-                } catch (IOException e) {
-                    // do nothing here
-                }
-            }
-        }
-        return decoder;
-    }
-
-    /*  Private constructor that must receive an already allocated native
-        region decoder int (pointer).
-
-        This can be called from JNI code.
-    */
-    private BitmapRegionDecoder(int decoder) {
-        mNativeBitmapRegionDecoder = decoder;
-        mRecycled = false;
-    }
-
-    /**
-     * Decodes a rectangle region in the image specified by rect.
-     *
-     * @param rect The rectangle that specified the region to be decode.
-     * @param options null-ok; Options that control downsampling.
-     *             inPurgeable is not supported.
-     * @return The decoded bitmap, or null if the image data could not be
-     *         decoded.
-     */
-    public Bitmap decodeRegion(Rect rect, BitmapFactory.Options options) {
-        checkRecycled("decodeRegion called on recycled region decoder");
-        if (rect.left < 0 || rect.top < 0 || rect.right > getWidth()
-                || rect.bottom > getHeight())
-            throw new IllegalArgumentException("rectangle is not inside the image");
-        return nativeDecodeRegion(mNativeBitmapRegionDecoder, rect.left, rect.top,
-                rect.right - rect.left, rect.bottom - rect.top, options);
-    }
-
-    /** Returns the original image's width */
-    public int getWidth() {
-        checkRecycled("getWidth called on recycled region decoder");
-        return nativeGetWidth(mNativeBitmapRegionDecoder);
-    }
-
-    /** Returns the original image's height */
-    public int getHeight() {
-        checkRecycled("getHeight called on recycled region decoder");
-        return nativeGetHeight(mNativeBitmapRegionDecoder);
-    }
-
-    /**
-     * Frees up the memory associated with this region decoder, and mark the
-     * region decoder as "dead", meaning it will throw an exception if decodeRegion(),
-     * getWidth() or getHeight() is called.
-     *
-     * <p>This operation cannot be reversed, so it should only be called if you are
-     * sure there are no further uses for the region decoder. This is an advanced call,
-     * and normally need not be called, since the normal GC process will free up this
-     * memory when there are no more references to this region decoder.
-     */
-    public void recycle() {
-        if (!mRecycled) {
-            nativeClean(mNativeBitmapRegionDecoder);
-            mRecycled = true;
-        }
-    }
-
-    /**
-     * Returns true if this region decoder has been recycled.
-     * If so, then it is an error to try use its method.
-     *
-     * @return true if the region decoder has been recycled
-     */
-    public final boolean isRecycled() {
-        return mRecycled;
-    }
-
-    /**
-     * Called by methods that want to throw an exception if the region decoder
-     * has already been recycled.
-     */
-    private void checkRecycled(String errorMessage) {
-        if (mRecycled) {
-            throw new IllegalStateException(errorMessage);
-        }
-    }
-
-    @Override
-    protected void finalize() throws Throwable {
-        try {
-            recycle();
-        } finally {
-            super.finalize();
-        }
-    }
-
-    private static native Bitmap nativeDecodeRegion(int lbm,
-            int start_x, int start_y, int width, int height,
-            BitmapFactory.Options options);
-    private static native int nativeGetWidth(int lbm);
-    private static native int nativeGetHeight(int lbm);
-    private static native void nativeClean(int lbm);
-
-    private static native BitmapRegionDecoder nativeNewInstance(
-            byte[] data, int offset, int length, boolean isShareable);
-    private static native BitmapRegionDecoder nativeNewInstance(
-            FileDescriptor fd, boolean isShareable);
-    private static native BitmapRegionDecoder nativeNewInstance(
-            InputStream is, byte[] storage, boolean isShareable);
-    private static native BitmapRegionDecoder nativeNewInstance(
-            int asset, boolean isShareable);
-}
diff --git a/include/ui/Input.h b/include/ui/Input.h
index 21baf32..ee40b85 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -73,7 +73,8 @@
  * policy decisions such as waking from device sleep.
  */
 enum {
-    /* These flags originate in RawEvents and are generally set in the key map. */
+    /* These flags originate in RawEvents and are generally set in the key map.
+     * See also labels for policy flags in KeycodeLabels.h. */
 
     POLICY_FLAG_WAKE = 0x00000001,
     POLICY_FLAG_WAKE_DROPPED = 0x00000002,
@@ -83,6 +84,7 @@
     POLICY_FLAG_ALT_GR = 0x00000020,
     POLICY_FLAG_MENU = 0x00000040,
     POLICY_FLAG_LAUNCHER = 0x00000080,
+    POLICY_FLAG_VIRTUAL = 0x00000100,
 
     POLICY_FLAG_RAW_MASK = 0x0000ffff,
 
diff --git a/include/ui/InputReader.h b/include/ui/InputReader.h
index d3fbaf7..2209cb8 100644
--- a/include/ui/InputReader.h
+++ b/include/ui/InputReader.h
@@ -103,10 +103,6 @@
     virtual bool getDisplayInfo(int32_t displayId,
             int32_t* width, int32_t* height, int32_t* orientation) = 0;
 
-    /* Provides feedback for a virtual key down.
-     */
-    virtual void virtualKeyDownFeedback() = 0;
-
     /* Intercepts a key event.
      * The policy can use this method as an opportunity to perform power management functions
      * and early event preprocessing such as updating policy flags.
diff --git a/include/ui/KeycodeLabels.h b/include/ui/KeycodeLabels.h
index c8d6ffc..f71d9cd 100755
--- a/include/ui/KeycodeLabels.h
+++ b/include/ui/KeycodeLabels.h
@@ -142,6 +142,7 @@
     { NULL, 0 }
 };
 
+// See also policy flags in Input.h.
 static const KeycodeLabel FLAGS[] = {
     { "WAKE", 0x00000001 },
     { "WAKE_DROPPED", 0x00000002 },
@@ -151,6 +152,7 @@
     { "ALT_GR", 0x00000020 },
     { "MENU", 0x00000040 },
     { "LAUNCHER", 0x00000080 },
+    { "VIRTUAL", 0x00000100 },
     { NULL, 0 }
 };
 
diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp
index 1d35e10..825febc 100644
--- a/libs/ui/InputReader.cpp
+++ b/libs/ui/InputReader.cpp
@@ -993,7 +993,10 @@
     int32_t keyEventAction = down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP;
     int32_t keyEventFlags = AKEY_EVENT_FLAG_FROM_SYSTEM;
     if (policyFlags & POLICY_FLAG_WOKE_HERE) {
-        keyEventFlags = keyEventFlags | AKEY_EVENT_FLAG_WOKE_HERE;
+        keyEventFlags |= AKEY_EVENT_FLAG_WOKE_HERE;
+    }
+    if (policyFlags & POLICY_FLAG_VIRTUAL) {
+        keyEventFlags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY;
     }
 
     getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags,
@@ -2162,10 +2165,7 @@
         int32_t keyCode, int32_t scanCode, nsecs_t downTime) {
     int32_t metaState = mContext->getGlobalMetaState();
 
-    if (keyEventAction == AKEY_EVENT_ACTION_DOWN) {
-        getPolicy()->virtualKeyDownFeedback();
-    }
-
+    policyFlags |= POLICY_FLAG_VIRTUAL;
     int32_t policyActions = getPolicy()->interceptKey(when, getDeviceId(),
             keyEventAction == AKEY_EVENT_ACTION_DOWN, keyCode, scanCode, policyFlags);
 
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 12022bd..c955ac3 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -273,20 +273,6 @@
 
 status_t AwesomePlayer::setDataSource(
         int fd, int64_t offset, int64_t length) {
-#if 0
-    // return setDataSource("httplive://qthttp.apple.com.edgesuite.net/1009qpeijrfn/sl.m3u8");
-    return setDataSource("httplive://qthttp.apple.com.edgesuite.net/1009qpeijrfn/0440.m3u8");
-    // return setDataSource("httplive://qthttp.apple.com.edgesuite.net/1009qpeijrfn/0640.m3u8");
-    // return setDataSource("httplive://qthttp.apple.com.edgesuite.net/1009qpeijrfn/1240_vod.m3u8");
-    // return setDataSource("httplive://iphoned5.akamai.com.edgesuite.net/mhbarron/nasatv/nasatv_96.m3u8");
-    // return setDataSource("httplive://iphoned5.akamai.com.edgesuite.net/mhbarron/nasatv/nasatv_1500.m3u8");
-    // return setDataSource("httplive://iphone.video.hsn.com/iPhone_high.m3u8");
-    // return setDataSource("httplive://iphoned5.akamai.com.edgesuite.net/mhbarron/iphonewebcast/webcast090209_all/webcast090209_all.m3u8");
-    // return setDataSource("httplive://qthttp.akamai.com.edgesuite.net/iphone_demo/Video_Content/usat/tt_062209_iphone/hi/prog_index.m3u8");
-    // return setDataSource("httplive://qthttp.akamai.com.edgesuite.net/iphone_demo/Video_Content/usat/tt_googmaps/hi/prog_index.m3u8");
-    // return setDataSource("httplive://qthttp.akamai.com.edgesuite.net/iphone_demo/Video_Content/mtv/ni_spo_25a_rt74137_clip_syn/hi/prog_index.m3u8");
-#endif
-
     Mutex::Autolock autoLock(mLock);
 
     reset_l();
diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/avc_utils.cpp
index 511ae12..a8f1104 100644
--- a/media/libstagefright/avc_utils.cpp
+++ b/media/libstagefright/avc_utils.cpp
@@ -21,7 +21,7 @@
 
 namespace android {
 
-static unsigned parseUE(ABitReader *br) {
+unsigned parseUE(ABitReader *br) {
     unsigned numZeroes = 0;
     while (br->getBits(1) == 0) {
         ++numZeroes;
diff --git a/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp b/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp
index 3c0b736..868c514 100644
--- a/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp
+++ b/media/libstagefright/codecs/avc/dec/AVCDecoder.cpp
@@ -31,6 +31,7 @@
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/Utils.h>
+#include <media/stagefright/foundation/hexdump.h>
 
 namespace android {
 
diff --git a/media/libstagefright/httplive/LiveSource.cpp b/media/libstagefright/httplive/LiveSource.cpp
index 001afc4..9103927 100644
--- a/media/libstagefright/httplive/LiveSource.cpp
+++ b/media/libstagefright/httplive/LiveSource.cpp
@@ -93,7 +93,7 @@
         }
 
         if (mLastFetchTimeUs < 0) {
-            mPlaylistIndex = mPlaylist->size() / 2;
+            mPlaylistIndex = 0;
         } else {
             if (nextSequenceNumber < mFirstItemSequenceNumber
                     || nextSequenceNumber
diff --git a/media/libstagefright/include/avc_utils.h b/media/libstagefright/include/avc_utils.h
index cc405b5..6602852 100644
--- a/media/libstagefright/include/avc_utils.h
+++ b/media/libstagefright/include/avc_utils.h
@@ -22,9 +22,13 @@
 
 namespace android {
 
+struct ABitReader;
+
 void FindAVCDimensions(
         const sp<ABuffer> &seqParamSet, int32_t *width, int32_t *height);
 
+unsigned parseUE(ABitReader *br);
+
 }  // namespace android
 
 #endif  // AVC_UTILS_H_
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index 47cca80..bcaab9f 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -21,6 +21,7 @@
 #include "ATSParser.h"
 
 #include "AnotherPacketSource.h"
+#include "ESQueue.h"
 #include "include/avc_utils.h"
 
 #include <media/stagefright/foundation/ABitReader.h>
@@ -79,6 +80,8 @@
     sp<AnotherPacketSource> mSource;
     bool mPayloadStarted;
 
+    ElementaryStreamQueue mQueue;
+
     void flush();
     void parsePES(ABitReader *br);
 
@@ -232,7 +235,9 @@
     : mElementaryPID(elementaryPID),
       mStreamType(streamType),
       mBuffer(new ABuffer(128 * 1024)),
-      mPayloadStarted(false) {
+      mPayloadStarted(false),
+      mQueue(streamType == 0x1b
+              ? ElementaryStreamQueue::H264 : ElementaryStreamQueue::AAC) {
     mBuffer->setRange(0, 0);
 }
 
@@ -433,373 +438,31 @@
     mBuffer->setRange(0, 0);
 }
 
-static sp<ABuffer> FindNAL(
-        const uint8_t *data, size_t size, unsigned nalType,
-        size_t *stopOffset) {
-    bool foundStart = false;
-    size_t startOffset = 0;
-
-    size_t offset = 0;
-    for (;;) {
-        while (offset + 3 < size
-                && memcmp("\x00\x00\x00\x01", &data[offset], 4)) {
-            ++offset;
-        }
-
-        if (foundStart) {
-            size_t nalSize;
-            if (offset + 3 >= size) {
-                nalSize = size - startOffset;
-            } else {
-                nalSize = offset - startOffset;
-            }
-
-            sp<ABuffer> nal = new ABuffer(nalSize);
-            memcpy(nal->data(), &data[startOffset], nalSize);
-
-            if (stopOffset != NULL) {
-                *stopOffset = startOffset + nalSize;
-            }
-
-            return nal;
-        }
-
-        if (offset + 4 >= size) {
-            return NULL;
-        }
-
-        if ((data[offset + 4] & 0x1f) == nalType) {
-            foundStart = true;
-            startOffset = offset + 4;
-        }
-
-        offset += 4;
-    }
-}
-
-static sp<ABuffer> MakeAVCCodecSpecificData(
-        const sp<ABuffer> &buffer, int32_t *width, int32_t *height) {
-    const uint8_t *data = buffer->data();
-    size_t size = buffer->size();
-
-    sp<ABuffer> seqParamSet = FindNAL(data, size, 7, NULL);
-    if (seqParamSet == NULL) {
-        return NULL;
-    }
-
-    FindAVCDimensions(seqParamSet, width, height);
-
-    size_t stopOffset;
-    sp<ABuffer> picParamSet = FindNAL(data, size, 8, &stopOffset);
-    CHECK(picParamSet != NULL);
-
-    buffer->setRange(stopOffset, size - stopOffset);
-    LOGV("buffer has %d bytes left.", buffer->size());
-
-    size_t csdSize =
-        1 + 3 + 1 + 1
-        + 2 * 1 + seqParamSet->size()
-        + 1 + 2 * 1 + picParamSet->size();
-
-    sp<ABuffer> csd = new ABuffer(csdSize);
-    uint8_t *out = csd->data();
-
-    *out++ = 0x01;  // configurationVersion
-    memcpy(out, seqParamSet->data() + 1, 3);  // profile/level...
-    out += 3;
-    *out++ = (0x3f << 2) | 1;  // lengthSize == 2 bytes
-    *out++ = 0xe0 | 1;
-
-    *out++ = seqParamSet->size() >> 8;
-    *out++ = seqParamSet->size() & 0xff;
-    memcpy(out, seqParamSet->data(), seqParamSet->size());
-    out += seqParamSet->size();
-
-    *out++ = 1;
-
-    *out++ = picParamSet->size() >> 8;
-    *out++ = picParamSet->size() & 0xff;
-    memcpy(out, picParamSet->data(), picParamSet->size());
-
-    return csd;
-}
-
-static bool getNextNALUnit(
-        const uint8_t **_data, size_t *_size,
-        const uint8_t **nalStart, size_t *nalSize) {
-    const uint8_t *data = *_data;
-    size_t size = *_size;
-
-    // hexdump(data, size);
-
-    *nalStart = NULL;
-    *nalSize = 0;
-
-    if (size == 0) {
-        return false;
-    }
-
-    size_t offset = 0;
-    for (;;) {
-        CHECK_LT(offset + 2, size);
-
-        if (!memcmp("\x00\x00\x01", &data[offset], 3)) {
-            break;
-        }
-
-        CHECK_EQ((unsigned)data[offset], 0x00u);
-        ++offset;
-    }
-
-    offset += 3;
-    size_t startOffset = offset;
-
-    while (offset + 2 < size
-            && memcmp("\x00\x00\x00", &data[offset], 3)
-            && memcmp("\x00\x00\x01", &data[offset], 3)) {
-        ++offset;
-    }
-
-    if (offset + 2 >= size) {
-        *nalStart = &data[startOffset];
-        *nalSize = size - startOffset;
-
-        *_data = NULL;
-        *_size = 0;
-
-        return true;
-    }
-
-    size_t endOffset = offset;
-
-    while (offset + 2 < size && memcmp("\x00\x00\x01", &data[offset], 3)) {
-        CHECK_EQ((unsigned)data[offset], 0x00u);
-        ++offset;
-    }
-
-    *nalStart = &data[startOffset];
-    *nalSize = endOffset - startOffset;
-
-    if (offset + 2 < size) {
-        *_data = &data[offset];
-        *_size = size - offset;
-    } else {
-        *_data = NULL;
-        *_size = 0;
-    }
-
-    return true;
-}
-
-sp<ABuffer> MakeCleanAVCData(const uint8_t *data, size_t size) {
-    // hexdump(data, size);
-
-    const uint8_t *tmpData = data;
-    size_t tmpSize = size;
-
-    size_t totalSize = 0;
-    const uint8_t *nalStart;
-    size_t nalSize;
-    while (getNextNALUnit(&tmpData, &tmpSize, &nalStart, &nalSize)) {
-        // hexdump(nalStart, nalSize);
-        totalSize += 4 + nalSize;
-    }
-
-    sp<ABuffer> buffer = new ABuffer(totalSize);
-    size_t offset = 0;
-    while (getNextNALUnit(&data, &size, &nalStart, &nalSize)) {
-        memcpy(buffer->data() + offset, "\x00\x00\x00\x01", 4);
-        memcpy(buffer->data() + offset + 4, nalStart, nalSize);
-
-        offset += 4 + nalSize;
-    }
-
-    return buffer;
-}
-
-static sp<ABuffer> FindMPEG2ADTSConfig(
-        const sp<ABuffer> &buffer, int32_t *sampleRate, int32_t *channelCount) {
-    ABitReader br(buffer->data(), buffer->size());
-
-    CHECK_EQ(br.getBits(12), 0xfffu);
-    CHECK_EQ(br.getBits(1), 0u);
-    CHECK_EQ(br.getBits(2), 0u);
-    br.getBits(1);  // protection_absent
-    unsigned profile = br.getBits(2);
-    LOGV("profile = %u", profile);
-    CHECK_NE(profile, 3u);
-    unsigned sampling_freq_index = br.getBits(4);
-    br.getBits(1);  // private_bit
-    unsigned channel_configuration = br.getBits(3);
-    CHECK_NE(channel_configuration, 0u);
-
-    LOGV("sampling_freq_index = %u", sampling_freq_index);
-    LOGV("channel_configuration = %u", channel_configuration);
-
-    CHECK_LE(sampling_freq_index, 11u);
-    static const int32_t kSamplingFreq[] = {
-        96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
-        16000, 12000, 11025, 8000
-    };
-    *sampleRate = kSamplingFreq[sampling_freq_index];
-
-    *channelCount = channel_configuration;
-
-    static const uint8_t kStaticESDS[] = {
-        0x03, 22,
-        0x00, 0x00,     // ES_ID
-        0x00,           // streamDependenceFlag, URL_Flag, OCRstreamFlag
-
-        0x04, 17,
-        0x40,                       // Audio ISO/IEC 14496-3
-        0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00,
-        0x00, 0x00, 0x00, 0x00,
-
-        0x05, 2,
-        // AudioSpecificInfo follows
-
-        // oooo offf fccc c000
-        // o - audioObjectType
-        // f - samplingFreqIndex
-        // c - channelConfig
-    };
-    sp<ABuffer> csd = new ABuffer(sizeof(kStaticESDS) + 2);
-    memcpy(csd->data(), kStaticESDS, sizeof(kStaticESDS));
-
-    csd->data()[sizeof(kStaticESDS)] =
-        ((profile + 1) << 3) | (sampling_freq_index >> 1);
-
-    csd->data()[sizeof(kStaticESDS) + 1] =
-        ((sampling_freq_index << 7) & 0x80) | (channel_configuration << 3);
-
-    // hexdump(csd->data(), csd->size());
-    return csd;
-}
-
 void ATSParser::Stream::onPayloadData(
         unsigned PTS_DTS_flags, uint64_t PTS, uint64_t DTS,
         const uint8_t *data, size_t size) {
     LOGV("onPayloadData mStreamType=0x%02x", mStreamType);
 
-    sp<ABuffer> buffer;
-
-    if (mStreamType == 0x1b) {
-        buffer = MakeCleanAVCData(data, size);
-    } else {
-        // hexdump(data, size);
-
-        buffer = new ABuffer(size);
-        memcpy(buffer->data(), data, size);
-    }
-
-    if (mSource == NULL) {
-        sp<MetaData> meta = new MetaData;
-
-        if (mStreamType == 0x1b) {
-            meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
-
-            int32_t width, height;
-            sp<ABuffer> csd = MakeAVCCodecSpecificData(buffer, &width, &height);
-
-            if (csd == NULL) {
-                return;
-            }
-
-            meta->setData(kKeyAVCC, 0, csd->data(), csd->size());
-            meta->setInt32(kKeyWidth, width);
-            meta->setInt32(kKeyHeight, height);
-        } else {
-            CHECK_EQ(mStreamType, 0x0fu);
-
-            meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
-
-            int32_t sampleRate, channelCount;
-            sp<ABuffer> csd =
-                FindMPEG2ADTSConfig(buffer, &sampleRate, &channelCount);
-
-            LOGV("sampleRate = %d", sampleRate);
-            LOGV("channelCount = %d", channelCount);
-
-            meta->setInt32(kKeySampleRate, sampleRate);
-            meta->setInt32(kKeyChannelCount, channelCount);
-
-            meta->setData(kKeyESDS, 0, csd->data(), csd->size());
-        }
-
-        LOGV("created source!");
-        mSource = new AnotherPacketSource(meta);
-
-        // fall through
-    }
-
     CHECK(PTS_DTS_flags == 2 || PTS_DTS_flags == 3);
-    buffer->meta()->setInt64("time", (PTS * 100) / 9);
+    int64_t timeUs = (PTS * 100) / 9;
 
-    if (mStreamType == 0x0f) {
-        extractAACFrames(buffer);
-    }
+    status_t err = mQueue.appendData(data, size, timeUs);
+    CHECK_EQ(err, (status_t)OK);
 
-    mSource->queueAccessUnit(buffer);
-}
+    sp<ABuffer> accessUnit;
+    while ((accessUnit = mQueue.dequeueAccessUnit()) != NULL) {
+        if (mSource == NULL) {
+            sp<MetaData> meta = mQueue.getFormat();
 
-// Disassemble one or more ADTS frames into their constituent parts and
-// leave only the concatenated raw_data_blocks in the buffer.
-void ATSParser::Stream::extractAACFrames(const sp<ABuffer> &buffer) {
-    size_t dstOffset = 0;
-
-    size_t offset = 0;
-    while (offset < buffer->size()) {
-        CHECK_LE(offset + 7, buffer->size());
-
-        ABitReader bits(buffer->data() + offset, buffer->size() - offset);
-
-        // adts_fixed_header
-
-        CHECK_EQ(bits.getBits(12), 0xfffu);
-        bits.skipBits(3);  // ID, layer
-        bool protection_absent = bits.getBits(1) != 0;
-
-        // profile_ObjectType, sampling_frequency_index, private_bits,
-        // channel_configuration, original_copy, home
-        bits.skipBits(12);
-
-        // adts_variable_header
-
-        // copyright_identification_bit, copyright_identification_start
-        bits.skipBits(2);
-
-        unsigned aac_frame_length = bits.getBits(13);
-
-        bits.skipBits(11);  // adts_buffer_fullness
-
-        unsigned number_of_raw_data_blocks_in_frame = bits.getBits(2);
-
-        if (number_of_raw_data_blocks_in_frame == 0) {
-            size_t scan = offset + aac_frame_length;
-
-            offset += 7;
-            if (!protection_absent) {
-                offset += 2;
+            if (meta != NULL) {
+                LOGV("created source!");
+                mSource = new AnotherPacketSource(meta);
+                mSource->queueAccessUnit(accessUnit);
             }
-
-            CHECK_LE(scan, buffer->size());
-
-            LOGV("found aac raw data block at [0x%08x ; 0x%08x)", offset, scan);
-
-            memmove(&buffer->data()[dstOffset], &buffer->data()[offset],
-                    scan - offset);
-
-            dstOffset += scan - offset;
-            offset = scan;
         } else {
-            // To be implemented.
-            TRESPASS();
+            mSource->queueAccessUnit(accessUnit);
         }
     }
-    CHECK_EQ(offset, buffer->size());
-
-    buffer->setRange(buffer->offset(), dstOffset);
 }
 
 sp<MediaSource> ATSParser::Stream::getSource(SourceType type) {
diff --git a/media/libstagefright/mpeg2ts/Android.mk b/media/libstagefright/mpeg2ts/Android.mk
index 3544b4c..4dfc0f7 100644
--- a/media/libstagefright/mpeg2ts/Android.mk
+++ b/media/libstagefright/mpeg2ts/Android.mk
@@ -5,6 +5,7 @@
 LOCAL_SRC_FILES:=                 \
         AnotherPacketSource.cpp   \
         ATSParser.cpp             \
+        ESQueue.cpp               \
         MPEG2TSExtractor.cpp      \
 
 LOCAL_C_INCLUDES:= \
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
new file mode 100644
index 0000000..d87040b
--- /dev/null
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -0,0 +1,504 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "ESQueue"
+#include <media/stagefright/foundation/ADebug.h>
+
+#include "ESQueue.h"
+
+#include <media/stagefright/foundation/hexdump.h>
+#include <media/stagefright/foundation/ABitReader.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MetaData.h>
+
+#include "include/avc_utils.h"
+
+namespace android {
+
+ElementaryStreamQueue::ElementaryStreamQueue(Mode mode)
+    : mMode(mode) {
+}
+
+sp<MetaData> ElementaryStreamQueue::getFormat() {
+    return mFormat;
+}
+
+static status_t getNextNALUnit(
+        const uint8_t **_data, size_t *_size,
+        const uint8_t **nalStart, size_t *nalSize,
+        bool startCodeFollows = false) {
+    const uint8_t *data = *_data;
+    size_t size = *_size;
+
+    *nalStart = NULL;
+    *nalSize = 0;
+
+    if (size == 0) {
+        return -EAGAIN;
+    }
+
+    // Skip any number of leading 0x00.
+
+    size_t offset = 0;
+    while (offset < size && data[offset] == 0x00) {
+        ++offset;
+    }
+
+    if (offset == size) {
+        return -EAGAIN;
+    }
+
+    // A valid startcode consists of at least two 0x00 bytes followed by 0x01.
+
+    if (offset < 2 || data[offset] != 0x01) {
+        return ERROR_MALFORMED;
+    }
+
+    ++offset;
+
+    size_t startOffset = offset;
+
+    for (;;) {
+        while (offset < size && data[offset] != 0x01) {
+            ++offset;
+        }
+
+        if (offset == size) {
+            if (startCodeFollows) {
+                offset = size + 2;
+                break;
+            }
+
+            return -EAGAIN;
+        }
+
+        if (data[offset - 1] == 0x00 && data[offset - 2] == 0x00) {
+            break;
+        }
+
+        ++offset;
+    }
+
+    size_t endOffset = offset - 2;
+    while (data[endOffset - 1] == 0x00) {
+        --endOffset;
+    }
+
+    *nalStart = &data[startOffset];
+    *nalSize = endOffset - startOffset;
+
+    if (offset + 2 < size) {
+        *_data = &data[offset - 2];
+        *_size = size - offset + 2;
+    } else {
+        *_data = NULL;
+        *_size = 0;
+    }
+
+    return OK;
+}
+
+status_t ElementaryStreamQueue::appendData(
+        const void *data, size_t size, int64_t timeUs) {
+    if (mBuffer == NULL || mBuffer->size() == 0) {
+        switch (mMode) {
+            case H264:
+            {
+                if (size < 4 || memcmp("\x00\x00\x00\x01", data, 4)) {
+                    return ERROR_MALFORMED;
+                }
+                break;
+            }
+
+            case AAC:
+            {
+                uint8_t *ptr = (uint8_t *)data;
+
+                if (size < 2 || ptr[0] != 0xff || (ptr[1] >> 4) != 0x0f) {
+                    return ERROR_MALFORMED;
+                }
+                break;
+            }
+
+            default:
+                TRESPASS();
+                break;
+        }
+    }
+
+    size_t neededSize = (mBuffer == NULL ? 0 : mBuffer->size()) + size;
+    if (mBuffer == NULL || neededSize > mBuffer->capacity()) {
+        neededSize = (neededSize + 65535) & ~65535;
+
+        LOGI("resizing buffer to size %d", neededSize);
+
+        sp<ABuffer> buffer = new ABuffer(neededSize);
+        if (mBuffer != NULL) {
+            memcpy(buffer->data(), mBuffer->data(), mBuffer->size());
+            buffer->setRange(0, mBuffer->size());
+        } else {
+            buffer->setRange(0, 0);
+        }
+
+        mBuffer = buffer;
+    }
+
+    memcpy(mBuffer->data() + mBuffer->size(), data, size);
+    mBuffer->setRange(0, mBuffer->size() + size);
+
+    mTimestamps.push_back(timeUs);
+
+    return OK;
+}
+
+sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnit() {
+    if (mMode == H264) {
+        return dequeueAccessUnitH264();
+    } else {
+        CHECK_EQ((unsigned)mMode, (unsigned)AAC);
+        return dequeueAccessUnitAAC();
+    }
+}
+
+sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitAAC() {
+    Vector<size_t> frameOffsets;
+    Vector<size_t> frameSizes;
+    size_t auSize = 0;
+
+    size_t offset = 0;
+    while (offset + 7 <= mBuffer->size()) {
+        ABitReader bits(mBuffer->data() + offset, mBuffer->size() - offset);
+
+        // adts_fixed_header
+
+        CHECK_EQ(bits.getBits(12), 0xfffu);
+        bits.skipBits(3);  // ID, layer
+        bool protection_absent = bits.getBits(1) != 0;
+
+        if (mFormat == NULL) {
+            unsigned profile = bits.getBits(2);
+            CHECK_NE(profile, 3u);
+            unsigned sampling_freq_index = bits.getBits(4);
+            bits.getBits(1);  // private_bit
+            unsigned channel_configuration = bits.getBits(3);
+            CHECK_NE(channel_configuration, 0u);
+            bits.skipBits(2);  // original_copy, home
+
+            mFormat = MakeAACCodecSpecificData(
+                    profile, sampling_freq_index, channel_configuration);
+        } else {
+            // profile_ObjectType, sampling_frequency_index, private_bits,
+            // channel_configuration, original_copy, home
+            bits.skipBits(12);
+        }
+
+        // adts_variable_header
+
+        // copyright_identification_bit, copyright_identification_start
+        bits.skipBits(2);
+
+        unsigned aac_frame_length = bits.getBits(13);
+
+        bits.skipBits(11);  // adts_buffer_fullness
+
+        unsigned number_of_raw_data_blocks_in_frame = bits.getBits(2);
+
+        if (number_of_raw_data_blocks_in_frame != 0) {
+            // To be implemented.
+            TRESPASS();
+        }
+
+        if (offset + aac_frame_length > mBuffer->size()) {
+            break;
+        }
+
+        size_t headerSize = protection_absent ? 7 : 9;
+
+        frameOffsets.push(offset + headerSize);
+        frameSizes.push(aac_frame_length - headerSize);
+        auSize += aac_frame_length - headerSize;
+
+        offset += aac_frame_length;
+    }
+
+    if (offset == 0) {
+        return NULL;
+    }
+
+    sp<ABuffer> accessUnit = new ABuffer(auSize);
+    size_t dstOffset = 0;
+    for (size_t i = 0; i < frameOffsets.size(); ++i) {
+        memcpy(accessUnit->data() + dstOffset,
+               mBuffer->data() + frameOffsets.itemAt(i),
+               frameSizes.itemAt(i));
+
+        dstOffset += frameSizes.itemAt(i);
+    }
+
+    memmove(mBuffer->data(), mBuffer->data() + offset,
+            mBuffer->size() - offset);
+    mBuffer->setRange(0, mBuffer->size() - offset);
+
+    CHECK_GT(mTimestamps.size(), 0u);
+    int64_t timeUs = *mTimestamps.begin();
+    mTimestamps.erase(mTimestamps.begin());
+
+    accessUnit->meta()->setInt64("time", timeUs);
+
+    return accessUnit;
+}
+
+// static
+sp<MetaData> ElementaryStreamQueue::MakeAACCodecSpecificData(
+        unsigned profile, unsigned sampling_freq_index,
+        unsigned channel_configuration) {
+    sp<MetaData> meta = new MetaData;
+    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
+
+    CHECK_LE(sampling_freq_index, 11u);
+    static const int32_t kSamplingFreq[] = {
+        96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
+        16000, 12000, 11025, 8000
+    };
+    meta->setInt32(kKeySampleRate, kSamplingFreq[sampling_freq_index]);
+    meta->setInt32(kKeyChannelCount, channel_configuration);
+
+    static const uint8_t kStaticESDS[] = {
+        0x03, 22,
+        0x00, 0x00,     // ES_ID
+        0x00,           // streamDependenceFlag, URL_Flag, OCRstreamFlag
+
+        0x04, 17,
+        0x40,                       // Audio ISO/IEC 14496-3
+        0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00,
+        0x00, 0x00, 0x00, 0x00,
+
+        0x05, 2,
+        // AudioSpecificInfo follows
+
+        // oooo offf fccc c000
+        // o - audioObjectType
+        // f - samplingFreqIndex
+        // c - channelConfig
+    };
+    sp<ABuffer> csd = new ABuffer(sizeof(kStaticESDS) + 2);
+    memcpy(csd->data(), kStaticESDS, sizeof(kStaticESDS));
+
+    csd->data()[sizeof(kStaticESDS)] =
+        ((profile + 1) << 3) | (sampling_freq_index >> 1);
+
+    csd->data()[sizeof(kStaticESDS) + 1] =
+        ((sampling_freq_index << 7) & 0x80) | (channel_configuration << 3);
+
+    meta->setData(kKeyESDS, 0, csd->data(), csd->size());
+
+    return meta;
+}
+
+struct NALPosition {
+    size_t nalOffset;
+    size_t nalSize;
+};
+
+sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitH264() {
+    const uint8_t *data = mBuffer->data();
+    size_t size = mBuffer->size();
+
+    Vector<NALPosition> nals;
+
+    size_t totalSize = 0;
+
+    status_t err;
+    const uint8_t *nalStart;
+    size_t nalSize;
+    bool foundSlice = false;
+    while ((err = getNextNALUnit(&data, &size, &nalStart, &nalSize)) == OK) {
+        CHECK_GT(nalSize, 0u);
+
+        unsigned nalType = nalStart[0] & 0x1f;
+        bool flush = false;
+
+        if (nalType == 1 || nalType == 5) {
+            if (foundSlice) {
+                ABitReader br(nalStart + 1, nalSize);
+                unsigned first_mb_in_slice = parseUE(&br);
+
+                if (first_mb_in_slice == 0) {
+                    // This slice starts a new frame.
+
+                    flush = true;
+                }
+            }
+
+            foundSlice = true;
+        } else if ((nalType == 9 || nalType == 7) && foundSlice) {
+            // Access unit delimiter and SPS will be associated with the
+            // next frame.
+
+            flush = true;
+        }
+
+        if (flush) {
+            // The access unit will contain all nal units up to, but excluding
+            // the current one, separated by 0x00 0x00 0x00 0x01 startcodes.
+
+            size_t auSize = 4 * nals.size() + totalSize;
+            sp<ABuffer> accessUnit = new ABuffer(auSize);
+
+#if !LOG_NDEBUG
+            AString out;
+#endif
+
+            size_t dstOffset = 0;
+            for (size_t i = 0; i < nals.size(); ++i) {
+                const NALPosition &pos = nals.itemAt(i);
+
+                unsigned nalType = mBuffer->data()[pos.nalOffset] & 0x1f;
+
+#if !LOG_NDEBUG
+                char tmp[128];
+                sprintf(tmp, "0x%02x", nalType);
+                if (i > 0) {
+                    out.append(", ");
+                }
+                out.append(tmp);
+#endif
+
+                memcpy(accessUnit->data() + dstOffset, "\x00\x00\x00\x01", 4);
+
+                memcpy(accessUnit->data() + dstOffset + 4,
+                       mBuffer->data() + pos.nalOffset,
+                       pos.nalSize);
+
+                dstOffset += pos.nalSize + 4;
+            }
+
+            LOGV("accessUnit contains nal types %s", out.c_str());
+
+            const NALPosition &pos = nals.itemAt(nals.size() - 1);
+            size_t nextScan = pos.nalOffset + pos.nalSize;
+
+            memmove(mBuffer->data(),
+                    mBuffer->data() + nextScan,
+                    mBuffer->size() - nextScan);
+
+            mBuffer->setRange(0, mBuffer->size() - nextScan);
+
+            CHECK_GT(mTimestamps.size(), 0u);
+            int64_t timeUs = *mTimestamps.begin();
+            mTimestamps.erase(mTimestamps.begin());
+
+            accessUnit->meta()->setInt64("time", timeUs);
+
+            if (mFormat == NULL) {
+                mFormat = MakeAVCCodecSpecificData(accessUnit);
+            }
+
+            return accessUnit;
+        }
+
+        NALPosition pos;
+        pos.nalOffset = nalStart - mBuffer->data();
+        pos.nalSize = nalSize;
+
+        nals.push(pos);
+
+        totalSize += nalSize;
+    }
+    CHECK_EQ(err, (status_t)-EAGAIN);
+
+    return NULL;
+}
+
+static sp<ABuffer> FindNAL(
+        const uint8_t *data, size_t size, unsigned nalType,
+        size_t *stopOffset) {
+    const uint8_t *nalStart;
+    size_t nalSize;
+    while (getNextNALUnit(&data, &size, &nalStart, &nalSize, true) == OK) {
+        if ((nalStart[0] & 0x1f) == nalType) {
+            sp<ABuffer> buffer = new ABuffer(nalSize);
+            memcpy(buffer->data(), nalStart, nalSize);
+            return buffer;
+        }
+    }
+
+    return NULL;
+}
+
+sp<MetaData> ElementaryStreamQueue::MakeAVCCodecSpecificData(
+        const sp<ABuffer> &accessUnit) {
+    const uint8_t *data = accessUnit->data();
+    size_t size = accessUnit->size();
+
+    sp<ABuffer> seqParamSet = FindNAL(data, size, 7, NULL);
+    if (seqParamSet == NULL) {
+        return NULL;
+    }
+
+    int32_t width, height;
+    FindAVCDimensions(seqParamSet, &width, &height);
+
+    size_t stopOffset;
+    sp<ABuffer> picParamSet = FindNAL(data, size, 8, &stopOffset);
+    CHECK(picParamSet != NULL);
+
+    size_t csdSize =
+        1 + 3 + 1 + 1
+        + 2 * 1 + seqParamSet->size()
+        + 1 + 2 * 1 + picParamSet->size();
+
+    sp<ABuffer> csd = new ABuffer(csdSize);
+    uint8_t *out = csd->data();
+
+    *out++ = 0x01;  // configurationVersion
+    memcpy(out, seqParamSet->data() + 1, 3);  // profile/level...
+    out += 3;
+    *out++ = (0x3f << 2) | 1;  // lengthSize == 2 bytes
+    *out++ = 0xe0 | 1;
+
+    *out++ = seqParamSet->size() >> 8;
+    *out++ = seqParamSet->size() & 0xff;
+    memcpy(out, seqParamSet->data(), seqParamSet->size());
+    out += seqParamSet->size();
+
+    *out++ = 1;
+
+    *out++ = picParamSet->size() >> 8;
+    *out++ = picParamSet->size() & 0xff;
+    memcpy(out, picParamSet->data(), picParamSet->size());
+
+#if 0
+    LOGI("AVC seq param set");
+    hexdump(seqParamSet->data(), seqParamSet->size());
+#endif
+
+    sp<MetaData> meta = new MetaData;
+    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
+
+    meta->setData(kKeyAVCC, 0, csd->data(), csd->size());
+    meta->setInt32(kKeyWidth, width);
+    meta->setInt32(kKeyHeight, height);
+
+    return meta;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/mpeg2ts/ESQueue.h b/media/libstagefright/mpeg2ts/ESQueue.h
new file mode 100644
index 0000000..d2e87f2
--- /dev/null
+++ b/media/libstagefright/mpeg2ts/ESQueue.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ES_QUEUE_H_
+
+#define ES_QUEUE_H_
+
+#include <media/stagefright/foundation/ABase.h>
+#include <utils/List.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+struct ABuffer;
+struct MetaData;
+
+struct ElementaryStreamQueue {
+    enum Mode {
+        H264,
+        AAC
+    };
+    ElementaryStreamQueue(Mode mode);
+
+    status_t appendData(const void *data, size_t size, int64_t timeUs);
+
+    sp<ABuffer> dequeueAccessUnit();
+
+    sp<MetaData> getFormat();
+
+private:
+    Mode mMode;
+
+    sp<ABuffer> mBuffer;
+    List<int64_t> mTimestamps;
+
+    sp<MetaData> mFormat;
+
+    sp<ABuffer> dequeueAccessUnitH264();
+    sp<ABuffer> dequeueAccessUnitAAC();
+
+    static sp<MetaData> MakeAACCodecSpecificData(
+            unsigned profile, unsigned sampling_freq_index,
+            unsigned channel_configuration);
+
+    static sp<MetaData> MakeAVCCodecSpecificData(
+            const sp<ABuffer> &accessUnit);
+
+    DISALLOW_EVIL_CONSTRUCTORS(ElementaryStreamQueue);
+};
+
+}  // namespace android
+
+#endif  // ES_QUEUE_H_
diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
index 2417305..c5257bb 100644
--- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
@@ -157,7 +157,7 @@
             }
         }
 
-        if (++numPacketsParsed > 1500) {
+        if (++numPacketsParsed > 2500) {
             break;
         }
     }
diff --git a/packages/SystemUI/res/drawable-hdpi/divider_horizontal_light_opaque.9.png b/packages/SystemUI/res/drawable-hdpi/divider_horizontal_light_opaque.9.png
new file mode 100644
index 0000000..f70f079
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/divider_horizontal_light_opaque.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/divider_horizontal_light_opaque.9.png b/packages/SystemUI/res/drawable-mdpi/divider_horizontal_light_opaque.9.png
new file mode 100644
index 0000000..f70f079
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/divider_horizontal_light_opaque.9.png
Binary files differ
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 12d1d5c..c3f4205 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -57,7 +57,7 @@
             style="?android:attr/buttonStyle"
             android:paddingLeft="15dp"
             android:paddingRight="15dp"
-            android:background="@drawable/btn_default_small"
+            android:background="@android:drawable/btn_default_small"
             />
     </LinearLayout>
 
diff --git a/packages/SystemUI/res/layout/status_bar_latest_event.xml b/packages/SystemUI/res/layout/status_bar_latest_event.xml
index 65c731b..b8a1cbe 100644
--- a/packages/SystemUI/res/layout/status_bar_latest_event.xml
+++ b/packages/SystemUI/res/layout/status_bar_latest_event.xml
@@ -17,7 +17,7 @@
     <View
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:background="@drawable/divider_horizontal_dark_opaque"
+        android:background="@drawable/divider_horizontal_light_opaque"
         />
 
 </LinearLayout>
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 384f527..538dae9 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -1500,7 +1500,9 @@
             } 
             if (attrs.type >= FIRST_APPLICATION_WINDOW
                     && attrs.type <= LAST_APPLICATION_WINDOW
-                    && win.fillsScreenLw(mW, mH, false, false)) {
+                    && attrs.x == 0 && attrs.y == 0
+                    && attrs.width == WindowManager.LayoutParams.MATCH_PARENT
+                    && attrs.height == WindowManager.LayoutParams.MATCH_PARENT) {
                 if (DEBUG_LAYOUT) Log.v(TAG, "Fullscreen window: " + win);
                 mTopFullscreenOpaqueWindowState = win;
                 if ((attrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) {
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index d6ee075..8e5cdc2 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -1599,20 +1599,23 @@
             addObbState(obbState);
         }
 
-        final MessageDigest md;
-        try {
-            md = MessageDigest.getInstance("MD5");
-        } catch (NoSuchAlgorithmException e) {
-            Slog.e(TAG, "Could not load MD5 algorithm", e);
+        String hashedKey = null;
+        if (key != null) {
+            final MessageDigest md;
             try {
-                token.onObbResult(filename, Environment.MEDIA_UNMOUNTED);
-            } catch (RemoteException e1) {
-                Slog.d(TAG, "Could not send unmount notification for: " + filename);
+                md = MessageDigest.getInstance("MD5");
+            } catch (NoSuchAlgorithmException e) {
+                Slog.e(TAG, "Could not load MD5 algorithm", e);
+                try {
+                    token.onObbResult(filename, Environment.MEDIA_UNMOUNTED);
+                } catch (RemoteException e1) {
+                    Slog.d(TAG, "Could not send unmount notification for: " + filename);
+                }
+                return;
             }
-            return;
-        }
 
-        String hashedKey = HexDump.toHexString(md.digest(key.getBytes()));
+            hashedKey = HexDump.toHexString(md.digest(key.getBytes()));
+        }
 
         ObbAction action = new MountObbAction(obbState, hashedKey);
         mObbActionHandler.sendMessage(mObbActionHandler.obtainMessage(OBB_RUN_ACTION, action));
@@ -1956,10 +1959,6 @@
                 throw new IllegalArgumentException("Caller package does not match OBB file");
             }
 
-            if (mKey == null) {
-                mKey = "none";
-            }
-
             boolean mounted = false;
             int rc;
             synchronized (mObbState) {
@@ -1969,7 +1968,8 @@
                 }
 
                 rc = StorageResultCode.OperationSucceeded;
-                String cmd = String.format("obb mount %s %s %d", mObbState.filename, mKey,
+                String cmd = String.format("obb mount %s %s %d", mObbState.filename,
+                        mKey != null ? mKey : "none",
                         mObbState.callerUid);
                 try {
                     mConnector.doCommand(cmd);
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index d7a3596..713524a 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -6965,31 +6965,6 @@
                 && (mOrientationChanging || (!mDrawPending && !mCommitDrawPending));
         }
 
-        public boolean fillsScreenLw(int screenWidth, int screenHeight,
-                                   boolean shownFrame, boolean onlyOpaque) {
-            if (mSurface == null) {
-                return false;
-            }
-            if (mAppToken != null && !mAppToken.appFullscreen) {
-                return false;
-            }
-            if (onlyOpaque && mAttrs.format != PixelFormat.OPAQUE) {
-                return false;
-            }
-            final Rect frame = shownFrame ? mShownFrame : mFrame;
-
-            if ((mAttrs.flags & FLAG_COMPATIBLE_WINDOW) != 0) {
-                return frame.left <= mCompatibleScreenFrame.left &&
-                        frame.top <= mCompatibleScreenFrame.top &&
-                        frame.right >= mCompatibleScreenFrame.right &&
-                        frame.bottom >= mCompatibleScreenFrame.bottom;
-            } else {
-                return frame.left <= 0 && frame.top <= 0
-                        && frame.right >= screenWidth
-                        && frame.bottom >= screenHeight;
-            }
-        }
-
         /**
          * Return true if the window is opaque and fully drawn.  This indicates
          * it may obscure windows behind it.
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index 6f52f24..6b3df38 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -182,7 +182,6 @@
 
     virtual bool getDisplayInfo(int32_t displayId,
             int32_t* width, int32_t* height, int32_t* orientation);
-    virtual void virtualKeyDownFeedback();
     virtual int32_t interceptKey(nsecs_t when, int32_t deviceId,
             bool down, int32_t keyCode, int32_t scanCode, uint32_t& policyFlags);
     virtual int32_t interceptSwitch(nsecs_t when, int32_t switchCode, int32_t switchValue,
@@ -464,17 +463,6 @@
     return android_server_PowerManagerService_isScreenBright();
 }
 
-void NativeInputManager::virtualKeyDownFeedback() {
-#if DEBUG_INPUT_READER_POLICY
-    LOGD("virtualKeyDownFeedback");
-#endif
-
-    JNIEnv* env = jniEnv();
-
-    env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.virtualKeyDownFeedback);
-    checkAndClearExceptionFromCallback(env, "virtualKeyDownFeedback");
-}
-
 int32_t NativeInputManager::interceptKey(nsecs_t when,
         int32_t deviceId, bool down, int32_t keyCode, int32_t scanCode, uint32_t& policyFlags) {
 #if DEBUG_INPUT_READER_POLICY
@@ -483,6 +471,12 @@
             when, deviceId, down, keyCode, scanCode, policyFlags);
 #endif
 
+    if (down && (policyFlags & POLICY_FLAG_VIRTUAL)) {
+        JNIEnv* env = jniEnv();
+        env->CallVoidMethod(mCallbacksObj, gCallbacksClassInfo.virtualKeyDownFeedback);
+        checkAndClearExceptionFromCallback(env, "virtualKeyDownFeedback");
+    }
+
     const int32_t WM_ACTION_PASS_TO_USER = 1;
     const int32_t WM_ACTION_POKE_USER_ACTIVITY = 2;
     const int32_t WM_ACTION_GO_TO_SLEEP = 4;
diff --git a/telephony/java/com/android/internal/telephony/CallManager.java b/telephony/java/com/android/internal/telephony/CallManager.java
index 7c3508f..09b7d05 100644
--- a/telephony/java/com/android/internal/telephony/CallManager.java
+++ b/telephony/java/com/android/internal/telephony/CallManager.java
@@ -861,6 +861,25 @@
     }
 
     /**
+     * Enables or disables echo suppression.
+     */
+    public void setEchoSuppressionEnabled(boolean enabled) {
+        if (VDBG) {
+            Log.d(LOG_TAG, " setEchoSuppression(" + enabled + ")");
+            Log.d(LOG_TAG, this.toString());
+        }
+
+        if (hasActiveFgCall()) {
+            getActiveFgCall().getPhone().setEchoSuppressionEnabled(enabled);
+        }
+
+        if (VDBG) {
+            Log.d(LOG_TAG, "End setEchoSuppression(" + enabled + ")");
+            Log.d(LOG_TAG, this.toString());
+        }
+    }
+
+    /**
      * Play a DTMF tone on the active call.
      *
      * @param c should be one of 0-9, '*' or '#'. Other values will be
diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java
index 9afade3..d5791eb 100644
--- a/telephony/java/com/android/internal/telephony/Phone.java
+++ b/telephony/java/com/android/internal/telephony/Phone.java
@@ -1169,6 +1169,11 @@
     boolean getMute();
 
     /**
+     * Enables or disables echo suppression.
+     */
+    void setEchoSuppressionEnabled(boolean enabled);
+
+    /**
      * Invokes RIL_REQUEST_OEM_HOOK_RAW on RIL implementation.
      *
      * @param data The data for the request.
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index ff28773..53503a53 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -505,6 +505,10 @@
         mCM.unregisterForResendIncallMute(h);
     }
 
+    public void setEchoSuppressionEnabled(boolean enabled) {
+        // no need for regular phone
+    }
+
     /**
      * Subclasses of Phone probably want to replace this with a
      * version scoped to their packages
diff --git a/telephony/java/com/android/internal/telephony/PhoneProxy.java b/telephony/java/com/android/internal/telephony/PhoneProxy.java
index e1511e6..6f08868 100644
--- a/telephony/java/com/android/internal/telephony/PhoneProxy.java
+++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java
@@ -568,6 +568,10 @@
         return mActivePhone.getMute();
     }
 
+    public void setEchoSuppressionEnabled(boolean enabled) {
+        mActivePhone.setEchoSuppressionEnabled(enabled);
+    }
+
     public void invokeOemRilRequestRaw(byte[] data, Message response) {
         mActivePhone.invokeOemRilRequestRaw(data, response);
     }
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhone.java b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
index af3e0886..e3c3d65 100755
--- a/telephony/java/com/android/internal/telephony/sip/SipPhone.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
@@ -327,6 +327,20 @@
         Log.e(LOG_TAG, "call waiting not supported");
     }
 
+    @Override
+    public void setEchoSuppressionEnabled(boolean enabled) {
+        synchronized (SipPhone.class) {
+            AudioGroup audioGroup = foregroundCall.getAudioGroup();
+            if (audioGroup == null) return;
+            int mode = audioGroup.getMode();
+            audioGroup.setMode(enabled
+                    ? AudioGroup.MODE_ECHO_SUPPRESSION
+                    : AudioGroup.MODE_NORMAL);
+            Log.d(LOG_TAG, String.format("audioGroup mode change: %d --> %d",
+                    mode, audioGroup.getMode()));
+        }
+    }
+
     public void setMute(boolean muted) {
         synchronized (SipPhone.class) {
             foregroundCall.setMute(muted);
diff --git a/tools/obbtool/mkobb.sh b/tools/obbtool/mkobb.sh
index 1987696..ba5256f 100755
--- a/tools/obbtool/mkobb.sh
+++ b/tools/obbtool/mkobb.sh
@@ -161,11 +161,10 @@
 
 while true; do \
     case "$1" in
-        -c) use_crypto=1; shift;;
         -d) directory=$2; shift 2;;
         -h) usage; exit 1;;
-        -k) key=$2; shift 2;;
-        -K) prompt_key=1; shift;;
+        -k) key=$2; use_crypto=1; shift 2;;
+        -K) prompt_key=1; use_crypto=1; shift;;
         -v) verbose=1; shift;;
         -o) filename=$2; shift 2;;
         --) shift; break;;