Merge change 4486 into donut

* changes:
  Fixes #1107690. Updates javadoc for Intent.java, android:value -> android:name.
diff --git a/cmds/backup/backup.cpp b/cmds/backup/backup.cpp
index 22dd486..d4e669b 100644
--- a/cmds/backup/backup.cpp
+++ b/cmds/backup/backup.cpp
@@ -64,22 +64,14 @@
     }
 
     BackupDataReader reader(fd);
+    bool done;
     int type;
 
-    while (reader.ReadNextHeader(&type) == 0) {
+    while (reader.ReadNextHeader(&done, &type) == 0) {
+        if (done) {
+            break;
+        }
         switch (type) {
-            case BACKUP_HEADER_APP_V1:
-            {
-                String8 packageName;
-                int cookie;
-                err = reader.ReadAppHeader(&packageName, &cookie);
-                if (err == 0) {
-                    printf("App header: %s 0x%08x (%d)\n", packageName.string(), cookie, cookie);
-                } else {
-                    printf("Error reading app header\n");
-                }
-                break;
-            }
             case BACKUP_HEADER_ENTITY_V1:
             {
                 String8 key;
@@ -92,17 +84,6 @@
                 }
                 break;
             }
-            case BACKUP_FOOTER_APP_V1:
-            {
-                int cookie;
-                err = reader.ReadAppFooter(&cookie);
-                if (err == 0) {
-                    printf("   App footer: 0x%08x (%d)\n", cookie, cookie);
-                } else {
-                    printf("   Error reading entity header\n");
-                }
-                break;
-            }
             default:
             {
                 printf("Unknown chunk type: 0x%08x\n", type);
diff --git a/cmds/keystore/commands.c b/cmds/keystore/commands.c
index e53cece..17dd060 100644
--- a/cmds/keystore/commands.c
+++ b/cmds/keystore/commands.c
@@ -1,5 +1,5 @@
 /*
-** Copyright 2008, The Android Open Source Project
+** Copyright 2009, The Android Open Source Project
 **
 ** Licensed under the Apache License, Version 2.0 (the "License");
 ** you may not use this file except in compliance with the License.
@@ -30,7 +30,8 @@
     return d;
 }
 
-static int list_files(const char *dir, char reply[REPLY_MAX]) {
+static int list_files(const char *dir, char reply[REPLY_MAX])
+{
     struct dirent *de;
     DIR *d;
 
@@ -39,7 +40,9 @@
     }
     reply[0]=0;
     while ((de = readdir(d))) {
-        if (de->d_type != DT_REG) continue;
+        if (de->d_type != DT_DIR) continue;
+        if ((strcmp(DOT, de->d_name) == 0) ||
+                (strcmp(DOTDOT, de->d_name) == 0)) continue;
         if (reply[0] != 0) strlcat(reply, " ", REPLY_MAX);
         if (strlcat(reply, de->d_name, REPLY_MAX) >= REPLY_MAX) {
             LOGE("reply is too long(too many files under '%s'\n", dir);
@@ -50,31 +53,25 @@
     return 0;
 }
 
-static int copy_keyfile(const char *keystore, const char *srcfile) {
-    int srcfd, dstfd;
-    int length;
-    char buf[2048];
-    char dstfile[KEYNAME_LENGTH];
-    const char *filename = strrchr(srcfile, '/');
+static int copy_keyfile(const char *src, int src_type, const char *dstfile) {
+    int srcfd = -1, dstfd;
+    char buf[REPLY_MAX];
 
-    strlcpy(dstfile, keystore, KEYNAME_LENGTH);
-    strlcat(dstfile, "/", KEYNAME_LENGTH);
-    if (strlcat(dstfile, filename ? filename + 1 : srcfile,
-                KEYNAME_LENGTH) >= KEYNAME_LENGTH) {
-        LOGE("keyname is too long '%s'\n", srcfile);
-        return -1;
-    }
-
-    if ((srcfd = open(srcfile, O_RDONLY)) == -1) {
-        LOGE("Cannot open the original file '%s'\n", srcfile);
+    if ((src_type == IS_FILE) && (srcfd = open(src, O_RDONLY)) == -1) {
+        LOGE("Cannot open the original file '%s'\n", src);
         return -1;
     }
     if ((dstfd = open(dstfile, O_CREAT|O_RDWR)) == -1) {
         LOGE("Cannot open the destination file '%s'\n", dstfile);
         return -1;
     }
-    while((length = read(srcfd, buf, 2048)) > 0) {
-        write(dstfd, buf, length);
+    if (src_type == IS_FILE) {
+        int length;
+        while((length = read(srcfd, buf, REPLY_MAX)) > 0) {
+            write(dstfd, buf, length);
+        }
+    } else {
+        write(dstfd, src, strlen(src));
     }
     close(srcfd);
     close(dstfd);
@@ -82,60 +79,149 @@
     return 0;
 }
 
-static int install_key(const char *dir, const char *keyfile)
+static int install_key(const char *path, const char *certname, const char *src,
+        int src_is_file, char *dstfile)
 {
     struct dirent *de;
+    char fullpath[KEYNAME_LENGTH];
     DIR *d;
 
-    if ((d = open_keystore(dir)) == NULL) {
+    if (snprintf(fullpath, sizeof(fullpath), "%s/%s/", path, certname)
+            >= KEYNAME_LENGTH) {
+        LOGE("cert name '%s' is too long.\n", certname);
         return -1;
     }
-    return copy_keyfile(dir, keyfile);
+
+    if ((d = open_keystore(fullpath)) == NULL) {
+        LOGE("Can not open the keystore '%s'\n", fullpath);
+        return -1;
+    }
+    closedir(d);
+    if (strlcat(fullpath, dstfile, KEYNAME_LENGTH) >= KEYNAME_LENGTH) {
+        LOGE("cert name '%s' is too long.\n", certname);
+        return -1;
+    }
+    return copy_keyfile(src, src_is_file, fullpath);
 }
 
-static int remove_key(const char *dir, const char *keyfile)
+static int get_key(const char *path, const char *keyname, const char *file,
+        char reply[REPLY_MAX])
 {
-    char dstfile[KEYNAME_LENGTH];
+    struct dirent *de;
+    char filename[KEYNAME_LENGTH];
+    int fd;
 
-    strlcpy(dstfile, dir, KEYNAME_LENGTH);
-    strlcat(dstfile, "/", KEYNAME_LENGTH);
-    if (strlcat(dstfile, keyfile, KEYNAME_LENGTH) >= KEYNAME_LENGTH) {
-        LOGE("keyname is too long '%s'\n", keyfile);
+    if (snprintf(filename, sizeof(filename), "%s/%s/%s", path, keyname, file)
+            >= KEYNAME_LENGTH) {
+        LOGE("cert name '%s' is too long.\n", keyname);
         return -1;
     }
-    if (unlink(dstfile)) {
-        LOGE("cannot delete '%s': %s\n", dstfile, strerror(errno));
+
+    if ((fd = open(filename, O_RDONLY)) == -1) {
+        return -1;
+    }
+    close(fd);
+    strlcpy(reply, filename, REPLY_MAX);
+    return 0;
+}
+
+static int remove_key(const char *dir, const char *key)
+{
+    char dstfile[KEYNAME_LENGTH];
+    char *keyfile[4] = { USER_KEY, USER_P12_CERT, USER_CERTIFICATE,
+            CA_CERTIFICATE };
+    int i, count = 0;
+
+    for ( i = 0 ; i < 4 ; i++) {
+        if (snprintf(dstfile, KEYNAME_LENGTH, "%s/%s/%s", dir, key, keyfile[i])
+                >= KEYNAME_LENGTH) {
+            LOGE("keyname is too long '%s'\n", key);
+            return -1;
+        }
+        if (unlink(dstfile) == 0) count++;
+    }
+
+    if (count == 0) {
+        LOGE("can not clean up '%s' keys or not exist\n", key);
+        return -1;
+    }
+
+    snprintf(dstfile, KEYNAME_LENGTH, "%s/%s", dir, key);
+    if (rmdir(dstfile)) {
+        LOGE("can not clean up '%s' directory\n", key);
         return -1;
     }
     return 0;
 }
 
-int list_certs(char reply[REPLY_MAX])
+int list_user_certs(char reply[REPLY_MAX])
 {
     return list_files(CERTS_DIR, reply);
 }
 
-int list_userkeys(char reply[REPLY_MAX])
+int list_ca_certs(char reply[REPLY_MAX])
 {
-    return list_files(USERKEYS_DIR, reply);
+    return list_files(CACERTS_DIR, reply);
 }
 
-int install_cert(const char *certfile)
+int install_user_cert(const char *keyname, const char *cert, const char *key)
 {
-    return install_key(CERTS_DIR, certfile);
+    if (install_key(CERTS_DIR, keyname, cert, IS_FILE, USER_CERTIFICATE) == 0) {
+        return install_key(CERTS_DIR, keyname, key, IS_FILE, USER_KEY);
+    }
+    return -1;
 }
 
-int install_userkey(const char *keyfile)
+int install_ca_cert(const char *keyname, const char *certfile)
 {
-    return install_key(USERKEYS_DIR, keyfile);
+    return install_key(CACERTS_DIR, keyname, certfile, IS_FILE, CA_CERTIFICATE);
 }
 
-int remove_cert(const char *certfile)
+int install_p12_cert(const char *keyname, const char *certfile)
 {
-    return remove_key(CERTS_DIR, certfile);
+    return install_key(CERTS_DIR, keyname, certfile, IS_FILE, USER_P12_CERT);
 }
 
-int remove_userkey(const char *keyfile)
+int add_ca_cert(const char *keyname, const char *certificate)
 {
-    return remove_key(USERKEYS_DIR, keyfile);
+    return install_key(CACERTS_DIR, keyname, certificate, IS_CONTENT,
+            CA_CERTIFICATE);
+}
+
+int add_user_cert(const char *keyname, const char *certificate)
+{
+    return install_key(CERTS_DIR, keyname, certificate, IS_CONTENT,
+            USER_CERTIFICATE);
+}
+
+int add_user_key(const char *keyname, const char *key)
+{
+    return install_key(CERTS_DIR, keyname, key, IS_CONTENT, USER_KEY);
+}
+
+int get_ca_cert(const char *keyname, char reply[REPLY_MAX])
+{
+    return get_key(CACERTS_DIR, keyname, CA_CERTIFICATE, reply);
+}
+
+int get_user_cert(const char *keyname, char reply[REPLY_MAX])
+{
+    return get_key(CERTS_DIR, keyname, USER_CERTIFICATE, reply);
+}
+
+int get_user_key(const char *keyname, char reply[REPLY_MAX])
+{
+    if(get_key(CERTS_DIR, keyname, USER_KEY, reply))
+        return get_key(CERTS_DIR, keyname, USER_P12_CERT, reply);
+    return 0;
+}
+
+int remove_user_cert(const char *key)
+{
+    return remove_key(CERTS_DIR, key);
+}
+
+int remove_ca_cert(const char *key)
+{
+    return remove_key(CACERTS_DIR, key);
 }
diff --git a/cmds/keystore/keystore.c b/cmds/keystore/keystore.c
index 5193b3d..df8d832 100644
--- a/cmds/keystore/keystore.c
+++ b/cmds/keystore/keystore.c
@@ -16,37 +16,89 @@
 
 #include "keystore.h"
 
-
-static int do_list_certs(char **arg, char reply[REPLY_MAX])
+static inline int has_whitespace(char *name)
 {
-    return list_certs(reply);
+    if((strrchr(name, ' ') != NULL)) {
+        LOGE("'%s' contains whitespace character\n", name);
+        return 1;
+    }
+    return 0;
 }
 
-static int do_list_userkeys(char **arg, char reply[REPLY_MAX])
+static int do_list_user_certs(char **arg, char reply[REPLY_MAX])
 {
-    return list_userkeys(reply);
+    return list_user_certs(reply);
 }
 
-static int do_install_cert(char **arg, char reply[REPLY_MAX])
+static int do_list_ca_certs(char **arg, char reply[REPLY_MAX])
 {
-    return install_cert(arg[0]); /* move the certificate to keystore */
+    return list_ca_certs(reply);
 }
 
-static int do_remove_cert(char **arg, char reply[REPLY_MAX])
+static int do_install_user_cert(char **arg, char reply[REPLY_MAX])
 {
-    return remove_cert(arg[0]); /* certificate */
+    if (has_whitespace(arg[0])) return -1;
+    /* copy the certificate and key to keystore */
+    return install_user_cert(arg[0], arg[1], arg[2]);
 }
 
-static int do_install_userkey(char **arg, char reply[REPLY_MAX])
+static int do_install_p12_cert(char **arg, char reply[REPLY_MAX])
 {
-    return install_userkey(arg[0]); /* move the certificate to keystore */
+    if (has_whitespace(arg[0])) return -1;
+    return install_p12_cert(arg[0], arg[1]);
 }
 
-static int do_remove_userkey(char **arg, char reply[REPLY_MAX])
+static int do_install_ca_cert(char **arg, char reply[REPLY_MAX])
 {
-    return remove_userkey(arg[0]); /* userkey */
+    if (has_whitespace(arg[0])) return -1;
+    /* copy the certificate and key to keystore */
+    return install_ca_cert(arg[0], arg[1]);
 }
 
+static int do_add_ca_cert(char **arg, char reply[REPLY_MAX])
+{
+    if (has_whitespace(arg[0])) return -1;
+    return add_ca_cert(arg[0], arg[1]);
+}
+
+static int do_add_user_cert(char **arg, char reply[REPLY_MAX])
+{
+    if (has_whitespace(arg[0])) return -1;
+    return add_user_cert(arg[0], arg[1]);
+}
+
+static int do_add_user_key(char **arg, char reply[REPLY_MAX])
+{
+    if (has_whitespace(arg[0])) return -1;
+    return add_user_key(arg[0], arg[1]);
+}
+
+static int do_get_ca_cert(char **arg, char reply[REPLY_MAX])
+{
+    return get_ca_cert(arg[0], reply);
+}
+
+static int do_get_user_cert(char **arg, char reply[REPLY_MAX])
+{
+    return get_user_cert(arg[0], reply);
+}
+
+static int do_get_user_key(char **arg, char reply[REPLY_MAX])
+{
+    return get_user_key(arg[0], reply);
+}
+
+static int do_remove_user_cert(char **arg, char reply[REPLY_MAX])
+{
+    return remove_user_cert(arg[0]);
+}
+
+static int do_remove_ca_cert(char **arg, char reply[REPLY_MAX])
+{
+    return remove_ca_cert(arg[0]);
+}
+
+
 struct cmdinfo {
     const char *name;
     unsigned numargs;
@@ -55,12 +107,19 @@
 
 
 struct cmdinfo cmds[] = {
-    { "listcerts",            0, do_list_certs },
-    { "listuserkeys",         0, do_list_userkeys },
-    { "installcert",          1, do_install_cert },
-    { "removecert",           1, do_remove_cert },
-    { "installuserkey",       1, do_install_userkey },
-    { "removeuserkey",        1, do_remove_userkey },
+    { "listcacerts",        0, do_list_ca_certs },
+    { "listusercerts",      0, do_list_user_certs },
+    { "installusercert",    3, do_install_user_cert },
+    { "installcacert",      2, do_install_ca_cert },
+    { "installp12cert",     2, do_install_p12_cert },
+    { "addusercert",        2, do_add_user_cert },
+    { "adduserkey",         2, do_add_user_key },
+    { "addcacert",          2, do_add_ca_cert },
+    { "getusercert",        1, do_get_user_cert },
+    { "getuserkey",         1, do_get_user_key },
+    { "getcacert",          1, do_get_ca_cert },
+    { "removecacert",       1, do_remove_ca_cert },
+    { "removeusercert",     1, do_remove_user_cert },
 };
 
 static int readx(int s, void *_buf, int count)
@@ -121,7 +180,7 @@
     /* n is number of args (not counting arg[0]) */
     arg[0] = cmd;
     while (*cmd) {
-        if (isspace(*cmd)) {
+        if (*cmd == CMD_DELIMITER) {
             *cmd++ = 0;
             n++;
             arg[n] = cmd;
@@ -167,6 +226,7 @@
     int fd, i;
     short ret;
     unsigned short count;
+    char delimiter[2] = { CMD_DELIMITER, 0 };
     char buf[BUFFER_MAX]="";
 
     fd = socket_local_client(SOCKET_PATH,
@@ -177,7 +237,7 @@
         exit(1);
     }
     for(i = 0; i < argc; i++) {
-        if (i > 0) strlcat(buf, " ", BUFFER_MAX);
+        if (i > 0) strlcat(buf, delimiter, BUFFER_MAX);
         if(strlcat(buf, argv[i], BUFFER_MAX) >= BUFFER_MAX) {
             fprintf(stderr, "Arguments are too long\n");
             exit(1);
diff --git a/cmds/keystore/keystore.h b/cmds/keystore/keystore.h
index 35acf0b9..b9cb185 100644
--- a/cmds/keystore/keystore.h
+++ b/cmds/keystore/keystore.h
@@ -40,18 +40,35 @@
 /* path of the keystore */
 
 #define KEYSTORE_DIR_PREFIX "/data/misc/keystore"
-#define CERTS_DIR           KEYSTORE_DIR_PREFIX "/certs"
-#define USERKEYS_DIR         KEYSTORE_DIR_PREFIX "/userkeys"
+#define CERTS_DIR           KEYSTORE_DIR_PREFIX "/keys"
+#define CACERTS_DIR         KEYSTORE_DIR_PREFIX "/cacerts"
+#define CA_CERTIFICATE      "ca.crt"
+#define USER_CERTIFICATE    "user.crt"
+#define USER_P12_CERT       "user.p12"
+#define USER_KEY            "user.key"
+#define DOT                 "."
+#define DOTDOT              ".."
 
-#define BUFFER_MAX      1024  /* input buffer for commands */
+#define BUFFER_MAX      4096  /* input buffer for commands */
 #define TOKEN_MAX       8     /* max number of arguments in buffer */
-#define REPLY_MAX       1024  /* largest reply allowed */
+#define REPLY_MAX       4096  /* largest reply allowed */
+#define CMD_DELIMITER   '\t'
 #define KEYNAME_LENGTH  128
+#define IS_CONTENT      0
+#define IS_FILE         1
+
 
 /* commands.c */
-int list_certs(char reply[REPLY_MAX]);
-int list_userkeys(char reply[REPLY_MAX]);
-int install_cert(const char *certfile);
-int install_userkey(const char *keyfile);
-int remove_cert(const char *certfile);
-int remove_userkey(const char *keyfile);
+int list_ca_certs(char reply[REPLY_MAX]);
+int list_user_certs(char reply[REPLY_MAX]);
+int install_user_cert(const char *certname, const char *cert, const char *key);
+int install_ca_cert(const char *certname, const char *cert);
+int install_p12_cert(const char *certname, const char *cert);
+int add_ca_cert(const char *certname, const char *content);
+int add_user_cert(const char *certname, const char *content);
+int add_user_key(const char *keyname, const char *content);
+int get_ca_cert(const char *keyname, char reply[REPLY_MAX]);
+int get_user_cert(const char *keyname, char reply[REPLY_MAX]);
+int get_user_key(const char *keyname, char reply[REPLY_MAX]);
+int remove_user_cert(const char *certname);
+int remove_ca_cert(const char *certname);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 2fe6471..3676594 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3217,7 +3217,7 @@
                             r.activity.getComponentName().getClassName());
                     if (!r.activity.mCalled) {
                         throw new SuperNotCalledException(
-                            "Activity " + r.intent.getComponent().toShortString()
+                            "Activity " + safeToComponentShortString(r.intent)
                             + " did not call through to super.onPause()");
                     }
                 } catch (SuperNotCalledException e) {
@@ -3226,7 +3226,7 @@
                     if (!mInstrumentation.onException(r.activity, e)) {
                         throw new RuntimeException(
                                 "Unable to pause activity "
-                                + r.intent.getComponent().toShortString()
+                                + safeToComponentShortString(r.intent)
                                 + ": " + e.toString(), e);
                     }
                 }
@@ -3241,7 +3241,7 @@
                     if (!mInstrumentation.onException(r.activity, e)) {
                         throw new RuntimeException(
                                 "Unable to stop activity "
-                                + r.intent.getComponent().toShortString()
+                                + safeToComponentShortString(r.intent)
                                 + ": " + e.toString(), e);
                     }
                 }
@@ -3266,7 +3266,7 @@
                     if (!mInstrumentation.onException(r.activity, e)) {
                         throw new RuntimeException(
                                 "Unable to retain child activities "
-                                + r.intent.getComponent().toShortString()
+                                + safeToComponentShortString(r.intent)
                                 + ": " + e.toString(), e);
                     }
                 }
@@ -3277,7 +3277,7 @@
                 r.activity.onDestroy();
                 if (!r.activity.mCalled) {
                     throw new SuperNotCalledException(
-                        "Activity " + r.intent.getComponent().toShortString() +
+                        "Activity " + safeToComponentShortString(r.intent) +
                         " did not call through to super.onDestroy()");
                 }
                 if (r.window != null) {
@@ -3287,10 +3287,9 @@
                 throw e;
             } catch (Exception e) {
                 if (!mInstrumentation.onException(r.activity, e)) {
-                    ComponentName component = r.intent.getComponent();
-                    String name = component == null ? "[Unknown]" : component.toShortString();
                     throw new RuntimeException(
-                            "Unable to destroy activity " + name + ": " + e.toString(), e);
+                            "Unable to destroy activity " + safeToComponentShortString(r.intent)
+                            + ": " + e.toString(), e);
                 }
             }
         }
@@ -3299,6 +3298,11 @@
         return r;
     }
 
+    private static String safeToComponentShortString(Intent intent) {
+        ComponentName component = intent.getComponent();
+        return component == null ? "[Unknown]" : component.toShortString();
+    }
+
     private final void handleDestroyActivity(IBinder token, boolean finishing,
             int configChanges, boolean getNonConfigInstance) {
         ActivityRecord r = performDestroyActivity(token, finishing,
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 9141c4c..b6c8385 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -35,11 +35,6 @@
 import android.database.Cursor;
 import android.graphics.drawable.AnimationDrawable;
 import android.graphics.drawable.Drawable;
-import android.location.Criteria;
-import android.location.Location;
-import android.location.LocationListener;
-import android.location.LocationManager;
-import android.location.LocationProvider;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.SystemClock;
@@ -153,15 +148,6 @@
     private final WeakHashMap<String, Drawable> mOutsideDrawablesCache =
             new WeakHashMap<String, Drawable>();
     
-    // Objects we keep around for requesting location updates when the dialog is started
-    // (and canceling them when the dialog is stopped). We don't actually make use of the
-    // updates ourselves here, so the LocationListener is just a dummy which doesn't do
-    // anything. We only do this here so that other suggest providers which wish to provide
-    // location-based suggestions are more likely to get a good fresh location.
-    private LocationManager mLocationManager;
-    private LocationProvider mLocationProvider;
-    private LocationListener mDummyLocationListener;
-    
     /**
      * Constructor - fires it up and makes it look like the search UI.
      * 
@@ -240,37 +226,6 @@
         
         mVoiceAppSearchIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
         mVoiceAppSearchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        
-        mLocationManager =
-                (LocationManager) getContext().getSystemService(Context.LOCATION_SERVICE);
-        
-        if (mLocationManager != null) {
-            Criteria criteria = new Criteria();
-            criteria.setAccuracy(Criteria.ACCURACY_COARSE);
-    
-            String providerName = mLocationManager.getBestProvider(criteria, true);
-    
-            if (providerName != null) {
-                mLocationProvider = mLocationManager.getProvider(providerName);
-            }
-            
-            // Just a dumb listener that doesn't do anything - requesting location updates here
-            // is only intended to give location-based suggestion providers the best chance
-            // of getting a good fresh location.
-            mDummyLocationListener = new LocationListener() {
-                public void onLocationChanged(Location location) {                    
-                }
-
-                public void onProviderDisabled(String provider) {
-                }
-
-                public void onProviderEnabled(String provider) {
-                }
-
-                public void onStatusChanged(String provider, int status, Bundle extras) {
-                }
-            };
-        }
     }
 
     /**
@@ -423,8 +378,6 @@
         // receive broadcasts
         getContext().registerReceiver(mBroadcastReceiver, mCloseDialogsFilter);
         getContext().registerReceiver(mBroadcastReceiver, mPackageFilter);
-        
-        startLocationUpdates();
     }
 
     /**
@@ -437,8 +390,6 @@
     public void onStop() {
         super.onStop();
         
-        stopLocationUpdates();
-        
         // stop receiving broadcasts (throws exception if none registered)
         try {
             getContext().unregisterReceiver(mBroadcastReceiver);
@@ -456,26 +407,7 @@
         mUserQuery = null;
         mPreviousComponents = null;
     }
-    
-    /**
-     * Asks the LocationManager for location updates so that it goes and gets a fresh location
-     * if needed.
-     */
-    private void startLocationUpdates() {
-        if (mLocationManager != null && mLocationProvider != null) {
-            mLocationManager.requestLocationUpdates(mLocationProvider.getName(),
-                    0, 0, mDummyLocationListener, getContext().getMainLooper());
-        }
 
-    }
-    
-    /**
-     * Makes sure to stop listening for location updates to save battery.
-     */
-    private void stopLocationUpdates() {
-        mLocationManager.removeUpdates(mDummyLocationListener);
-    }
-    
     /**
      * Sets the search dialog to the 'working' state, which shows a working spinner in the
      * right hand size of the text field.
@@ -1168,7 +1100,7 @@
      */
     protected void launchQuerySearch(int actionKey, String actionMsg)  {
         String query = mSearchAutoComplete.getText().toString();
-        Intent intent = createIntent(Intent.ACTION_SEARCH, null, query, null,
+        Intent intent = createIntent(Intent.ACTION_SEARCH, null, null, query, null,
                 actionKey, actionMsg);
         launchIntent(intent);
     }
@@ -1238,8 +1170,8 @@
         // logic for falling back on the searchable default
         cv.put(SearchManager.SUGGEST_COLUMN_INTENT_ACTION, intent.getAction());
         cv.put(SearchManager.SUGGEST_COLUMN_INTENT_DATA, intent.getDataString());
-        cv.put(SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA,
-                        intent.getStringExtra(SearchManager.EXTRA_DATA_KEY));
+        cv.put(SearchManager.SUGGEST_COLUMN_INTENT_COMPONENT_NAME,
+                        intent.getStringExtra(SearchManager.COMPONENT_NAME_KEY));
 
         // ensure the icons will work for global search
         cv.put(SearchManager.SUGGEST_COLUMN_ICON_1,
@@ -1467,11 +1399,14 @@
             }
             Uri dataUri = (data == null) ? null : Uri.parse(data);
 
-            String extraData = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA);
+            String componentName = getColumnString(
+                    c, SearchManager.SUGGEST_COLUMN_INTENT_COMPONENT_NAME);
 
             String query = getColumnString(c, SearchManager.SUGGEST_COLUMN_QUERY);
+            String extraData = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA);
 
-            return createIntent(action, dataUri, query, extraData, actionKey, actionMsg);
+            return createIntent(action, dataUri, extraData, query, componentName, actionKey,
+                    actionMsg);
         } catch (RuntimeException e ) {
             int rowNum;
             try {                       // be really paranoid now
@@ -1490,16 +1425,17 @@
      * 
      * @param action Intent action.
      * @param data Intent data, or <code>null</code>.
-     * @param query Intent query, or <code>null</code>.
      * @param extraData Data for {@link SearchManager#EXTRA_DATA_KEY} or <code>null</code>.
+     * @param query Intent query, or <code>null</code>.
+     * @param componentName Data for {@link SearchManager#COMPONENT_NAME_KEY} or <code>null</code>.
      * @param actionKey The key code of the action key that was pressed,
      *        or {@link KeyEvent#KEYCODE_UNKNOWN} if none.
      * @param actionMsg The message for the action key that was pressed,
      *        or <code>null</code> if none.
      * @return The intent.
      */
-    private Intent createIntent(String action, Uri data, String query, String extraData,
-            int actionKey, String actionMsg) {
+    private Intent createIntent(String action, Uri data, String extraData, String query,
+            String componentName, int actionKey, String actionMsg) {
         // Now build the Intent
         Intent intent = new Intent(action);
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -1512,6 +1448,9 @@
         if (extraData != null) {
             intent.putExtra(SearchManager.EXTRA_DATA_KEY, extraData);
         }
+        if (componentName != null) {
+            intent.putExtra(SearchManager.COMPONENT_NAME_KEY, componentName);
+        }
         if (mAppSearchData != null) {
             intent.putExtra(SearchManager.APP_DATA, mAppSearchData);
         }
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 1ddd20a..eb80400 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -1165,6 +1165,14 @@
     public final static String ACTION_KEY = "action_key";
     
     /**
+     * Intent component name key: This key will be used for the extra populated by the
+     * {@link #SUGGEST_COLUMN_INTENT_COMPONENT_NAME} column.
+     *
+     * {@hide}
+     */
+    public final static String COMPONENT_NAME_KEY = "intent_component_name_key";
+
+    /**
      * Intent extra data key: This key will be used for the extra populated by the
      * {@link #SUGGEST_COLUMN_INTENT_EXTRA_DATA} column.
      *
@@ -1364,14 +1372,24 @@
      */
     public final static String SUGGEST_COLUMN_INTENT_DATA = "suggest_intent_data";
     /**
+     * Column name for suggestions cursor.  <i>Optional.</i>  If this column exists <i>and</i>
+     * this element exists at the given row, this is the data that will be used when
+     * forming the suggestion's intent. If not provided, the Intent's extra data field will be null.
+     * This column allows suggestions to provide additional arbitrary data which will be included as
+     * an extra under the key EXTRA_DATA_KEY.
+     *
+     * @hide Pending API council approval.
+     */
+    public final static String SUGGEST_COLUMN_INTENT_EXTRA_DATA = "suggest_intent_extra_data";
+    /**
      * Column name for suggestions cursor.  <i>Optional.</i>  This column allows suggestions
      *  to provide additional arbitrary data which will be included as an extra under the key
-     *  {@link #EXTRA_DATA_KEY}. For use by the global search system only - if other providers
+     *  {@link #COMPONENT_NAME_KEY}. For use by the global search system only - if other providers
      *  attempt to use this column, the value will be overwritten by global search.
      *
      * @hide
      */
-    public final static String SUGGEST_COLUMN_INTENT_EXTRA_DATA = "suggest_intent_extra_data";
+    public final static String SUGGEST_COLUMN_INTENT_COMPONENT_NAME = "suggest_intent_component";
     /**
      * Column name for suggestions cursor.  <i>Optional.</i>  If this column exists <i>and</i>
      * this element exists at the given row, then "/" and this value will be appended to the data
diff --git a/core/java/android/backup/BackupDataInput.java b/core/java/android/backup/BackupDataInput.java
index 609dd90..69c206c 100644
--- a/core/java/android/backup/BackupDataInput.java
+++ b/core/java/android/backup/BackupDataInput.java
@@ -82,9 +82,9 @@
         }
     }
 
-    public int readEntityData(byte[] data, int size) throws IOException {
+    public int readEntityData(byte[] data, int offset, int size) throws IOException {
         if (mHeaderReady) {
-            int result = readEntityData_native(mBackupReader, data, size);
+            int result = readEntityData_native(mBackupReader, data, offset, size);
             if (result >= 0) {
                 return result;
             } else {
@@ -95,9 +95,23 @@
         }
     }
 
+    public void skipEntityData() throws IOException {
+        if (mHeaderReady) {
+            int result = skipEntityData_native(mBackupReader);
+            if (result >= 0) {
+                return;
+            } else {
+                throw new IOException("result=0x" + Integer.toHexString(result));
+            }
+        } else {
+            throw new IllegalStateException("mHeaderReady=false");
+        }
+    }
+
     private native static int ctor(FileDescriptor fd);
     private native static void dtor(int mBackupReader);
 
     private native int readNextHeader_native(int mBackupReader, EntityHeader entity);
-    private native int readEntityData_native(int mBackupReader, byte[] data, int size);
+    private native int readEntityData_native(int mBackupReader, byte[] data, int offset, int size);
+    private native int skipEntityData_native(int mBackupReader);
 }
diff --git a/core/java/android/backup/BackupDataInputStream.java b/core/java/android/backup/BackupDataInputStream.java
new file mode 100644
index 0000000..52b1675
--- /dev/null
+++ b/core/java/android/backup/BackupDataInputStream.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.backup;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+/** @hide */
+public class BackupDataInputStream extends InputStream {
+
+    String key;
+    int dataSize;
+
+    BackupDataInput mData;
+    byte[] mOneByte;
+
+    BackupDataInputStream(BackupDataInput data) {
+        mData = data;
+    }
+
+    public int read() throws IOException {
+        byte[] one = mOneByte;
+        if (mOneByte == null) {
+            one = mOneByte = new byte[1];
+        }
+        mData.readEntityData(one, 0, 1);
+        return one[0];
+    }
+
+    public int read(byte[] b, int offset, int size) throws IOException {
+        return mData.readEntityData(b, offset, size);
+    }
+
+    public int read(byte[] b) throws IOException {
+        return mData.readEntityData(b, 0, b.length);
+    }
+
+    public String getKey() {
+        return this.key;
+    }
+    
+    public int size() {
+        return this.dataSize;
+    }
+}
+
+
diff --git a/core/java/android/backup/RestoreHelper.java b/core/java/android/backup/RestoreHelper.java
index ebd9906e..ee8bedd 100644
--- a/core/java/android/backup/RestoreHelper.java
+++ b/core/java/android/backup/RestoreHelper.java
@@ -16,8 +16,16 @@
 
 package android.backup;
 
+import java.io.InputStream;
+
 /** @hide */
 public interface RestoreHelper {
-    public void performRestore();
+    /**
+     * Called by RestoreHelperDispatcher to dispatch one entity of data.
+     * <p class=note>
+     * Do not close the <code>data</code> stream.  Do not read more than
+     * <code>dataSize</code> bytes from <code>data</code>.
+     */
+    public void performRestore(BackupDataInputStream data);
 }
 
diff --git a/core/java/android/backup/RestoreHelperDispatcher.java b/core/java/android/backup/RestoreHelperDispatcher.java
new file mode 100644
index 0000000..cbfefdc
--- /dev/null
+++ b/core/java/android/backup/RestoreHelperDispatcher.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.backup;
+
+import java.io.IOException;
+import java.util.HashMap;
+
+/** @hide */
+public class RestoreHelperDispatcher {
+    HashMap<String,RestoreHelper> mHelpers;
+
+    public void addHelper(String keyPrefix, RestoreHelper helper) {
+        mHelpers.put(keyPrefix, helper);
+    }
+
+    public void dispatch(BackupDataInput input) throws IOException {
+        BackupDataInputStream stream = new BackupDataInputStream(input);
+        while (input.readNextHeader()) {
+            String rawKey = input.getKey();
+            int pos = rawKey.indexOf(':');
+            if (pos > 0) {
+                String prefix = rawKey.substring(0, pos);
+                RestoreHelper helper = mHelpers.get(prefix);
+                if (helper != null) {
+                    stream.dataSize = input.getDataSize();
+                    stream.key = rawKey.substring(pos+1);
+                    helper.performRestore(stream);
+                }
+            }
+            input.skipEntityData(); // In case they didn't consume the data.
+        }
+    }
+}
diff --git a/core/java/android/backup/RestoreHelperDistributor.java b/core/java/android/backup/RestoreHelperDistributor.java
deleted file mode 100644
index 555ca79..0000000
--- a/core/java/android/backup/RestoreHelperDistributor.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.backup;
-
-import java.util.HashMap;
-
-/** @hide */
-public class RestoreHelperDistributor {
-    HashMap<String,RestoreHelper> mHelpers;
-
-    public void addHelper(String keyPrefix, RestoreHelper helper) {
-        mHelpers.put(keyPrefix, helper);
-    }
-}
diff --git a/core/java/android/gesture/GestureOverlayView.java b/core/java/android/gesture/GestureOverlayView.java
index 14323b8..5bfdcc4 100755
--- a/core/java/android/gesture/GestureOverlayView.java
+++ b/core/java/android/gesture/GestureOverlayView.java
@@ -84,7 +84,7 @@
 
     private final Rect mInvalidRect = new Rect();
     private final Path mPath = new Path();
-    private boolean mGestureVisible;
+    private boolean mGestureVisible = true;
 
     private float mX;
     private float mY;
diff --git a/core/java/android/speech/tts/ITts.aidl b/core/java/android/speech/tts/ITts.aidl
index 739a8e4..02211fd 100755
--- a/core/java/android/speech/tts/ITts.aidl
+++ b/core/java/android/speech/tts/ITts.aidl
@@ -39,7 +39,7 @@
 

     void addSpeechFile(in String text, in String filename);

 

-    void setLanguage(in String language);

+    void setLanguage(in String language, in String country, in String variant);

 

     boolean synthesizeToFile(in String text, in String[] params, in String outputDirectory);

 

diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index 2c0c09e..8f58194 100755
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -22,13 +22,12 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Log;
 
 import java.util.HashMap;
+import java.util.Locale;
 
 /**
  *
@@ -36,7 +35,7 @@
  *
  * {@hide}
  */
-//TODO #TTS# review + complete javadoc
+//TODO #TTS# review + complete javadoc + add links to constants
 public class TextToSpeech {
 
     /**
@@ -52,9 +51,18 @@
      */
     public static final int TTS_ERROR_MISSING_RESOURCE = -2;
 
+    /**
+     * Queue mode where all entries in the playback queue (media to be played
+     * and text to be synthesized) are dropped and replaced by the new entry.
+     */
+    public static final int TTS_QUEUE_FLUSH = 0;
+    /**
+     * Queue mode where the new entry is added at the end of the playback queue.
+     */
+    public static final int TTS_QUEUE_ADD = 1;
 
     /**
-     * Called when the TTS has initialized
+     * Called when the TTS has initialized.
      *
      * The InitListener must implement the onInit function. onInit is passed a
      * status code indicating the result of the TTS initialization.
@@ -73,9 +81,9 @@
     }
 
     /**
-     * Connection needed for the TTS
+     * Connection needed for the TTS.
      */
-    private ServiceConnection serviceConnection;
+    private ServiceConnection mServiceConnection;
 
     private ITts mITts = null;
     private Context mContext = null;
@@ -104,8 +112,7 @@
     }
 
 
-    public void setOnSpeechCompletedListener(
-            final OnSpeechCompletedListener listener) {
+    public void setOnSpeechCompletedListener(final OnSpeechCompletedListener listener) {
         synchronized(mSpeechCompListenerLock) {
             mSpeechCompListener = listener;
         }
@@ -126,7 +133,7 @@
         mStarted = false;
 
         // Initialize the TTS, run the callback after the binding is successful
-        serviceConnection = new ServiceConnection() {
+        mServiceConnection = new ServiceConnection() {
             public void onServiceConnected(ComponentName name, IBinder service) {
                 synchronized(mStartLock) {
                     mITts = ITts.Stub.asInterface(service);
@@ -176,7 +183,7 @@
 
         Intent intent = new Intent("android.intent.action.USE_TTS");
         intent.addCategory("android.intent.category.TTS");
-        mContext.bindService(intent, serviceConnection,
+        mContext.bindService(intent, mServiceConnection,
                 Context.BIND_AUTO_CREATE);
         // TODO handle case where the binding works (should always work) but
         //      the plugin fails
@@ -190,7 +197,7 @@
      */
     public void shutdown() {
         try {
-            mContext.unbindService(serviceConnection);
+            mContext.unbindService(mServiceConnection);
         } catch (IllegalArgumentException e) {
             // Do nothing and fail silently since an error here indicates that
             // binding never succeeded in the first place.
@@ -291,8 +298,8 @@
      * @param text
      *            The string of text to be spoken.
      * @param queueMode
-     *            The queuing strategy to use. Use 0 for no queuing, and 1 for
-     *            queuing.
+     *            The queuing strategy to use.
+     *            See TTS_QUEUE_ADD and TTS_QUEUE_FLUSH.
      * @param params
      *            The hashmap of speech parameters to be used.
      */
@@ -329,12 +336,11 @@
      * @param earcon
      *            The earcon that should be played
      * @param queueMode
-     *            0 for no queue (interrupts all previous utterances), 1 for
-     *            queued
+     *            See TTS_QUEUE_ADD and TTS_QUEUE_FLUSH.
      * @param params
      *            The hashmap of parameters to be used.
      */
-    public void playEarcon(String earcon, int queueMode, 
+    public void playEarcon(String earcon, int queueMode,
             HashMap<String,String> params) {
         synchronized (mStartLock) {
             if (!mStarted) {
@@ -358,8 +364,8 @@
             }
         }
     }
-    
-    
+
+
     public void playSilence(long durationInMs, int queueMode) {
         // TODO implement, already present in TTS service
     }
@@ -429,20 +435,22 @@
      * Note that the speech rate is not universally supported by all engines and
      * will be treated as a hint. The TTS library will try to use the specified
      * speech rate, but there is no guarantee.
-     *
-     * Currently, this will change the speech rate for the espeak engine, but it
-     * has no effect on any pre-recorded speech.
+     * This has no effect on any pre-recorded speech.
      *
      * @param speechRate
-     *            The speech rate for the TTS engine.
+     *            The speech rate for the TTS engine. 1 is the normal speed,
+     *            lower values slow down the speech (0.5 is half the normal speech rate),
+     *            greater values accelerate it (2 is twice the normal speech rate).
      */
-    public void setSpeechRate(int speechRate) {
+    public void setSpeechRate(float speechRate) {
         synchronized (mStartLock) {
             if (!mStarted) {
                 return;
             }
             try {
-                mITts.setSpeechRate(speechRate);
+                if (speechRate > 0) {
+                    mITts.setSpeechRate((int)(speechRate*100));
+                }
             } catch (RemoteException e) {
                 // TTS died; restart it.
                 mStarted = false;
@@ -457,24 +465,18 @@
      *
      * Note that the language is not universally supported by all engines and
      * will be treated as a hint. The TTS library will try to use the specified
-     * language, but there is no guarantee.
+     * language as represented by the Locale, but there is no guarantee.
      *
-     * Currently, this will change the language for the espeak engine, but it
-     * has no effect on any pre-recorded speech.
-     *
-     * @param language
-     *            The language to be used. The languages are specified by their
-     *            IETF language tags as defined by BCP 47. This is the same
-     *            standard used for the lang attribute in HTML. See:
-     *            http://en.wikipedia.org/wiki/IETF_language_tag
+     * @param loc
+     *            The locale describing the language to be used.
      */
-    public void setLanguage(String language) {
+    public void setLanguage(Locale loc) {
         synchronized (mStartLock) {
             if (!mStarted) {
                 return;
             }
             try {
-                mITts.setLanguage(language);
+                mITts.setLanguage(loc.getISO3Language(), loc.getISO3Country(), loc.getVariant());
             } catch (RemoteException e) {
                 // TTS died; restart it.
                 mStarted = false;
diff --git a/core/java/com/android/internal/backup/IBackupTransport.aidl b/core/java/com/android/internal/backup/IBackupTransport.aidl
index 9daabca..84ed729 100644
--- a/core/java/com/android/internal/backup/IBackupTransport.aidl
+++ b/core/java/com/android/internal/backup/IBackupTransport.aidl
@@ -42,11 +42,14 @@
 */
     /**
      * Verify that this is a suitable time for a backup pass.  This should return zero
-     * if a backup is reasonable right now, false otherwise.  This method will be called
-     * outside of the {@link #startSession}/{@link #endSession} pair.
+     * if a backup is reasonable right now, some positive value otherwise.  This method
+     * will be called outside of the {@link #startSession}/{@link #endSession} pair.
      *
-     * <p>If this is not a suitable time for a backup, the transport should suggest a
+     * <p>If this is not a suitable time for a backup, the transport should return a
      * backoff delay, in milliseconds, after which the Backup Manager should try again.
+     *
+     * @return Zero if this is a suitable time for a backup pass, or a positive time delay
+     *   in milliseconds to suggest deferring the backup pass for a while.
      */
     long requestBackupTime();
 
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java
index 5da0883..123c072 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/core/java/com/android/internal/backup/LocalTransport.java
@@ -84,7 +84,7 @@
                     bufSize = dataSize;
                     buf = new byte[bufSize];
                 }
-                changeSet.readEntityData(buf, dataSize);
+                changeSet.readEntityData(buf, 0, dataSize);
                 if (DEBUG) Log.v(TAG, "  + data size " + dataSize);
 
                 File entityFile = new File(packageDir, key);
diff --git a/core/jni/android_backup_BackupDataInput.cpp b/core/jni/android_backup_BackupDataInput.cpp
index 5b2fb73..cf8a8e8 100644
--- a/core/jni/android_backup_BackupDataInput.cpp
+++ b/core/jni/android_backup_BackupDataInput.cpp
@@ -55,18 +55,13 @@
 readNextHeader_native(JNIEnv* env, jobject clazz, int r, jobject entity)
 {
     int err;
+    bool done;
     BackupDataReader* reader = (BackupDataReader*)r;
 
-    err = reader->Status();
-    if (err != 0) {
-        return err < 0 ? err : -1;
-    }
-
     int type = 0;
 
-    err = reader->ReadNextHeader(&type);
-    if (err == EIO) {
-        // Clean EOF with no footer block; just claim we're done
+    err = reader->ReadNextHeader(&done, &type);
+    if (done) {
         return 1;
     }
 
@@ -75,24 +70,12 @@
     }
 
     switch (type) {
-    case BACKUP_HEADER_APP_V1:
-    {
-        String8 packageName;
-        int cookie;
-        err = reader->ReadAppHeader(&packageName, &cookie);
-        if (err != 0) {
-            LOGD("ReadAppHeader() returned %d; aborting", err);
-            return err < 0 ? err : -1;
-        }
-        break;
-    }
     case BACKUP_HEADER_ENTITY_V1:
     {
         String8 key;
         size_t dataSize;
         err = reader->ReadEntityHeader(&key, &dataSize);
         if (err != 0) {
-            LOGD("ReadEntityHeader(); aborting", err);
             return err < 0 ? err : -1;
         }
         // TODO: Set the fields in the entity object
@@ -101,10 +84,6 @@
         env->SetIntField(entity, s_dataSizeField, dataSize);
         return 0;
     }
-    case BACKUP_FOOTER_APP_V1:
-    {
-        break;
-    }
     default:
         LOGD("Unknown header type: 0x%08x\n", type);
         return -1;
@@ -115,12 +94,12 @@
 }
 
 static jint
-readEntityData_native(JNIEnv* env, jobject clazz, int r, jbyteArray data, int size)
+readEntityData_native(JNIEnv* env, jobject clazz, int r, jbyteArray data, int offset, int size)
 {
     int err;
     BackupDataReader* reader = (BackupDataReader*)r;
 
-    if (env->GetArrayLength(data) < size) {
+    if (env->GetArrayLength(data) < (size+offset)) {
         // size mismatch
         return -1;
     }
@@ -130,19 +109,31 @@
         return -2;
     }
 
-    err = reader->ReadEntityData(dataBytes, size);
+    err = reader->ReadEntityData(dataBytes+offset, size);
 
     env->ReleaseByteArrayElements(data, dataBytes, 0);
 
     return err;
 }
 
+static jint
+skipEntityData_native(JNIEnv* env, jobject clazz, int r)
+{
+    int err;
+    BackupDataReader* reader = (BackupDataReader*)r;
+
+    err = reader->SkipEntityData();
+
+    return err;
+}
+
 static const JNINativeMethod g_methods[] = {
     { "ctor", "(Ljava/io/FileDescriptor;)I", (void*)ctor_native },
     { "dtor", "(I)V", (void*)dtor_native },
     { "readNextHeader_native", "(ILandroid/backup/BackupDataInput$EntityHeader;)I",
             (void*)readNextHeader_native },
-    { "readEntityData_native", "(I[BI)I", (void*)readEntityData_native },
+    { "readEntityData_native", "(I[BII)I", (void*)readEntityData_native },
+    { "skipEntityData_native", "(I)I", (void*)skipEntityData_native },
 };
 
 int register_android_backup_BackupDataInput(JNIEnv* env)
diff --git a/core/res/res/layout/recent_apps_dialog.xml b/core/res/res/layout/recent_apps_dialog.xml
index 852b2f1..c4ee95d 100644
--- a/core/res/res/layout/recent_apps_dialog.xml
+++ b/core/res/res/layout/recent_apps_dialog.xml
@@ -17,67 +17,63 @@
 */
 -->
 
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="fill_parent"
-    android:layout_height="wrap_content">
-    
+    android:layout_height="wrap_content"
+    android:padding="3dip"
+    android:orientation="vertical">
+
+    <!-- This is only intended to be visible when all buttons (below) are invisible -->
+    <TextView
+        android:id="@+id/no_applications_message"
+        android:layout_width="285dip"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="15dip"
+        android:layout_marginBottom="15dip"
+        android:gravity="center"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:text="@android:string/no_recent_tasks" />
+
+    <!-- The first row has a fixed-width because the UI spec requires the box
+         to display with full-width no matter how many icons are visible, but to
+         adjust height based on number of rows. -->
+    <!-- TODO Adjust all sizes, padding, etc. to meet pixel-perfect specs -->
+    <LinearLayout
+        android:layout_width="285dip"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal" >
+
+        <include
+            layout="@android:layout/recent_apps_icon"
+            android:id="@+id/button1" />
+
+        <include
+            layout="@android:layout/recent_apps_icon"
+            android:id="@+id/button2" />
+
+        <include
+            layout="@android:layout/recent_apps_icon"
+            android:id="@+id/button3" />
+
+    </LinearLayout>
+
     <LinearLayout
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:padding="3dip"
-        android:orientation="vertical">
-        
-        <!-- This is only intended to be visible when all buttons (below) are invisible -->
-        <TextView
-            android:id="@+id/no_applications_message"
-            android:layout_width="285dip"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="15dip"
-            android:layout_marginBottom="15dip"
-            android:gravity="center"
-            android:textAppearance="?android:attr/textAppearanceMedium"
-            android:text="@android:string/no_recent_tasks" />
-    
-        <!-- The first row has a fixed-width because the UI spec requires the box
-             to display with full-width no matter how many icons are visible, but to
-             adjust height based on number of rows. -->
-        <!-- TODO Adjust all sizes, padding, etc. to meet pixel-perfect specs -->
-        <LinearLayout
-            android:layout_width="285dip"
-            android:layout_height="wrap_content"
-            android:orientation="horizontal" >
+        android:orientation="horizontal" >
 
-            <include
-                layout="@android:layout/recent_apps_icon"
-                android:id="@+id/button1" />
-    
-            <include
-                layout="@android:layout/recent_apps_icon"
-                android:id="@+id/button2" />
-    
-            <include
-                layout="@android:layout/recent_apps_icon"
-                android:id="@+id/button3" />
-    
-        </LinearLayout>
-        
-        <LinearLayout
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:orientation="horizontal" >
-            
-            <include
-                layout="@android:layout/recent_apps_icon"
-                android:id="@+id/button4" />
-            
-            <include
-                layout="@android:layout/recent_apps_icon"
-                android:id="@+id/button5" />
-            
-            <include
-                layout="@android:layout/recent_apps_icon"
-                android:id="@+id/button6" />
-                
-        </LinearLayout>    
+        <include
+            layout="@android:layout/recent_apps_icon"
+            android:id="@+id/button4" />
+
+        <include
+            layout="@android:layout/recent_apps_icon"
+            android:id="@+id/button5" />
+
+        <include
+            layout="@android:layout/recent_apps_icon"
+            android:id="@+id/button6" />
+
     </LinearLayout>
-</FrameLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/core/res/res/layout/recent_apps_icon.xml b/core/res/res/layout/recent_apps_icon.xml
index b8cf089..d32643c 100644
--- a/core/res/res/layout/recent_apps_icon.xml
+++ b/core/res/res/layout/recent_apps_icon.xml
@@ -18,27 +18,22 @@
 -->
 
 <!-- This is not a standalone element - it is imported into recent_apps_dialog.xml -->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="87dip"
-    android:layout_height="78dip"
-    android:layout_margin="3dip"
-    android:orientation="vertical"
-    android:gravity="center_vertical"
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/label"
     style="?android:attr/buttonStyle"
-    android:background="@drawable/btn_application_selector">
-    <ImageView android:id="@+id/icon"
-        android:layout_width="@android:dimen/app_icon_size"
-        android:layout_height="@android:dimen/app_icon_size"
-        android:layout_gravity="center_horizontal"
-        android:scaleType="fitCenter" />
-    <TextView android:id="@+id/label"
-        android:layout_width="fill_parent"
-        android:layout_height="wrap_content"
-        android:textSize="12dip"
-        android:maxLines="1"
-        android:ellipsize="end"
-        android:duplicateParentState="true"
-        android:textColor="@color/primary_text_dark_focused"
-        android:gravity="center_horizontal" />
-</LinearLayout>
+    android:background="@drawable/btn_application_selector"
+    android:layout_width="87dip"
+    android:layout_height="88dip"
+    android:layout_margin="3dip"
+    android:textColor="@color/primary_text_dark_focused"
+
+    android:paddingTop="5dip"
+    android:paddingBottom="2dip"
+    android:drawablePadding="0dip"
+
+    android:textSize="13dip"
+    android:maxLines="2"
+    android:ellipsize="marquee"
+    android:fadingEdge="horizontal"
+    android:gravity="top|center_horizontal" />
diff --git a/include/utils/BackupHelpers.h b/include/utils/BackupHelpers.h
index f60f4ea..3ca8ad2 100644
--- a/include/utils/BackupHelpers.h
+++ b/include/utils/BackupHelpers.h
@@ -23,30 +23,15 @@
 namespace android {
 
 enum {
-    BACKUP_HEADER_APP_V1 = 0x31707041, // App1 (little endian)
     BACKUP_HEADER_ENTITY_V1 = 0x61746144, // Data (little endian)
-    BACKUP_FOOTER_APP_V1 = 0x746f6f46, // Foot (little endian)
 };
 
-// the sizes of all of these match.
-typedef struct {
-    int type; // == BACKUP_HEADER_APP_V1
-    int packageLen; // length of the name of the package that follows, not including the null.
-    int cookie;
-} app_header_v1;
-
 typedef struct {
     int type; // BACKUP_HEADER_ENTITY_V1
     int keyLen; // length of the key name, not including the null terminator
     int dataSize; // size of the data, not including the padding, -1 means delete
 } entity_header_v1;
 
-typedef struct {
-    int type; // BACKUP_FOOTER_APP_V1
-    int entityCount; // the number of entities that were written
-    int cookie;
-} app_footer_v1;
-
 
 /**
  * Writes the data.
@@ -61,13 +46,9 @@
     // does not close fd
     ~BackupDataWriter();
 
-    status_t WriteAppHeader(const String8& packageName, int cookie);
-
     status_t WriteEntityHeader(const String8& key, size_t dataSize);
     status_t WriteEntityData(const void* data, size_t size);
 
-    status_t WriteAppFooter(int cookie);
-
 private:
     explicit BackupDataWriter();
     status_t write_padding_for(int n);
@@ -92,28 +73,26 @@
     ~BackupDataReader();
 
     status_t Status();
-    status_t ReadNextHeader(int* type = NULL);
+    status_t ReadNextHeader(bool* done, int* type);
 
-    status_t ReadAppHeader(String8* packageName, int* cookie);
     bool HasEntities();
     status_t ReadEntityHeader(String8* key, size_t* dataSize);
     status_t SkipEntityData(); // must be called with the pointer at the begining of the data.
     status_t ReadEntityData(void* data, size_t size);
-    status_t ReadAppFooter(int* cookie);
 
 private:
     explicit BackupDataReader();
     status_t skip_padding();
     
     int m_fd;
+    bool m_done;
     status_t m_status;
     ssize_t m_pos;
+    ssize_t m_dataEndPos;
     int m_entityCount;
     union {
         int type;
-        app_header_v1 app;
         entity_header_v1 entity;
-        app_footer_v1 footer;
     } m_header;
 };
 
diff --git a/keystore/java/android/security/Keystore.java b/keystore/java/android/security/Keystore.java
index 71c1cf4..ce3fa88 100644
--- a/keystore/java/android/security/Keystore.java
+++ b/keystore/java/android/security/Keystore.java
@@ -30,6 +30,7 @@
         return new FileKeystore();
     }
 
+    // for compatiblity, start from here
     /**
      */
     public abstract String getUserkey(String key);
@@ -46,6 +47,34 @@
      */
     public abstract String[] getAllUserkeyKeys();
 
+    // to here
+
+    /**
+     */
+    public abstract String getCaCertificate(String key);
+
+    /**
+     */
+    public abstract String getUserCertificate(String key);
+
+    /**
+     */
+    public abstract String getUserPrivateKey(String key);
+
+    /**
+     * Returns the array of the certificate keynames in keystore if successful.
+     * Or return an empty array if error.
+     *
+     * @return array of the certificate keynames
+     */
+    public abstract String[] getAllUserCertificateKeys();
+
+    /**
+     */
+    public abstract String[] getAllCaCertificateKeys();
+
+    /**
+     */
     public abstract String[] getSupportedKeyStrenghs();
 
     /**
@@ -63,13 +92,25 @@
 
     private static class FileKeystore extends Keystore {
         private static final String SERVICE_NAME = "keystore";
+        private static final String LIST_CA_CERTIFICATES = "listcacerts";
+        private static final String LIST_USER_CERTIFICATES = "listusercerts";
+        private static final String GET_CA_CERTIFICATE = "getcacert";
+        private static final String GET_USER_CERTIFICATE = "getusercert";
+        private static final String GET_USER_KEY = "getuserkey";
+        private static final String ADD_CA_CERTIFICATE = "addcacert";
+        private static final String ADD_USER_CERTIFICATE = "addusercert";
+        private static final String ADD_USER_KEY = "adduserkey";
+        private static final String COMMAND_DELIMITER = "\t";
+        private static final ServiceCommand mServiceCommand =
+                new ServiceCommand(SERVICE_NAME);
+
+        // for compatiblity, start from here
+
         private static final String LIST_CERTIFICATES = "listcerts";
         private static final String LIST_USERKEYS = "listuserkeys";
         private static final String PATH = "/data/misc/keystore/";
         private static final String USERKEY_PATH = PATH + "userkeys/";
         private static final String CERT_PATH = PATH + "certs/";
-        private static final ServiceCommand mServiceCommand =
-                new ServiceCommand(SERVICE_NAME);
 
         @Override
         public String getUserkey(String key) {
@@ -81,12 +122,6 @@
             return CERT_PATH + key;
         }
 
-        /**
-         * Returns the array of the certificate names in keystore if successful.
-         * Or return an empty array if error.
-         *
-         * @return array of the certificates
-         */
         @Override
         public String[] getAllCertificateKeys() {
             try {
@@ -98,12 +133,6 @@
             }
         }
 
-        /**
-         * Returns the array of the names of private keys in keystore if successful.
-         * Or return an empty array if errors.
-         *
-         * @return array of the user keys
-         */
         @Override
         public String[] getAllUserkeyKeys() {
             try {
@@ -115,6 +144,48 @@
             }
         }
 
+        // to here
+
+        @Override
+        public String getUserPrivateKey(String key) {
+            return mServiceCommand.execute(
+                    GET_USER_KEY + COMMAND_DELIMITER + key);
+        }
+
+        @Override
+        public String getUserCertificate(String key) {
+            return mServiceCommand.execute(
+                    GET_USER_CERTIFICATE + COMMAND_DELIMITER + key);
+        }
+
+        @Override
+        public String getCaCertificate(String key) {
+            return mServiceCommand.execute(
+                    GET_CA_CERTIFICATE + COMMAND_DELIMITER + key);
+        }
+
+        @Override
+        public String[] getAllUserCertificateKeys() {
+            try {
+                String result = mServiceCommand.execute(LIST_USER_CERTIFICATES);
+                if (result != null) return result.split("\\s+");
+                return NOTFOUND;
+            } catch (NumberFormatException ex) {
+                return NOTFOUND;
+            }
+        }
+
+        @Override
+        public String[] getAllCaCertificateKeys() {
+            try {
+                String result = mServiceCommand.execute(LIST_CA_CERTIFICATES);
+                if (result != null) return result.split("\\s+");
+                return NOTFOUND;
+            } catch (NumberFormatException ex) {
+                return NOTFOUND;
+            }
+        }
+
         @Override
         public String[] getSupportedKeyStrenghs() {
             // TODO: real implementation
@@ -149,5 +220,26 @@
         public void addCertificate(String cert) {
             // TODO: real implementation
         }
+
+        private boolean addUserCertificate(String key, String certificate,
+                String privateKey) {
+            if(mServiceCommand.execute(ADD_USER_CERTIFICATE + COMMAND_DELIMITER
+                    + key + COMMAND_DELIMITER + certificate) != null) {
+                if (mServiceCommand.execute(ADD_USER_KEY + COMMAND_DELIMITER
+                        + key + COMMAND_DELIMITER + privateKey) != null) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        private boolean addCaCertificate(String key, String content) {
+            if (mServiceCommand.execute(ADD_CA_CERTIFICATE + COMMAND_DELIMITER
+                    + key + COMMAND_DELIMITER + content) != null) {
+                return true;
+            }
+            return false;
+        }
+
     }
 }
diff --git a/libs/utils/BackupData.cpp b/libs/utils/BackupData.cpp
index 8c9f875..16ff1e5 100644
--- a/libs/utils/BackupData.cpp
+++ b/libs/utils/BackupData.cpp
@@ -86,46 +86,6 @@
 }
 
 status_t
-BackupDataWriter::WriteAppHeader(const String8& packageName, int cookie)
-{
-    if (m_status != NO_ERROR) {
-        return m_status;
-    }
-
-    ssize_t amt;
-
-    amt = write_padding_for(m_pos);
-    if (amt != 0) {
-        return amt;
-    }
-
-    app_header_v1 header;
-    ssize_t nameLen;
-
-    nameLen = packageName.length();
-
-    header.type = tolel(BACKUP_HEADER_APP_V1);
-    header.packageLen = tolel(nameLen);
-    header.cookie = cookie;
-
-    amt = write(m_fd, &header, sizeof(app_header_v1));
-    if (amt != sizeof(app_header_v1)) {
-        m_status = errno;
-        return m_status;
-    }
-    m_pos += amt;
-
-    amt = write(m_fd, packageName.string(), nameLen+1);
-    if (amt != nameLen+1) {
-        m_status = errno;
-        return m_status;
-    }
-    m_pos += amt;
-
-    return NO_ERROR;
-}
-
-status_t
 BackupDataWriter::WriteEntityHeader(const String8& key, size_t dataSize)
 {
     if (m_status != NO_ERROR) {
@@ -188,40 +148,11 @@
     return NO_ERROR;
 }
 
-status_t
-BackupDataWriter::WriteAppFooter(int cookie)
-{
-    if (m_status != NO_ERROR) {
-        return m_status;
-    }
-
-    ssize_t amt;
-
-    amt = write_padding_for(m_pos);
-    if (amt != 0) {
-        return amt;
-    }
-
-    app_footer_v1 footer;
-    ssize_t nameLen;
-
-    footer.type = tolel(BACKUP_FOOTER_APP_V1);
-    footer.entityCount = tolel(m_entityCount);
-    footer.cookie = cookie;
-
-    amt = write(m_fd, &footer, sizeof(app_footer_v1));
-    if (amt != sizeof(app_footer_v1)) {
-        m_status = errno;
-        return m_status;
-    }
-    m_pos += amt;
-
-    return NO_ERROR;
-}
 
 
 BackupDataReader::BackupDataReader(int fd)
     :m_fd(fd),
+     m_done(false),
      m_status(NO_ERROR),
      m_pos(0),
      m_entityCount(0)
@@ -260,31 +191,25 @@
     } while(0)
 
 status_t
-BackupDataReader::ReadNextHeader(int* type)
+BackupDataReader::ReadNextHeader(bool* done, int* type)
 {
+    *done = m_done;
     if (m_status != NO_ERROR) {
         return m_status;
     }
 
     int amt;
 
-    SKIP_PADDING();
+    // No error checking here, in case we're at the end of the stream.  Just let read() fail.
+    skip_padding();
     amt = read(m_fd, &m_header, sizeof(m_header));
+    *done = m_done = (amt == 0);
     CHECK_SIZE(amt, sizeof(m_header));
 
     // validate and fix up the fields.
     m_header.type = fromlel(m_header.type);
     switch (m_header.type)
     {
-        case BACKUP_HEADER_APP_V1:
-            m_header.app.packageLen = fromlel(m_header.app.packageLen);
-            if (m_header.app.packageLen < 0) {
-                LOGD("App header at %d has packageLen<0: 0x%08x\n", (int)m_pos,
-                    (int)m_header.app.packageLen);
-                m_status = EINVAL;
-            }
-            m_header.app.cookie = m_header.app.cookie;
-            break;
         case BACKUP_HEADER_ENTITY_V1:
             m_header.entity.keyLen = fromlel(m_header.entity.keyLen);
             if (m_header.entity.keyLen <= 0) {
@@ -295,15 +220,6 @@
             m_header.entity.dataSize = fromlel(m_header.entity.dataSize);
             m_entityCount++;
             break;
-        case BACKUP_FOOTER_APP_V1:
-            m_header.footer.entityCount = fromlel(m_header.footer.entityCount);
-            if (m_header.footer.entityCount < 0) {
-                LOGD("Entity header at %d has entityCount<0: 0x%08x\n", (int)m_pos,
-                        (int)m_header.footer.entityCount);
-                m_status = EINVAL;
-            }
-            m_header.footer.cookie = m_header.footer.cookie;
-            break;
         default:
             LOGD("Chunk header at %d has invalid type: 0x%08x", (int)m_pos, (int)m_header.type);
             m_status = EINVAL;
@@ -316,30 +232,6 @@
     return m_status;
 }
 
-status_t
-BackupDataReader::ReadAppHeader(String8* packageName, int* cookie)
-{
-    if (m_status != NO_ERROR) {
-        return m_status;
-    }
-    if (m_header.type != BACKUP_HEADER_APP_V1) {
-        return EINVAL;
-    }
-    size_t size = m_header.app.packageLen;
-    char* buf = packageName->lockBuffer(size);
-    if (buf == NULL) {
-        packageName->unlockBuffer();
-        m_status = ENOMEM;
-        return m_status;
-    }
-    int amt = read(m_fd, buf, size+1);
-    CHECK_SIZE(amt, (int)size+1);
-    packageName->unlockBuffer(size);
-    m_pos += size+1;
-    *cookie = m_header.app.cookie;
-    return NO_ERROR;
-}
-
 bool
 BackupDataReader::HasEntities()
 {
@@ -368,6 +260,7 @@
     m_pos += size+1;
     *dataSize = m_header.entity.dataSize;
     SKIP_PADDING();
+    m_dataEndPos = m_pos + *dataSize;
     return NO_ERROR;
 }
 
@@ -381,7 +274,7 @@
         return EINVAL;
     }
     if (m_header.entity.dataSize > 0) {
-        int pos = lseek(m_fd, m_header.entity.dataSize, SEEK_CUR);
+        int pos = lseek(m_fd, m_dataEndPos, SEEK_SET);
         return pos == -1 ? (int)errno : (int)NO_ERROR;
     } else {
         return NO_ERROR;
@@ -394,6 +287,15 @@
     if (m_status != NO_ERROR) {
         return m_status;
     }
+    int remaining = m_dataEndPos - m_pos;
+    if (size > remaining) {
+        printf("size=%d m_pos=0x%x m_dataEndPos=0x%x remaining=%d\n",
+                size, m_pos, m_dataEndPos, remaining);
+        size = remaining;
+    }
+    if (remaining <= 0) {
+        return 0;
+    }
     int amt = read(m_fd, data, size);
     CHECK_SIZE(amt, (int)size);
     m_pos += size;
@@ -401,25 +303,6 @@
 }
 
 status_t
-BackupDataReader::ReadAppFooter(int* cookie)
-{
-    if (m_status != NO_ERROR) {
-        return m_status;
-    }
-    if (m_header.type != BACKUP_FOOTER_APP_V1) {
-        return EINVAL;
-    }
-    if (m_header.footer.entityCount != m_entityCount) {
-        LOGD("entity count mismatch actual=%d expected=%d", m_entityCount,
-                m_header.footer.entityCount);
-        m_status = EINVAL;
-        return m_status;
-    }
-    *cookie = m_header.footer.cookie;
-    return NO_ERROR;
-}
-
-status_t
 BackupDataReader::skip_padding()
 {
     ssize_t amt;
diff --git a/libs/utils/BackupHelpers.cpp b/libs/utils/BackupHelpers.cpp
index 4c3e37d..c1d5404 100644
--- a/libs/utils/BackupHelpers.cpp
+++ b/libs/utils/BackupHelpers.cpp
@@ -689,41 +689,27 @@
 
 // hexdump -v -e '"    " 8/1 " 0x%02x," "\n"' data_writer.data
 const unsigned char DATA_GOLDEN_FILE[] = {
-     0x41, 0x70, 0x70, 0x31, 0x0b, 0x00, 0x00, 0x00,
-     0xdd, 0xcc, 0xbb, 0xaa, 0x6e, 0x6f, 0x5f, 0x70,
-     0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
      0x44, 0x61, 0x74, 0x61, 0x0b, 0x00, 0x00, 0x00,
      0x0c, 0x00, 0x00, 0x00, 0x6e, 0x6f, 0x5f, 0x70,
      0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x00,
      0x6e, 0x6f, 0x5f, 0x70, 0x61, 0x64, 0x64, 0x69,
-     0x6e, 0x67, 0x5f, 0x00, 0x41, 0x70, 0x70, 0x31,
-     0x0c, 0x00, 0x00, 0x00, 0xdd, 0xcc, 0xbb, 0xaa,
+     0x6e, 0x67, 0x5f, 0x00, 0x44, 0x61, 0x74, 0x61,
+     0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
      0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
      0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
-     0x44, 0x61, 0x74, 0x61, 0x0c, 0x00, 0x00, 0x00,
-     0x0d, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
-     0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x5f, 0x33,
-     0x00, 0xbc, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
-     0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x5f, 0x33,
-     0x00, 0xbc, 0xbc, 0xbc, 0x41, 0x70, 0x70, 0x31,
-     0x0d, 0x00, 0x00, 0x00, 0xdd, 0xcc, 0xbb, 0xaa,
      0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
-     0x6f, 0x5f, 0x32, 0x5f, 0x5f, 0x00, 0xbc, 0xbc,
+     0x6f, 0x5f, 0x5f, 0x33, 0x00, 0xbc, 0xbc, 0xbc,
      0x44, 0x61, 0x74, 0x61, 0x0d, 0x00, 0x00, 0x00,
      0x0e, 0x00, 0x00, 0x00, 0x70, 0x61, 0x64, 0x64,
      0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
      0x5f, 0x00, 0xbc, 0xbc, 0x70, 0x61, 0x64, 0x64,
      0x65, 0x64, 0x5f, 0x74, 0x6f, 0x5f, 0x32, 0x5f,
-     0x5f, 0x00, 0xbc, 0xbc, 0x41, 0x70, 0x70, 0x31,
-     0x0a, 0x00, 0x00, 0x00, 0xdd, 0xcc, 0xbb, 0xaa,
-     0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
-     0x6f, 0x31, 0x00, 0xbc, 0x44, 0x61, 0x74, 0x61,
+     0x5f, 0x00, 0xbc, 0xbc, 0x44, 0x61, 0x74, 0x61,
      0x0a, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
      0x70, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x74,
      0x6f, 0x31, 0x00, 0xbc, 0x70, 0x61, 0x64, 0x64,
-     0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00, 0xbc,
-     0x46, 0x6f, 0x6f, 0x74, 0x04, 0x00, 0x00, 0x00,
-     0x99, 0x99, 0x77, 0x77
+     0x65, 0x64, 0x5f, 0x74, 0x6f, 0x31, 0x00
+
 };
 const int DATA_GOLDEN_FILE_SIZE = sizeof(DATA_GOLDEN_FILE);
 
@@ -733,12 +719,6 @@
     int err;
     String8 text(str);
 
-    err = writer.WriteAppHeader(text, 0xaabbccdd);
-    if (err != 0) {
-        fprintf(stderr, "WriteAppHeader failed with %s\n", strerror(err));
-        return err;
-    }
-
     err = writer.WriteEntityHeader(text, text.length()+1);
     if (err != 0) {
         fprintf(stderr, "WriteEntityHeader failed with %s\n", strerror(err));
@@ -779,8 +759,6 @@
     err |= test_write_header_and_entity(writer, "padded_to_2__");
     err |= test_write_header_and_entity(writer, "padded_to1");
 
-    writer.WriteAppFooter(0x77779999);
-
     close(fd);
 
     err = compare_file(filename, DATA_GOLDEN_FILE, DATA_GOLDEN_FILE_SIZE);
@@ -800,70 +778,59 @@
     String8 string;
     int cookie = 0x11111111;
     size_t actualSize;
+    bool done;
+    int type;
 
     // printf("\n\n---------- test_read_header_and_entity -- %s\n\n", str);
 
-    err = reader.ReadNextHeader();
+    err = reader.ReadNextHeader(&done, &type);
+    if (done) {
+        fprintf(stderr, "should not be done yet\n");
+        goto finished;
+    }
     if (err != 0) {
         fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
-        goto done;
+        goto finished;
     }
-
-    err = reader.ReadAppHeader(&string, &cookie);
-    if (err != 0) {
-        fprintf(stderr, "ReadAppHeader failed with %s\n", strerror(err));
-        goto done;
-    }
-    if (string != str) {
-        fprintf(stderr, "ReadAppHeader expected packageName '%s' got '%s'\n", str, string.string());
+    if (type != BACKUP_HEADER_ENTITY_V1) {
         err = EINVAL;
-        goto done;
-    }
-    if (cookie != (int)0xaabbccdd) {
-        fprintf(stderr, "ReadAppHeader expected cookie 0x%08x got 0x%08x\n", 0xaabbccdd, cookie);
-        err = EINVAL;
-        goto done;
-    }
-
-    err = reader.ReadNextHeader();
-    if (err != 0) {
-        fprintf(stderr, "ReadNextHeader (for entity header) failed with %s\n", strerror(err));
-        goto done;
+        fprintf(stderr, "type=0x%08x expected 0x%08x\n", type, BACKUP_HEADER_ENTITY_V1);
     }
 
     err = reader.ReadEntityHeader(&string, &actualSize);
     if (err != 0) {
         fprintf(stderr, "ReadEntityHeader failed with %s\n", strerror(err));
-        goto done;
+        goto finished;
     }
     if (string != str) {
         fprintf(stderr, "ReadEntityHeader expected key '%s' got '%s'\n", str, string.string());
         err = EINVAL;
-        goto done;
+        goto finished;
     }
     if ((int)actualSize != bufSize) {
         fprintf(stderr, "ReadEntityHeader expected dataSize 0x%08x got 0x%08x\n", bufSize,
                 actualSize);
         err = EINVAL;
-        goto done;
+        goto finished;
     }
 
     err = reader.ReadEntityData(buf, bufSize);
     if (err != NO_ERROR) {
         fprintf(stderr, "ReadEntityData failed with %s\n", strerror(err));
-        goto done;
+        goto finished;
     }
 
     if (0 != memcmp(buf, str, bufSize)) {
         fprintf(stderr, "ReadEntityData expected '%s' but got something starting with "
-                "%02x %02x %02x %02x\n", str, buf[0], buf[1], buf[2], buf[3]);
+                "%02x %02x %02x %02x  '%c%c%c%c'\n", str, buf[0], buf[1], buf[2], buf[3],
+                buf[0], buf[1], buf[2], buf[3]);
         err = EINVAL;
-        goto done;
+        goto finished;
     }
 
     // The next read will confirm whether it got the right amount of data.
 
-done:
+finished:
     if (err != NO_ERROR) {
         fprintf(stderr, "test_read_header_and_entity failed with %s\n", strerror(err));
     }
@@ -923,23 +890,6 @@
         if (err == NO_ERROR) {
             err = test_read_header_and_entity(reader, "padded_to1");
         }
-
-        if (err == NO_ERROR) {
-            err = reader.ReadNextHeader();
-            if (err != 0) {
-                fprintf(stderr, "ReadNextHeader (for app header) failed with %s\n", strerror(err));
-            }
-
-            if (err == NO_ERROR) {
-                int cookie;
-                err |= reader.ReadAppFooter(&cookie);
-                if (cookie != 0x77779999) {
-                    fprintf(stderr, "app footer cookie expected=0x%08x actual=0x%08x\n",
-                        0x77779999, cookie);
-                    err = EINVAL;
-                }
-            }
-        }
     }
 
     close(fd);
diff --git a/packages/TtsService/jni/android_tts_SynthProxy.cpp b/packages/TtsService/jni/android_tts_SynthProxy.cpp
index dfecfd8..54d038a 100644
--- a/packages/TtsService/jni/android_tts_SynthProxy.cpp
+++ b/packages/TtsService/jni/android_tts_SynthProxy.cpp
@@ -269,10 +269,10 @@
     }
 }
 
-// TODO update to use language, country, variant
+
 static void
 android_tts_SynthProxy_setLanguage(JNIEnv *env, jobject thiz, jint jniData,
-        jstring language)
+        jstring language, jstring country, jstring variant)
 {
     if (jniData == 0) {
         LOGE("android_tts_SynthProxy_setLanguage(): invalid JNI data");
@@ -281,14 +281,16 @@
 
     SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
     const char *langNativeString = env->GetStringUTFChars(language, 0);
+    const char *countryNativeString = env->GetStringUTFChars(country, 0);
+    const char *variantNativeString = env->GetStringUTFChars(variant, 0);
     // TODO check return codes
     if (pSynthData->mNativeSynthInterface) {
-        // TODO update to use language, country, variant
-        //      commented out to not break the build
-        //pSynthData->mNativeSynthInterface->setLanguage(langNativeString,
-        //        strlen(langNativeString));
+        pSynthData->mNativeSynthInterface->setLanguage(langNativeString, countryNativeString,
+                variantNativeString);
     }
     env->ReleaseStringUTFChars(language, langNativeString);
+    env->ReleaseStringUTFChars(language, countryNativeString);
+    env->ReleaseStringUTFChars(language, variantNativeString);
 }
 
 
@@ -496,6 +498,7 @@
     return env->NewStringUTF(buf);
 }
 
+
 JNIEXPORT int JNICALL
 android_tts_SynthProxy_getRate(JNIEnv *env, jobject thiz, jint jniData)
 {
@@ -531,7 +534,7 @@
         (void*)android_tts_SynthProxy_synthesizeToFile
     },
     {   "native_setLanguage",
-        "(ILjava/lang/String;)V",
+        "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
         (void*)android_tts_SynthProxy_setLanguage
     },
     {   "native_setSpeechRate",
@@ -567,7 +570,6 @@
 #define SP_JNIDATA_FIELD_NAME                "mJniData"
 #define SP_POSTSPEECHSYNTHESIZED_METHOD_NAME "postNativeSpeechSynthesizedInJava"
 
-// TODO: verify this is the correct path
 static const char* const kClassPathName = "android/tts/SynthProxy";
 
 jint JNI_OnLoad(JavaVM* vm, void* reserved)
diff --git a/packages/TtsService/src/android/tts/SynthProxy.java b/packages/TtsService/src/android/tts/SynthProxy.java
index e065f40..364dc58 100755
--- a/packages/TtsService/src/android/tts/SynthProxy.java
+++ b/packages/TtsService/src/android/tts/SynthProxy.java
@@ -70,8 +70,8 @@
     /**
      * Sets the language
      */
-    public void setLanguage(String language) {
-        native_setLanguage(mJniData, language);
+    public void setLanguage(String language, String country, String variant) {
+        native_setLanguage(mJniData, language, country, variant);
     }
 
     /**
@@ -141,7 +141,8 @@
 
     private native final void native_synthesizeToFile(int jniData, String text, String filename);
 
-    private native final void native_setLanguage(int jniData, String language);
+    private native final void native_setLanguage(int jniData, String language, String country,
+            String variant);
 
     private native final void native_setSpeechRate(int jniData, int speechRate);
 
diff --git a/packages/TtsService/src/android/tts/TtsService.java b/packages/TtsService/src/android/tts/TtsService.java
index 8a64113..f7dd0e8 100755
--- a/packages/TtsService/src/android/tts/TtsService.java
+++ b/packages/TtsService/src/android/tts/TtsService.java
@@ -129,7 +129,9 @@
         mSpeechQueue = new ArrayList<SpeechItem>();
         mPlayer = null;
 
-        setLanguage(prefs.getString("lang_pref", "en-rUS"));
+        // TODO set default settings
+        //setLanguage(prefs.getString("lang_pref", "en-rUS"));
+        setLanguage("eng", "USA", "");
         setSpeechRate(Integer.parseInt(prefs.getString("rate_pref", "140")));
     }
 
@@ -155,7 +157,7 @@
         nativeSynth.setSpeechRate(rate);
     }
 
-    private void setLanguage(String lang) {
+    private void setLanguage(String lang, String country, String variant) {
         if (prefs.getBoolean("override_pref", false)) {
             // This is set to the default here so that the preview in the prefs
             // activity will show the change without a restart, even if apps are
@@ -163,7 +165,8 @@
             // allowed to change the defaults.
             lang = prefs.getString("lang_pref", "en-rUS");
         }
-        nativeSynth.setLanguage(lang);
+        Log.v("TTS", "TtsService.setLanguage("+lang+", "+country+", "+variant+")");
+        nativeSynth.setLanguage(lang, country, variant);
     }
 
     /**
@@ -683,20 +686,14 @@
         }
 
         /**
-         * Sets the speech rate for the TTS. Note that this will only have an
-         * effect on synthesized speech; it will not affect pre-recorded speech.
+         * Sets the speech rate for the TTS, which affects the synthesized voice.
          *
-         * @param language
-         *            Language values are based on the Android conventions for
-         *            localization as described in the Android platform
-         *            documentation on internationalization. This implies that
-         *            language data is specified in the format xx-rYY, where xx
-         *            is a two letter ISO 639-1 language code in lowercase and
-         *            rYY is a two letter ISO 3166-1-alpha-2 language code in
-         *            uppercase preceded by a lowercase "r".
+         * @param lang  the three letter ISO language code.
+         * @param country  the three letter ISO country code.
+         * @param variant  the variant code associated with the country and language pair.
          */
-        public void setLanguage(String language) {
-            mSelf.setLanguage(language);
+        public void setLanguage(String lang, String country, String variant) {
+            mSelf.setLanguage(lang, country, variant);
         }
 
         /**
diff --git a/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java b/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java
index ce56921..8358c5c 100644
--- a/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java
+++ b/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java
@@ -50,16 +50,17 @@
     }
 
     private String getCaCertPath() {
-        return Keystore.getInstance().getCertificate(
+        return Keystore.getInstance().getCaCertificate(
                 getProfile().getCaCertificate());
     }
 
     private String getUserCertPath() {
-        return Keystore.getInstance().getCertificate(
+        return Keystore.getInstance().getUserCertificate(
                 getProfile().getUserCertificate());
     }
 
     private String getUserkeyPath() {
-        return Keystore.getInstance().getUserkey(getProfile().getUserkey());
+        return Keystore.getInstance().getUserPrivateKey(
+                getProfile().getUserCertificate());
     }
 }
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 4742636..d842d34 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -68,7 +68,7 @@
 class BackupManagerService extends IBackupManager.Stub {
     private static final String TAG = "BackupManagerService";
     private static final boolean DEBUG = true;
-    
+
     private static final long COLLECTION_INTERVAL = 1000;
     //private static final long COLLECTION_INTERVAL = 3 * 60 * 1000;
 
@@ -90,7 +90,7 @@
     private class BackupRequest {
         public ApplicationInfo appInfo;
         public boolean fullBackup;
-        
+
         BackupRequest(ApplicationInfo app, boolean isFull) {
             appInfo = app;
             fullBackup = isFull;
@@ -120,7 +120,9 @@
     private final Object mClearDataLock = new Object();
     private volatile boolean mClearingData;
 
+    // Current active transport & restore session
     private int mTransportId;
+    private IBackupTransport mTransport;
     private RestoreSession mActiveRestoreSession;
 
     private File mStateDir;
@@ -128,7 +130,7 @@
     private File mJournalDir;
     private File mJournal;
     private RandomAccessFile mJournalStream;
-    
+
     public BackupManagerService(Context context) {
         mContext = context;
         mPackageManager = context.getPackageManager();
@@ -144,14 +146,16 @@
         mJournalDir.mkdirs();
         makeJournalLocked();    // okay because no other threads are running yet
 
-        //!!! TODO: default to cloud transport, not local
-        mTransportId = BackupManager.TRANSPORT_LOCAL;
-        
         // Build our mapping of uid to backup client services
         synchronized (mBackupParticipants) {
             addPackageParticipantsLocked(null);
         }
 
+        // Stand up our default transport
+        //!!! TODO: default to cloud transport, not local
+        mTransportId = BackupManager.TRANSPORT_LOCAL;
+        mTransport = createTransport(mTransportId);
+
         // Now that we know about valid backup participants, parse any
         // leftover journal files and schedule a new backup pass
         parseLeftoverJournals();
@@ -284,7 +288,7 @@
                     // deleted.  If we crash prior to that, the old journal is parsed
                     // at next boot and the journaled requests fulfilled.
                 }
-                (new PerformBackupThread(mTransportId, mBackupQueue, oldJournal)).run();
+                (new PerformBackupThread(mTransport, mBackupQueue, oldJournal)).run();
                 break;
 
             case MSG_RUN_FULL_BACKUP:
@@ -396,7 +400,7 @@
         }
         return allApps;
     }
-    
+
     // Reset the given package's known backup participants.  Unlike add/remove, the update
     // action cannot be passed a null package name.
     void updatePackageParticipantsLocked(String packageName) {
@@ -505,13 +509,13 @@
 
     class PerformBackupThread extends Thread {
         private static final String TAG = "PerformBackupThread";
-        int mTransport;
+        IBackupTransport mTransport;
         ArrayList<BackupRequest> mQueue;
         File mJournal;
 
-        public PerformBackupThread(int transportId, ArrayList<BackupRequest> queue,
+        public PerformBackupThread(IBackupTransport transport, ArrayList<BackupRequest> queue,
                 File journal) {
-            mTransport = transportId;
+            mTransport = transport;
             mQueue = queue;
             mJournal = journal;
         }
@@ -520,15 +524,9 @@
         public void run() {
             if (DEBUG) Log.v(TAG, "Beginning backup of " + mQueue.size() + " targets");
 
-            // stand up the current transport
-            IBackupTransport transport = createTransport(mTransport);
-            if (transport == null) {
-                return;
-            }
-
             // start up the transport
             try {
-                transport.startSession();
+                mTransport.startSession();
             } catch (Exception e) {
                 Log.e(TAG, "Error session transport");
                 e.printStackTrace();
@@ -536,11 +534,11 @@
             }
 
             // The transport is up and running; now run all the backups in our queue
-            doQueuedBackups(transport);
+            doQueuedBackups(mTransport);
 
             // Finally, tear down the transport
             try {
-                transport.endSession();
+                mTransport.endSession();
             } catch (Exception e) {
                 Log.e(TAG, "Error ending transport");
                 e.printStackTrace();
@@ -850,8 +848,26 @@
         // a backup pass for each of them.
 
         Log.d(TAG, "dataChanged packageName=" + packageName);
-        
-        HashSet<ApplicationInfo> targets = mBackupParticipants.get(Binder.getCallingUid());
+
+        // If the caller does not hold the BACKUP permission, it can only request a
+        // backup of its own data.
+        HashSet<ApplicationInfo> targets;
+        if ((mContext.checkPermission("android.permission.BACKUP", Binder.getCallingPid(),
+                Binder.getCallingUid())) == PackageManager.PERMISSION_DENIED) {
+            targets = mBackupParticipants.get(Binder.getCallingUid());
+        } else {
+            // a caller with full permission can ask to back up any participating app
+            // !!! TODO: allow backup of ANY app?
+            if (DEBUG) Log.v(TAG, "Privileged caller, allowing backup of other apps");
+            targets = new HashSet<ApplicationInfo>();
+            int N = mBackupParticipants.size();
+            for (int i = 0; i < N; i++) {
+                HashSet<ApplicationInfo> s = mBackupParticipants.valueAt(i);
+                if (s != null) {
+                    targets.addAll(s);
+                }
+            }
+        }
         if (targets != null) {
             synchronized (mQueueLock) {
                 // Note that this client has made data changes that need to be backed up
@@ -921,8 +937,14 @@
     public int selectBackupTransport(int transportId) {
         mContext.enforceCallingPermission("android.permission.BACKUP", "selectBackupTransport");
 
-        int prevTransport = mTransportId;
-        mTransportId = transportId;
+        int prevTransport = -1;
+        IBackupTransport newTransport = createTransport(transportId);
+        if (newTransport != null) {
+            // !!! TODO: a method on the old transport that says it's being deactivated?
+            mTransport = newTransport;
+            prevTransport = mTransportId;
+            mTransportId = transportId;
+        }
         return prevTransport;
     }
 
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 07d6b6f..c0d4496 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -61,7 +61,6 @@
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.net.Uri;
-import android.os.BatteryStats;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Environment;
@@ -88,7 +87,6 @@
 import android.util.Config;
 import android.util.EventLog;
 import android.util.Log;
-import android.util.LogPrinter;
 import android.util.PrintWriterPrinter;
 import android.util.SparseArray;
 import android.view.Gravity;
@@ -127,6 +125,7 @@
     static final boolean DEBUG_OOM_ADJ = localLOGV || false;
     static final boolean DEBUG_TRANSITION = localLOGV || false;
     static final boolean DEBUG_BROADCAST = localLOGV || false;
+    static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
     static final boolean DEBUG_SERVICE = localLOGV || false;
     static final boolean DEBUG_VISBILITY = localLOGV || false;
     static final boolean DEBUG_PROCESSES = localLOGV || false;
@@ -10596,7 +10595,7 @@
             boolean ordered, boolean sticky, int callingPid, int callingUid) {
         intent = new Intent(intent);
 
-        if (DEBUG_BROADCAST) Log.v(
+        if (DEBUG_BROADCAST_LIGHT) Log.v(
             TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
             + " ordered=" + ordered);
         if ((resultTo != null) && !ordered) {
@@ -11088,7 +11087,7 @@
 
         boolean started = false;
         try {
-            if (DEBUG_BROADCAST) Log.v(TAG,
+            if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
                     "Delivering to component " + r.curComponent
                     + ": " + r);
             app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
@@ -11158,12 +11157,22 @@
                 r.curFilter = filter;
                 filter.receiverList.curBroadcast = r;
                 r.state = BroadcastRecord.CALL_IN_RECEIVE;
+                if (filter.receiverList.app != null) {
+                    // Bump hosting application to no longer be in background
+                    // scheduling class.  Note that we can't do that if there
+                    // isn't an app...  but we can only be in that case for
+                    // things that directly call the IActivityManager API, which
+                    // are already core system stuff so don't matter for this.
+                    r.curApp = filter.receiverList.app;
+                    filter.receiverList.app.curReceiver = r;
+                    updateOomAdjLocked();
+                }
             }
             try {
-                if (DEBUG_BROADCAST) {
+                if (DEBUG_BROADCAST_LIGHT) {
                     int seq = r.intent.getIntExtra("seq", -1);
-                    Log.i(TAG, "Sending broadcast " + r.intent.getAction() + " seq=" + seq
-                            + " app=" + filter.receiverList.app);
+                    Log.i(TAG, "Delivering to " + filter.receiverList.app
+                            + " (seq=" + seq + "): " + r);
                 }
                 performReceive(filter.receiverList.app, filter.receiverList.receiver,
                     new Intent(r.intent), r.resultCode,
@@ -11177,6 +11186,9 @@
                     r.receiver = null;
                     r.curFilter = null;
                     filter.receiverList.curBroadcast = null;
+                    if (filter.receiverList.app != null) {
+                        filter.receiverList.app.curReceiver = null;
+                    }
                 }
             }
         }
@@ -11200,6 +11212,8 @@
             while (mParallelBroadcasts.size() > 0) {
                 r = mParallelBroadcasts.remove(0);
                 final int N = r.receivers.size();
+                if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
+                        + r);
                 for (int i=0; i<N; i++) {
                     Object target = r.receivers.get(i);
                     if (DEBUG_BROADCAST)  Log.v(TAG,
@@ -11207,6 +11221,8 @@
                             + target + ": " + r);
                     deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
                 }
+                if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
+                        + r);
             }
 
             // Now take care of the next serialized one...
@@ -11232,10 +11248,18 @@
                 }
             }
 
+            boolean looped = false;
+            
             do {
                 if (mOrderedBroadcasts.size() == 0) {
                     // No more broadcasts pending, so all done!
                     scheduleAppGcsLocked();
+                    if (looped) {
+                        // If we had finished the last ordered broadcast, then
+                        // make sure all processes have correct oom and sched
+                        // adjustments.
+                        updateOomAdjLocked();
+                    }
                     return;
                 }
                 r = mOrderedBroadcasts.get(0);
@@ -11292,9 +11316,13 @@
                     if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
                     mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
 
+                    if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
+                            + r);
+                    
                     // ... and on to the next...
                     mOrderedBroadcasts.remove(0);
                     r = null;
+                    looped = true;
                     continue;
                 }
             } while (r == null);
@@ -11308,6 +11336,8 @@
             if (recIdx == 0) {
                 r.dispatchTime = r.startTime;
 
+                if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
+                        + r);
                 if (DEBUG_BROADCAST) Log.v(TAG,
                         "Submitting BROADCAST_TIMEOUT_MSG for "
                         + (r.startTime + BROADCAST_TIMEOUT));
diff --git a/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java b/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java
index 16aca4d..b2529811 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/CdmaSmsTest.java
@@ -103,6 +103,9 @@
         assertEquals(userData.msgEncoding, revBearerData.userData.msgEncoding);
         assertEquals(userData.payloadStr.length(), revBearerData.userData.numFields);
         assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
+        userData.payloadStr = "More @ testing\nis great^|^~woohoo";
+        revBearerData = BearerData.decode(BearerData.encode(bearerData));
+        assertEquals(userData.payloadStr, revBearerData.userData.payloadStr);
     }
 
     @SmallTest