Merge change 4115 into donut

* changes:
  * component can be null after destory?  This was causing NPE in catch block, which hides the actual exception.
diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp
index 4e6859c..128fd5a 100644
--- a/camera/libcameraservice/CameraService.cpp
+++ b/camera/libcameraservice/CameraService.cpp
@@ -215,7 +215,7 @@
 {
     Mutex::Autolock _l(mLock);
     // allow anyone to use camera
-    LOGV("unlock (%p)", getCameraClient()->asBinder().get());
+    LOGD("unlock (%p)", getCameraClient()->asBinder().get());
     status_t result = checkPid();
     if (result == NO_ERROR) {
         mClientPid = 0;
@@ -230,7 +230,7 @@
 status_t CameraService::Client::connect(const sp<ICameraClient>& client)
 {
     // connect a new process to the camera
-    LOGV("connect (%p)", client->asBinder().get());
+    LOGD("connect (%p)", client->asBinder().get());
 
     // I hate this hack, but things get really ugly when the media recorder
     // service is handing back the camera to the app. The ICameraClient
@@ -245,7 +245,7 @@
         sp<ICameraClient> oldClient;
         {
             Mutex::Autolock _l(mLock);
-            if (mClientPid != 0) {
+            if (mClientPid != 0 && checkPid() != NO_ERROR) {
                 LOGW("Tried to connect to locked camera");
                 return -EBUSY;
             }
@@ -257,7 +257,7 @@
             mCameraClient = client;
             mClientPid = -1;
             mPreviewCallbackFlag = FRAME_CALLBACK_FLAG_NOOP;
-            LOGV("connect new process (%d) to existing camera client", mClientPid);
+            LOGD("connect new process (%d) to existing camera client", mClientPid);
         }
 
     }
@@ -319,17 +319,17 @@
             IPCThreadState::self()->getCallingPid());
     Mutex::Autolock lock(mLock);
     if (mClientPid <= 0) {
-        LOGV("camera is unlocked, don't tear down hardware");
+        LOGD("camera is unlocked, don't tear down hardware");
         return;
     }
     if (checkPid() != NO_ERROR) {
-        LOGV("Different client - don't disconnect");
+        LOGD("Different client - don't disconnect");
         return;
     }
 
     mCameraService->removeClient(mCameraClient);
     if (mHardware != 0) {
-        LOGV("hardware teardown");
+        LOGD("hardware teardown");
         // Before destroying mHardware, we must make sure it's in the
         // idle state.
         mHardware->stopPreview();
diff --git a/cmds/keystore/Android.mk b/cmds/keystore/Android.mk
new file mode 100644
index 0000000..20f4adf
--- /dev/null
+++ b/cmds/keystore/Android.mk
@@ -0,0 +1,21 @@
+ifneq ($(TARGET_SIMULATOR),true)
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+    keystore.c commands.c
+
+LOCAL_C_INCLUDES := \
+    $(call include-path-for, system-core)/cutils
+
+LOCAL_SHARED_LIBRARIES := \
+    libcutils
+
+LOCAL_STATIC_LIBRARIES :=
+
+LOCAL_MODULE:= keystore
+
+include $(BUILD_EXECUTABLE)
+
+endif # !simulator))
diff --git a/cmds/keystore/commands.c b/cmds/keystore/commands.c
new file mode 100644
index 0000000..e53cece
--- /dev/null
+++ b/cmds/keystore/commands.c
@@ -0,0 +1,141 @@
+/*
+** Copyright 2008, 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.
+*/
+
+#include "keystore.h"
+
+static DIR *open_keystore(const char *dir)
+{
+    DIR *d;
+    if ((d = opendir(dir)) == NULL) {
+        if (mkdir(dir, 0770) < 0) {
+            LOGE("cannot create dir '%s': %s\n", dir, strerror(errno));
+            unlink(dir);
+            return NULL;
+        }
+        d = open_keystore(dir);
+    }
+    return d;
+}
+
+static int list_files(const char *dir, char reply[REPLY_MAX]) {
+    struct dirent *de;
+    DIR *d;
+
+    if ((d = open_keystore(dir)) == NULL) {
+        return -1;
+    }
+    reply[0]=0;
+    while ((de = readdir(d))) {
+        if (de->d_type != DT_REG) 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);
+            return -1;
+        }
+    }
+    closedir(d);
+    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, '/');
+
+    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);
+        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);
+    }
+    close(srcfd);
+    close(dstfd);
+    chmod(dstfile, 0440);
+    return 0;
+}
+
+static int install_key(const char *dir, const char *keyfile)
+{
+    struct dirent *de;
+    DIR *d;
+
+    if ((d = open_keystore(dir)) == NULL) {
+        return -1;
+    }
+    return copy_keyfile(dir, keyfile);
+}
+
+static int remove_key(const char *dir, const char *keyfile)
+{
+    char dstfile[KEYNAME_LENGTH];
+
+    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);
+        return -1;
+    }
+    if (unlink(dstfile)) {
+        LOGE("cannot delete '%s': %s\n", dstfile, strerror(errno));
+        return -1;
+    }
+    return 0;
+}
+
+int list_certs(char reply[REPLY_MAX])
+{
+    return list_files(CERTS_DIR, reply);
+}
+
+int list_userkeys(char reply[REPLY_MAX])
+{
+    return list_files(USERKEYS_DIR, reply);
+}
+
+int install_cert(const char *certfile)
+{
+    return install_key(CERTS_DIR, certfile);
+}
+
+int install_userkey(const char *keyfile)
+{
+    return install_key(USERKEYS_DIR, keyfile);
+}
+
+int remove_cert(const char *certfile)
+{
+    return remove_key(CERTS_DIR, certfile);
+}
+
+int remove_userkey(const char *keyfile)
+{
+    return remove_key(USERKEYS_DIR, keyfile);
+}
diff --git a/cmds/keystore/keystore.c b/cmds/keystore/keystore.c
new file mode 100644
index 0000000..5193b3d
--- /dev/null
+++ b/cmds/keystore/keystore.c
@@ -0,0 +1,255 @@
+/*
+** 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.
+** 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.
+*/
+
+#include "keystore.h"
+
+
+static int do_list_certs(char **arg, char reply[REPLY_MAX])
+{
+    return list_certs(reply);
+}
+
+static int do_list_userkeys(char **arg, char reply[REPLY_MAX])
+{
+    return list_userkeys(reply);
+}
+
+static int do_install_cert(char **arg, char reply[REPLY_MAX])
+{
+    return install_cert(arg[0]); /* move the certificate to keystore */
+}
+
+static int do_remove_cert(char **arg, char reply[REPLY_MAX])
+{
+    return remove_cert(arg[0]); /* certificate */
+}
+
+static int do_install_userkey(char **arg, char reply[REPLY_MAX])
+{
+    return install_userkey(arg[0]); /* move the certificate to keystore */
+}
+
+static int do_remove_userkey(char **arg, char reply[REPLY_MAX])
+{
+    return remove_userkey(arg[0]); /* userkey */
+}
+
+struct cmdinfo {
+    const char *name;
+    unsigned numargs;
+    int (*func)(char **arg, char reply[REPLY_MAX]);
+};
+
+
+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 },
+};
+
+static int readx(int s, void *_buf, int count)
+{
+    char *buf = _buf;
+    int n = 0, r;
+    if (count < 0) return -1;
+    while (n < count) {
+        r = read(s, buf + n, count - n);
+        if (r < 0) {
+            if (errno == EINTR) continue;
+            LOGE("read error: %s\n", strerror(errno));
+            return -1;
+        }
+        if (r == 0) {
+            LOGE("eof\n");
+            return -1; /* EOF */
+        }
+        n += r;
+    }
+    return 0;
+}
+
+static int writex(int s, const void *_buf, int count)
+{
+    const char *buf = _buf;
+    int n = 0, r;
+    if (count < 0) return -1;
+    while (n < count) {
+        r = write(s, buf + n, count - n);
+        if (r < 0) {
+            if (errno == EINTR) continue;
+            LOGE("write error: %s\n", strerror(errno));
+            return -1;
+        }
+        n += r;
+    }
+    return 0;
+}
+
+
+/* Tokenize the command buffer, locate a matching command,
+ * ensure that the required number of arguments are provided,
+ * call the function(), return the result.
+ */
+static int execute(int s, char cmd[BUFFER_MAX])
+{
+    char reply[REPLY_MAX];
+    char *arg[TOKEN_MAX+1];
+    unsigned i;
+    unsigned n = 0;
+    unsigned short count;
+    short ret = -1;
+
+    /* default reply is "" */
+    reply[0] = 0;
+
+    /* n is number of args (not counting arg[0]) */
+    arg[0] = cmd;
+    while (*cmd) {
+        if (isspace(*cmd)) {
+            *cmd++ = 0;
+            n++;
+            arg[n] = cmd;
+            if (n == TOKEN_MAX) {
+                LOGE("too many arguments\n");
+                goto done;
+            }
+        }
+        cmd++;
+    }
+
+    for (i = 0; i < sizeof(cmds) / sizeof(cmds[0]); i++) {
+        if (!strcmp(cmds[i].name,arg[0])) {
+            if (n != cmds[i].numargs) {
+                LOGE("%s requires %d arguments (%d given)\n",
+                     cmds[i].name, cmds[i].numargs, n);
+            } else {
+                ret = (short) cmds[i].func(arg + 1, reply);
+            }
+            goto done;
+        }
+    }
+    LOGE("unsupported command '%s'\n", arg[0]);
+
+done:
+    if (reply[0]) {
+        strlcpy(cmd, reply, BUFFER_MAX);
+        count = strlen(cmd);
+    } else {
+        count = 0;
+    }
+    if (writex(s, &ret, sizeof(ret))) return -1;
+    if (ret == 0) {
+        if (writex(s, &count, sizeof(count))) return -1;
+        if (writex(s, cmd, count)) return -1;
+    }
+
+    return 0;
+}
+
+int shell_command(const int argc, const char **argv)
+{
+    int fd, i;
+    short ret;
+    unsigned short count;
+    char buf[BUFFER_MAX]="";
+
+    fd = socket_local_client(SOCKET_PATH,
+                             ANDROID_SOCKET_NAMESPACE_RESERVED,
+                             SOCK_STREAM);
+    if (fd == -1) {
+        fprintf(stderr, "Keystore service is not up and running\n");
+        exit(1);
+    }
+    for(i = 0; i < argc; i++) {
+        if (i > 0) strlcat(buf, " ", BUFFER_MAX);
+        if(strlcat(buf, argv[i], BUFFER_MAX) >= BUFFER_MAX) {
+            fprintf(stderr, "Arguments are too long\n");
+            exit(1);
+        }
+    }
+    count = strlen(buf);
+    if (writex(fd, &count, sizeof(count))) return -1;
+    if (writex(fd, buf, strlen(buf))) return -1;
+    if (readx(fd, &ret, sizeof(ret))) return -1;
+    if (ret == 0) {
+        if (readx(fd, &count, sizeof(count))) return -1;
+        if (readx(fd, buf, count)) return -1;
+        buf[count]=0;
+        fprintf(stdout, "%s\n", buf);
+    } else {
+        fprintf(stderr, "Failed, please check log!\n");
+    }
+    return 0;
+}
+
+int main(const int argc, const char *argv[])
+{
+    char buf[BUFFER_MAX];
+    struct sockaddr addr;
+    socklen_t alen;
+    int lsocket, s, count;
+
+    if (argc > 1) {
+        return shell_command(argc - 1, argv + 1);
+    }
+
+    lsocket = android_get_control_socket(SOCKET_PATH);
+    if (lsocket < 0) {
+        LOGE("Failed to get socket from environment: %s\n", strerror(errno));
+        exit(1);
+    }
+    if (listen(lsocket, 5)) {
+        LOGE("Listen on socket failed: %s\n", strerror(errno));
+        exit(1);
+    }
+    fcntl(lsocket, F_SETFD, FD_CLOEXEC);
+
+    for (;;) {
+        alen = sizeof(addr);
+        s = accept(lsocket, &addr, &alen);
+        if (s < 0) {
+            LOGE("Accept failed: %s\n", strerror(errno));
+            continue;
+        }
+        fcntl(s, F_SETFD, FD_CLOEXEC);
+
+        LOGI("new connection\n");
+        for (;;) {
+            unsigned short count;
+            if (readx(s, &count, sizeof(count))) {
+                LOGE("failed to read size\n");
+                break;
+            }
+            if ((count < 1) || (count >= BUFFER_MAX)) {
+                LOGE("invalid size %d\n", count);
+                break;
+            }
+            if (readx(s, buf, count)) {
+                LOGE("failed to read command\n");
+                break;
+            }
+            buf[count] = 0;
+            if (execute(s, buf)) break;
+        }
+        LOGI("closing connection\n");
+        close(s);
+    }
+
+    return 0;
+}
diff --git a/cmds/keystore/keystore.h b/cmds/keystore/keystore.h
new file mode 100644
index 0000000..35acf0b
--- /dev/null
+++ b/cmds/keystore/keystore.h
@@ -0,0 +1,57 @@
+/*
+**
+** 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.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#define LOG_TAG "keystore"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <utime.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <cutils/sockets.h>
+#include <cutils/log.h>
+#include <cutils/properties.h>
+
+#define SOCKET_PATH "keystore"
+
+
+/* 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 BUFFER_MAX      1024  /* input buffer for commands */
+#define TOKEN_MAX       8     /* max number of arguments in buffer */
+#define REPLY_MAX       1024  /* largest reply allowed */
+#define KEYNAME_LENGTH  128
+
+/* 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);
diff --git a/include/utils/BackupHelpers.h b/include/utils/BackupHelpers.h
index 24b6c9e..f60f4ea 100644
--- a/include/utils/BackupHelpers.h
+++ b/include/utils/BackupHelpers.h
@@ -118,7 +118,7 @@
 };
 
 int back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD,
-        char const* fileBase, char const* const* files, int fileCount);
+        char const* const* files, char const* const *keys, int fileCount);
 
 
 #define TEST_BACKUP_HELPERS 1
@@ -127,6 +127,8 @@
 int backup_helper_test_empty();
 int backup_helper_test_four();
 int backup_helper_test_files();
+int backup_helper_test_null_base();
+int backup_helper_test_missing_file();
 int backup_helper_test_data_writer();
 int backup_helper_test_data_reader();
 #endif
diff --git a/libs/utils/BackupData.cpp b/libs/utils/BackupData.cpp
index 120f23d..8c9f875 100644
--- a/libs/utils/BackupData.cpp
+++ b/libs/utils/BackupData.cpp
@@ -327,7 +327,7 @@
     }
     size_t size = m_header.app.packageLen;
     char* buf = packageName->lockBuffer(size);
-    if (packageName == NULL) {
+    if (buf == NULL) {
         packageName->unlockBuffer();
         m_status = ENOMEM;
         return m_status;
diff --git a/libs/utils/BackupHelpers.cpp b/libs/utils/BackupHelpers.cpp
index 7f423a8..4c3e37d 100644
--- a/libs/utils/BackupHelpers.cpp
+++ b/libs/utils/BackupHelpers.cpp
@@ -41,8 +41,8 @@
 #define MAGIC0 0x70616e53 // Snap
 #define MAGIC1 0x656c6946 // File
 
-#if 0 // TEST_BACKUP_HELPERS
-#define LOGP(x...) printf(x)
+#if 1 // TEST_BACKUP_HELPERS
+#define LOGP(f, x...) printf(f "\n", x)
 #else
 #define LOGP(x...) LOGD(x)
 #endif
@@ -62,6 +62,12 @@
     int nameLen;
 };
 
+struct FileRec {
+    char const* file; // this object does not own this string
+    bool deleted;
+    FileState s;
+};
+
 const static int ROUND_UP[4] = { 0, 3, 2, 1 };
 
 static inline int
@@ -92,8 +98,8 @@
         FileState file;
         char filenameBuf[128];
 
-        amt = read(fd, &file, sizeof(file));
-        if (amt != sizeof(file)) {
+        amt = read(fd, &file, sizeof(FileState));
+        if (amt != sizeof(FileState)) {
             LOGW("read_snapshot_file FileState truncated/error with read at %d bytes\n", bytesRead);
             return 1;
         }
@@ -128,20 +134,25 @@
 }
 
 static int
-write_snapshot_file(int fd, const KeyedVector<String8,FileState>& snapshot)
+write_snapshot_file(int fd, const KeyedVector<String8,FileRec>& snapshot)
 {
+    int fileCount = 0;
     int bytesWritten = sizeof(SnapshotHeader);
     // preflight size
     const int N = snapshot.size();
     for (int i=0; i<N; i++) {
-        const String8& name = snapshot.keyAt(i);
-        bytesWritten += sizeof(FileState) + round_up(name.length());
+        const FileRec& g = snapshot.valueAt(i);
+        if (!g.deleted) {
+            const String8& name = snapshot.keyAt(i);
+            bytesWritten += sizeof(FileState) + round_up(name.length());
+            fileCount++;
+        }
     }
 
     LOGP("write_snapshot_file fd=%d\n", fd);
 
     int amt;
-    SnapshotHeader header = { MAGIC0, N, MAGIC1, bytesWritten };
+    SnapshotHeader header = { MAGIC0, fileCount, MAGIC1, bytesWritten };
 
     amt = write(fd, &header, sizeof(header));
     if (amt != sizeof(header)) {
@@ -149,32 +160,34 @@
         return errno;
     }
 
-    for (int i=0; i<header.fileCount; i++) {
-        const String8& name = snapshot.keyAt(i);
-        FileState file = snapshot.valueAt(i);
-        int nameLen = file.nameLen = name.length();
+    for (int i=0; i<N; i++) {
+        FileRec r = snapshot.valueAt(i);
+        if (!r.deleted) {
+            const String8& name = snapshot.keyAt(i);
+            int nameLen = r.s.nameLen = name.length();
 
-        amt = write(fd, &file, sizeof(file));
-        if (amt != sizeof(file)) {
-            LOGW("write_snapshot_file error writing header %s", strerror(errno));
-            return 1;
-        }
-
-        // filename is not NULL terminated, but it is padded
-        amt = write(fd, name.string(), nameLen);
-        if (amt != nameLen) {
-            LOGW("write_snapshot_file error writing filename %s", strerror(errno));
-            return 1;
-        }
-        int paddingLen = ROUND_UP[nameLen % 4];
-        if (paddingLen != 0) {
-            int padding = 0xabababab;
-            amt = write(fd, &padding, paddingLen);
-            if (amt != paddingLen) {
-                LOGW("write_snapshot_file error writing %d bytes of filename padding %s",
-                        paddingLen, strerror(errno));
+            amt = write(fd, &r.s, sizeof(FileState));
+            if (amt != sizeof(FileState)) {
+                LOGW("write_snapshot_file error writing header %s", strerror(errno));
                 return 1;
             }
+
+            // filename is not NULL terminated, but it is padded
+            amt = write(fd, name.string(), nameLen);
+            if (amt != nameLen) {
+                LOGW("write_snapshot_file error writing filename %s", strerror(errno));
+                return 1;
+            }
+            int paddingLen = ROUND_UP[nameLen % 4];
+            if (paddingLen != 0) {
+                int padding = 0xabababab;
+                amt = write(fd, &padding, paddingLen);
+                if (amt != paddingLen) {
+                    LOGW("write_snapshot_file error writing %d bytes of filename padding %s",
+                            paddingLen, strerror(errno));
+                    return 1;
+                }
+            }
         }
     }
 
@@ -190,9 +203,9 @@
 
 static int
 write_update_file(BackupDataWriter* dataStream, int fd, const String8& key,
-        const String8& realFilename)
+        char const* realFilename)
 {
-    LOGP("write_update_file %s (%s)\n", realFilename.string(), key.string());
+    LOGP("write_update_file %s (%s)\n", realFilename, key.string());
 
     const int bufsize = 4*1024;
     int err;
@@ -237,8 +250,7 @@
             }
         }
         LOGE("write_update_file size mismatch for %s. expected=%d actual=%d."
-                " You aren't doing proper locking!",
-                realFilename.string(), fileSize, fileSize-bytesLeft);
+                " You aren't doing proper locking!", realFilename, fileSize, fileSize-bytesLeft);
     }
 
     free(buf);
@@ -247,10 +259,10 @@
 }
 
 static int
-write_update_file(BackupDataWriter* dataStream, const String8& key, const String8& realFilename)
+write_update_file(BackupDataWriter* dataStream, const String8& key, char const* realFilename)
 {
     int err;
-    int fd = open(realFilename.string(), O_RDONLY);
+    int fd = open(realFilename, O_RDONLY);
     if (fd == -1) {
         return errno;
     }
@@ -281,12 +293,11 @@
 
 int
 back_up_files(int oldSnapshotFD, BackupDataWriter* dataStream, int newSnapshotFD,
-        char const* fileBase, char const* const* files, int fileCount)
+        char const* const* files, char const* const* keys, int fileCount)
 {
     int err;
-    const String8 base(fileBase);
     KeyedVector<String8,FileState> oldSnapshot;
-    KeyedVector<String8,FileState> newSnapshot;
+    KeyedVector<String8,FileRec> newSnapshot;
 
     if (oldSnapshotFD != -1) {
         err = read_snapshot_file(oldSnapshotFD, &oldSnapshot);
@@ -297,26 +308,29 @@
     }
 
     for (int i=0; i<fileCount; i++) {
-        String8 name(files[i]);
-        FileState s;
+        String8 key(keys[i]);
+        FileRec r;
+        char const* file = r.file = files[i];
         struct stat st;
-        String8 realFilename(base);
-        realFilename.appendPath(name);
 
-        err = stat(realFilename.string(), &st);
+        err = stat(file, &st);
         if (err != 0) {
-            LOGW("Error stating file %s", realFilename.string());
-            continue;
+            LOGW("Error stating file %s", file);
+            r.deleted = true;
+        } else {
+            r.deleted = false;
+            r.s.modTime_sec = st.st_mtime;
+            r.s.modTime_nsec = 0; // workaround sim breakage
+            //r.s.modTime_nsec = st.st_mtime_nsec;
+            r.s.size = st.st_size;
+            // we compute the crc32 later down below, when we already have the file open.
+
+            if (newSnapshot.indexOfKey(key) >= 0) {
+                LOGP("back_up_files key already in use '%s'", key.string());
+                return -1;
+            }
         }
-
-        s.modTime_sec = st.st_mtime;
-        s.modTime_nsec = 0; // workaround sim breakage
-        //s.modTime_nsec = st.st_mtime_nsec;
-        s.size = st.st_size;
-
-        // we compute the crc32 later down below, when we already have the file open.
-
-        newSnapshot.add(name, s);
+        newSnapshot.add(key, r);
     }
 
     int n = 0;
@@ -326,46 +340,42 @@
     while (n<N && m<fileCount) {
         const String8& p = oldSnapshot.keyAt(n);
         const String8& q = newSnapshot.keyAt(m);
+        FileRec& g = newSnapshot.editValueAt(m);
         int cmp = p.compare(q);
-        if (cmp > 0) {
-            // file added
-            String8 realFilename(base);
-            realFilename.appendPath(q);
-            LOGP("file added: %s\n", realFilename.string());
-            write_update_file(dataStream, q, realFilename);
-            m++;
-        }
-        else if (cmp < 0) {
+        if (g.deleted || cmp < 0) {
             // file removed
-            LOGP("file removed: %s\n", p.string());
+            LOGP("file removed: %s", p.string());
+            g.deleted = true; // They didn't mention the file, but we noticed that it's gone.
             dataStream->WriteEntityHeader(p, -1);
             n++;
         }
+        else if (cmp > 0) {
+            // file added
+            LOGP("file added: %s", g.file);
+            write_update_file(dataStream, q, g.file);
+            m++;
+        }
         else {
-
             // both files exist, check them
-            String8 realFilename(base);
-            realFilename.appendPath(q);
             const FileState& f = oldSnapshot.valueAt(n);
-            FileState& g = newSnapshot.editValueAt(m);
 
-            int fd = open(realFilename.string(), O_RDONLY);
+            int fd = open(g.file, O_RDONLY);
             if (fd < 0) {
                 // We can't open the file.  Don't report it as a delete either.  Let the
                 // server keep the old version.  Maybe they'll be able to deal with it
                 // on restore.
-                LOGP("Unable to open file %s - skipping", realFilename.string());
+                LOGP("Unable to open file %s - skipping", g.file);
             } else {
-                g.crc32 = compute_crc32(fd);
+                g.s.crc32 = compute_crc32(fd);
 
-                LOGP("%s\n", q.string());
-                LOGP("  new: modTime=%d,%d size=%-3d crc32=0x%08x\n",
+                LOGP("%s", q.string());
+                LOGP("  new: modTime=%d,%d size=%-3d crc32=0x%08x",
                         f.modTime_sec, f.modTime_nsec, f.size, f.crc32);
-                LOGP("  old: modTime=%d,%d size=%-3d crc32=0x%08x\n",
-                        g.modTime_sec, g.modTime_nsec, g.size, g.crc32);
-                if (f.modTime_sec != g.modTime_sec || f.modTime_nsec != g.modTime_nsec
-                        || f.size != g.size || f.crc32 != g.crc32) {
-                    write_update_file(dataStream, fd, p, realFilename);
+                LOGP("  old: modTime=%d,%d size=%-3d crc32=0x%08x",
+                        g.s.modTime_sec, g.s.modTime_nsec, g.s.size, g.s.crc32);
+                if (f.modTime_sec != g.s.modTime_sec || f.modTime_nsec != g.s.modTime_nsec
+                        || f.size != g.s.size || f.crc32 != g.s.crc32) {
+                    write_update_file(dataStream, fd, p, g.file);
                 }
 
                 close(fd);
@@ -384,9 +394,8 @@
     // these were added
     while (m<fileCount) {
         const String8& q = newSnapshot.keyAt(m);
-        String8 realFilename(base);
-        realFilename.appendPath(q);
-        write_update_file(dataStream, q, realFilename);
+        FileRec& g = newSnapshot.editValueAt(m);
+        write_update_file(dataStream, q, g.file);
         m++;
     }
 
@@ -475,7 +484,7 @@
 {
     int err;
     int fd;
-    KeyedVector<String8,FileState> snapshot;
+    KeyedVector<String8,FileRec> snapshot;
     const char* filename = SCRATCH_DIR "backup_helper_test_empty.snap";
 
     system("rm -r " SCRATCH_DIR);
@@ -534,7 +543,7 @@
 {
     int err;
     int fd;
-    KeyedVector<String8,FileState> snapshot;
+    KeyedVector<String8,FileRec> snapshot;
     const char* filename = SCRATCH_DIR "backup_helper_test_four.snap";
 
     system("rm -r " SCRATCH_DIR);
@@ -549,38 +558,45 @@
 
     String8 filenames[4];
     FileState states[4];
+    FileRec r;
+    r.deleted = false;
+    r.file = NULL;
 
     states[0].modTime_sec = 0xfedcba98;
     states[0].modTime_nsec = 0xdeadbeef;
     states[0].size = 0xababbcbc;
     states[0].crc32 = 0x12345678;
     states[0].nameLen = -12;
+    r.s = states[0];
     filenames[0] = String8("bytes_of_padding");
-    snapshot.add(filenames[0], states[0]);
+    snapshot.add(filenames[0], r);
 
     states[1].modTime_sec = 0x93400031;
     states[1].modTime_nsec = 0xdeadbeef;
     states[1].size = 0x88557766;
     states[1].crc32 = 0x22334422;
     states[1].nameLen = -1;
+    r.s = states[1];
     filenames[1] = String8("bytes_of_padding3");
-    snapshot.add(filenames[1], states[1]);
+    snapshot.add(filenames[1], r);
 
     states[2].modTime_sec = 0x33221144;
     states[2].modTime_nsec = 0xdeadbeef;
     states[2].size = 0x11223344;
     states[2].crc32 = 0x01122334;
     states[2].nameLen = 0;
+    r.s = states[2];
     filenames[2] = String8("bytes_of_padding_2");
-    snapshot.add(filenames[2], states[2]);
+    snapshot.add(filenames[2], r);
 
     states[3].modTime_sec = 0x33221144;
     states[3].modTime_nsec = 0xdeadbeef;
     states[3].size = 0x11223344;
     states[3].crc32 = 0x01122334;
     states[3].nameLen = 0;
+    r.s = states[3];
     filenames[3] = String8("bytes_of_padding__1");
-    snapshot.add(filenames[3], states[3]);
+    snapshot.add(filenames[3], r);
 
     err = write_snapshot_file(fd, snapshot);
 
@@ -982,6 +998,14 @@
     write_text_file(SCRATCH_DIR "data/h", "h\nhh\n");
 
     char const* files_before[] = {
+        SCRATCH_DIR "data/b",
+        SCRATCH_DIR "data/c",
+        SCRATCH_DIR "data/d",
+        SCRATCH_DIR "data/e",
+        SCRATCH_DIR "data/f"
+    };
+
+    char const* keys_before[] = {
         "data/b",
         "data/c",
         "data/d",
@@ -1004,7 +1028,7 @@
     {
         BackupDataWriter dataStream(dataStreamFD);
 
-        err = back_up_files(-1, &dataStream, newSnapshotFD, SCRATCH_DIR, files_before, 5);
+        err = back_up_files(-1, &dataStream, newSnapshotFD, files_before, keys_before, 5);
         if (err != 0) {
             return err;
         }
@@ -1035,6 +1059,15 @@
     unlink(SCRATCH_DIR "data/f");
 
     char const* files_after[] = {
+        SCRATCH_DIR "data/a", // added
+        SCRATCH_DIR "data/b", // same
+        SCRATCH_DIR "data/c", // different mod time
+        SCRATCH_DIR "data/d", // different size (same mod time)
+        SCRATCH_DIR "data/e", // different contents (same mod time, same size)
+        SCRATCH_DIR "data/g"  // added
+    };
+
+    char const* keys_after[] = {
         "data/a", // added
         "data/b", // same
         "data/c", // different mod time
@@ -1064,8 +1097,7 @@
     {
         BackupDataWriter dataStream(dataStreamFD);
 
-        err = back_up_files(oldSnapshotFD, &dataStream, newSnapshotFD, SCRATCH_DIR,
-                files_after, 6);
+        err = back_up_files(oldSnapshotFD, &dataStream, newSnapshotFD, files_after, keys_after, 6);
         if (err != 0) {
             return err;
         }
@@ -1078,6 +1110,109 @@
     return 0;
 }
 
+int
+backup_helper_test_null_base()
+{
+    int err;
+    int oldSnapshotFD;
+    int dataStreamFD;
+    int newSnapshotFD;
+
+    system("rm -r " SCRATCH_DIR);
+    mkdir(SCRATCH_DIR, 0777);
+    mkdir(SCRATCH_DIR "data", 0777);
+
+    write_text_file(SCRATCH_DIR "data/a", "a\naa\n");
+
+    char const* files[] = {
+        SCRATCH_DIR "data/a",
+    };
+
+    char const* keys[] = {
+        "a",
+    };
+
+    dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
+    if (dataStreamFD == -1) {
+        fprintf(stderr, "error creating: %s\n", strerror(errno));
+        return errno;
+    }
+
+    newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
+    if (newSnapshotFD == -1) {
+        fprintf(stderr, "error creating: %s\n", strerror(errno));
+        return errno;
+    }
+
+    {
+        BackupDataWriter dataStream(dataStreamFD);
+
+        err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
+        if (err != 0) {
+            return err;
+        }
+    }
+
+    close(dataStreamFD);
+    close(newSnapshotFD);
+
+    return 0;
+}
+
+int
+backup_helper_test_missing_file()
+{
+    int err;
+    int oldSnapshotFD;
+    int dataStreamFD;
+    int newSnapshotFD;
+
+    system("rm -r " SCRATCH_DIR);
+    mkdir(SCRATCH_DIR, 0777);
+    mkdir(SCRATCH_DIR "data", 0777);
+
+    write_text_file(SCRATCH_DIR "data/b", "b\nbb\n");
+
+    char const* files[] = {
+        SCRATCH_DIR "data/a",
+        SCRATCH_DIR "data/b",
+        SCRATCH_DIR "data/c",
+    };
+
+    char const* keys[] = {
+        "a",
+        "b",
+        "c",
+    };
+
+    dataStreamFD = creat(SCRATCH_DIR "null_base.data", 0666);
+    if (dataStreamFD == -1) {
+        fprintf(stderr, "error creating: %s\n", strerror(errno));
+        return errno;
+    }
+
+    newSnapshotFD = creat(SCRATCH_DIR "null_base.snap", 0666);
+    if (newSnapshotFD == -1) {
+        fprintf(stderr, "error creating: %s\n", strerror(errno));
+        return errno;
+    }
+
+    {
+        BackupDataWriter dataStream(dataStreamFD);
+
+        err = back_up_files(-1, &dataStream, newSnapshotFD, files, keys, 1);
+        if (err != 0) {
+            return err;
+        }
+    }
+
+    close(dataStreamFD);
+    close(newSnapshotFD);
+
+    return 0;
+}
+
+
 #endif // TEST_BACKUP_HELPERS
 
 }
diff --git a/opengl/tools/glgen/gen b/opengl/tools/glgen/gen
index 011a6ed..9bff0b2 100755
--- a/opengl/tools/glgen/gen
+++ b/opengl/tools/glgen/gen
@@ -4,14 +4,31 @@
 rm -rf out generated
 
 mkdir out
+
+# Create dummy Java files for Android APIs that are used by the code we generate.
+# This allows us to test the generated code without building the rest of Android.
+
 mkdir -p out/javax/microedition/khronos/opengles
 mkdir -p out/com/google/android/gles_jni
+mkdir -p out/android/app
 mkdir -p out/android/graphics
 mkdir -p out/android/opengl
+mkdir -p out/android/content
+mkdir -p out/android/content/pm
+mkdir -p out/android/os
+mkdir -p out/android/util
 
 echo "package android.graphics;" > out/android/graphics/Canvas.java
 echo "public interface Canvas {}" >> out/android/graphics/Canvas.java
 
+echo "package android.app; import android.content.pm.IPackageManager; public class ActivityThread { public static final ActivityThread currentActivityThread() { return null; } public static final String currentPackageName(){ return null; } public static IPackageManager getPackageManager() { return null;} }" > out/android/app/ActivityThread.java
+# echo "package android.content; import android.content.pm.PackageManager; public interface Context { public PackageManager getPackageManager(); }" > out/android/content/Context.java
+echo "package android.content.pm; public class ApplicationInfo {public int targetSdkVersion;}" > out/android/content/pm/ApplicationInfo.java
+echo "package android.content.pm; public interface IPackageManager {ApplicationInfo getApplicationInfo(java.lang.String packageName, int flags) throws android.os.RemoteException;}" > out/android/content/pm/IPackageManager.java
+echo "package android.os; public class Build {public static class VERSION_CODES { public static final int CUPCAKE = 3;};	}" > out/android/os/Build.java
+echo "package android.os; public class RemoteException extends Exception {}" > out/android/os/RemoteException.java
+echo "package android.util; public class Log {public static void w(String a, String b) {} public static void e(String a, String b) {}}" > out/android/util/Log.java
+
 GLFILE=out/javax/microedition/khronos/opengles/GL.java
 cp stubs/jsr239/GLHeader.java-if $GLFILE
 
diff --git a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
index 4896acb..4494643 100644
--- a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
+++ b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
@@ -44,9 +44,11 @@
 static jclass UOEClass;
 static jclass IAEClass;
 static jclass AIOOBEClass;
+static jclass G11ImplClass;
 static jmethodID getBasePointerID;
 static jmethodID getBaseArrayID;
 static jmethodID getBaseArrayOffsetID;
+static jmethodID allowIndirectBuffersID;
 static jfieldID positionID;
 static jfieldID limitID;
 static jfieldID elementSizeShiftID;
@@ -62,13 +64,17 @@
     jclass bufferClassLocal = _env->FindClass("java/nio/Buffer");
     bufferClass = (jclass) _env->NewGlobalRef(bufferClassLocal);
 
+    jclass g11impClassLocal = _env->FindClass("com/google/android/gles_jni/GLImpl");
+    G11ImplClass = (jclass) _env->NewGlobalRef(g11impClassLocal);
+
     getBasePointerID = _env->GetStaticMethodID(nioAccessClass,
             "getBasePointer", "(Ljava/nio/Buffer;)J");
     getBaseArrayID = _env->GetStaticMethodID(nioAccessClass,
             "getBaseArray", "(Ljava/nio/Buffer;)Ljava/lang/Object;");
     getBaseArrayOffsetID = _env->GetStaticMethodID(nioAccessClass,
             "getBaseArrayOffset", "(Ljava/nio/Buffer;)I");
-
+    allowIndirectBuffersID = _env->GetStaticMethodID(g11impClassLocal,
+            "allowIndirectBuffers", "(Ljava/lang/String;)Z");
     positionID = _env->GetFieldID(bufferClass, "position", "I");
     limitID = _env->GetFieldID(bufferClass, "limit", "I");
     elementSizeShiftID =
@@ -118,6 +124,9 @@
     
     *array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
             getBaseArrayID, buffer);
+    if (*array == NULL) {
+        return (void*) NULL;
+    }
     offset = _env->CallStaticIntMethod(nioAccessClass,
             getBaseArrayOffsetID, buffer);
     data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
@@ -132,17 +141,43 @@
 					   commit ? 0 : JNI_ABORT);
 }
 
+extern "C" {
+extern char*  __progname;
+}
+
+static bool
+allowIndirectBuffers(JNIEnv *_env) {
+    static jint sIndirectBufferCompatability;
+    if (sIndirectBufferCompatability == 0) {
+        jobject appName = _env->NewStringUTF(::__progname);
+        sIndirectBufferCompatability = _env->CallStaticBooleanMethod(G11ImplClass, allowIndirectBuffersID, appName) ? 2 : 1;
+    }
+    return sIndirectBufferCompatability == 2;
+}
+
 static void *
 getDirectBufferPointer(JNIEnv *_env, jobject buffer) {
-    char* buf = (char*) _env->GetDirectBufferAddress(buffer);
+    if (!buffer) {
+        return NULL;
+    }
+    void* buf = _env->GetDirectBufferAddress(buffer);
     if (buf) {
         jint position = _env->GetIntField(buffer, positionID);
         jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
-        buf += position << elementSizeShift;
+        buf = ((char*) buf) + (position << elementSizeShift);
     } else {
-        _env->ThrowNew(IAEClass, "Must use a native order direct Buffer");
+        if (allowIndirectBuffers(_env)) {
+            jarray array = 0;
+            jint remaining;
+            buf = getPointer(_env, buffer, &array, &remaining);
+            if (array) {
+                releasePointer(_env, array, buf, 0);
+            }
+        } else {
+            _env->ThrowNew(IAEClass, "Must use a native order direct Buffer");
+        }
     }
-    return (void*) buf;
+    return buf;
 }
 
 static int
diff --git a/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl b/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl
index db3a41c..fe60c5d 100644
--- a/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl
+++ b/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl
@@ -18,6 +18,12 @@
 
 package com.google.android.gles_jni;
 
+import android.app.ActivityThread;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
+import android.os.Build;
+import android.util.Log;
+
 import java.nio.Buffer;
 import javax.microedition.khronos.opengles.GL10;
 import javax.microedition.khronos.opengles.GL10Ext;
@@ -42,7 +48,28 @@
     public GLImpl() {
     }
 
-     public void glGetPointerv(int pname, java.nio.Buffer[] params) {
-         throw new UnsupportedOperationException("glGetPointerv");
-     }
+    public void glGetPointerv(int pname, java.nio.Buffer[] params) {
+        throw new UnsupportedOperationException("glGetPointerv");
+    }
+
+    private static boolean allowIndirectBuffers(String appName) {
+        boolean result = false;
+        int version = 0;
+        IPackageManager pm = ActivityThread.getPackageManager();
+        try {
+            ApplicationInfo applicationInfo = pm.getApplicationInfo(appName, 0);
+            if (applicationInfo != null) {
+                version = applicationInfo.targetSdkVersion;
+            }
+        } catch (android.os.RemoteException e) {
+            // ignore
+        }
+        Log.e("OpenGLES", String.format(
+            "Application %s (SDK target %d) called a GL11 Pointer method with an indirect Buffer.",
+            appName, version));
+        if (version <= Build.VERSION_CODES.CUPCAKE) {
+            result = true;
+        }
+        return result;
+    }
 
diff --git a/tts/java/android/tts/ITts.aidl b/tts/java/android/tts/ITts.aidl
deleted file mode 100755
index 3558f5a..0000000
--- a/tts/java/android/tts/ITts.aidl
+++ /dev/null
@@ -1,57 +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.tts;

-

-import android.tts.ITtsCallback;

-

-import android.content.Intent;

-

-/**

- * AIDL for the TTS Service

- * ITts.java is autogenerated from this.

- *

- * {@hide}

- */

-interface ITts {

-    void setSpeechRate(in int speechRate);

-

-    void speak(in String text, in int queueMode, in String[] params);

-

-    boolean isSpeaking();

-

-    void stop();

-

-    void addSpeech(in String text, in String packageName, in int resId);

-

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

-

-    void setLanguage(in String language);

-

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

-

-    void playEarcon(in String earcon, in int queueMode, in String[] params);

-

-    void addEarcon(in String earcon, in String packageName, in int resId);

-

-    void addEarconFile(in String earcon, in String filename);

-

-    void registerCallback(ITtsCallback cb);

-

-    void unregisterCallback(ITtsCallback cb);

-

-    void playSilence(in long duration, in int queueMode, in String[] params);

-}

diff --git a/tts/java/android/tts/ITtsCallback.aidl b/tts/java/android/tts/ITtsCallback.aidl
deleted file mode 100755
index 1314010..0000000
--- a/tts/java/android/tts/ITtsCallback.aidl
+++ /dev/null
@@ -1,27 +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.tts;
-
-/**
- * AIDL for the callback from the TTS Service
- * ITtsCallback.java is autogenerated from this.
- *
- * {@hide}
- */
-oneway interface ITtsCallback {
-    void markReached(String mark);
-}
diff --git a/tts/java/android/tts/SynthProxy.java b/tts/java/android/tts/SynthProxy.java
deleted file mode 100755
index e065f40..0000000
--- a/tts/java/android/tts/SynthProxy.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (C) 2009 Google Inc.
- *
- * 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.tts;
-
-import android.util.Log;
-import java.lang.ref.WeakReference;
-
-/**
- * @hide
- *
- * The SpeechSynthesis class provides a high-level api to create and play
- * synthesized speech. This class is used internally to talk to a native
- * TTS library that implements the interface defined in
- * frameworks/base/include/tts/TtsEngine.h
- *
- */
-@SuppressWarnings("unused")
-public class SynthProxy {
-
-    //
-    // External API
-    //
-
-    /**
-     * Constructor; pass the location of the native TTS .so to use.
-     */
-    public SynthProxy(String nativeSoLib) {
-        Log.e("TTS is loading", nativeSoLib);
-        native_setup(new WeakReference<SynthProxy>(this), nativeSoLib);
-    }
-
-    /**
-     * Stops and clears the AudioTrack.
-     */
-    public void stop() {
-        native_stop(mJniData);
-    }
-
-    /**
-     * Synthesize speech and speak it directly using AudioTrack.
-     */
-    public void speak(String text) {
-        native_speak(mJniData, text);
-    }
-
-    /**
-     * Synthesize speech to a file. The current implementation writes a valid
-     * WAV file to the given path, assuming it is writable. Something like
-     * "/sdcard/???.wav" is recommended.
-     */
-    public void synthesizeToFile(String text, String filename) {
-        native_synthesizeToFile(mJniData, text, filename);
-    }
-
-    // TODO add IPA methods
-
-    /**
-     * Sets the language
-     */
-    public void setLanguage(String language) {
-        native_setLanguage(mJniData, language);
-    }
-
-    /**
-     * Sets the speech rate
-     */
-    public final void setSpeechRate(int speechRate) {
-        native_setSpeechRate(mJniData, speechRate);
-    }
-
-
-    /**
-     * Plays the given audio buffer
-     */
-    public void playAudioBuffer(int bufferPointer, int bufferSize) {
-        native_playAudioBuffer(mJniData, bufferPointer, bufferSize);
-    }
-
-    /**
-     * Gets the currently set language
-     */
-    public String getLanguage() {
-        return native_getLanguage(mJniData);
-    }
-
-    /**
-     * Gets the currently set rate
-     */
-    public int getRate() {
-        return native_getRate(mJniData);
-    }
-
-    /**
-     * Shuts down the native synthesizer
-     */
-    public void shutdown()  {
-        native_shutdown(mJniData);
-    }
-
-    //
-    // Internal
-    //
-
-    protected void finalize() {
-        native_finalize(mJniData);
-        mJniData = 0;
-    }
-
-    static {
-        System.loadLibrary("ttssynthproxy");
-    }
-
-    private final static String TAG = "SynthProxy";
-
-    /**
-     * Accessed by native methods
-     */
-    private int mJniData = 0;
-
-    private native final void native_setup(Object weak_this,
-            String nativeSoLib);
-
-    private native final void native_finalize(int jniData);
-
-    private native final void native_stop(int jniData);
-
-    private native final void native_speak(int jniData, String text);
-
-    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_setSpeechRate(int jniData, int speechRate);
-
-    // TODO add buffer format
-    private native final void native_playAudioBuffer(int jniData, int bufferPointer, int bufferSize);
-
-    private native final String native_getLanguage(int jniData);
-
-    private native final int native_getRate(int jniData);
-
-    private native final void native_shutdown(int jniData);
-
-
-    /**
-     * Callback from the C layer
-     */
-    @SuppressWarnings("unused")
-    private static void postNativeSpeechSynthesizedInJava(Object tts_ref,
-            int bufferPointer, int bufferSize) {
-
-        Log.i("TTS plugin debug", "bufferPointer: " + bufferPointer
-                + " bufferSize: " + bufferSize);
-
-        SynthProxy nativeTTS = (SynthProxy)((WeakReference)tts_ref).get();
-        // TODO notify TTS service of synthesis/playback completion,
-        //      method definition to be changed.
-    }
-}
diff --git a/tts/java/android/tts/TtsService.java b/tts/java/android/tts/TtsService.java
deleted file mode 100755
index 2373e96..0000000
--- a/tts/java/android/tts/TtsService.java
+++ /dev/null
@@ -1,734 +0,0 @@
-/*
- * Copyright (C) 2009 Google Inc.
- *
- * 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.tts;
-
-import android.tts.ITts.Stub;
-
-import android.app.Service;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.media.MediaPlayer;
-import android.media.MediaPlayer.OnCompletionListener;
-import android.net.Uri;
-import android.os.IBinder;
-import android.os.RemoteCallbackList;
-import android.os.RemoteException;
-import android.preference.PreferenceManager;
-import android.util.Log;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.concurrent.locks.ReentrantLock;
-
-/**
- * @hide Synthesizes speech from text. This is implemented as a service so that
- *       other applications can call the TTS without needing to bundle the TTS
- *       in the build.
- *
- */
-public class TtsService extends Service implements OnCompletionListener {
-
-    private static class SpeechItem {
-        public static final int SPEECH = 0;
-        public static final int EARCON = 1;
-        public static final int SILENCE = 2;
-        public String mText = null;
-        public ArrayList<String> mParams = null;
-        public int mType = SPEECH;
-        public long mDuration = 0;
-
-        public SpeechItem(String text, ArrayList<String> params, int itemType) {
-            mText = text;
-            mParams = params;
-            mType = itemType;
-        }
-
-        public SpeechItem(long silenceTime) {
-            mDuration = silenceTime;
-        }
-    }
-
-    /**
-     * Contains the information needed to access a sound resource; the name of
-     * the package that contains the resource and the resID of the resource
-     * within that package.
-     */
-    private static class SoundResource {
-        public String mSourcePackageName = null;
-        public int mResId = -1;
-        public String mFilename = null;
-
-        public SoundResource(String packageName, int id) {
-            mSourcePackageName = packageName;
-            mResId = id;
-            mFilename = null;
-        }
-
-        public SoundResource(String file) {
-            mSourcePackageName = null;
-            mResId = -1;
-            mFilename = file;
-        }
-    }
-
-    private static final String ACTION = "android.intent.action.USE_TTS";
-    private static final String CATEGORY = "android.intent.category.TTS";
-    private static final String PKGNAME = "android.tts";
-
-    final RemoteCallbackList<ITtsCallback> mCallbacks = new RemoteCallbackList<ITtsCallback>();
-
-    private Boolean mIsSpeaking;
-    private ArrayList<SpeechItem> mSpeechQueue;
-    private HashMap<String, SoundResource> mEarcons;
-    private HashMap<String, SoundResource> mUtterances;
-    private MediaPlayer mPlayer;
-    private TtsService mSelf;
-
-    private SharedPreferences prefs;
-
-    private final ReentrantLock speechQueueLock = new ReentrantLock();
-    private final ReentrantLock synthesizerLock = new ReentrantLock();
-
-    private SynthProxy nativeSynth;
-
-    @Override
-    public void onCreate() {
-        super.onCreate();
-        Log.i("TTS", "TTS starting");
-
-        // TODO: Make this work when the settings are done in the main Settings
-        // app.
-        prefs = PreferenceManager.getDefaultSharedPreferences(this);
-
-        PackageManager pm = this.getPackageManager();
-        String soLibPath = "";
-        try {
-            soLibPath = pm.getApplicationInfo("com.svox.pico", 0).dataDir;
-        } catch (NameNotFoundException e) {
-            // This exception cannot actually happen as com.svox.pico is
-            // included with the system image.
-            e.printStackTrace();
-        }
-        soLibPath = soLibPath + "/lib/libttspico.so";
-        nativeSynth = new SynthProxy(soLibPath);
-
-        mSelf = this;
-        mIsSpeaking = false;
-
-        mEarcons = new HashMap<String, SoundResource>();
-        mUtterances = new HashMap<String, SoundResource>();
-
-        mSpeechQueue = new ArrayList<SpeechItem>();
-        mPlayer = null;
-
-        setLanguage(prefs.getString("lang_pref", "en-rUS"));
-        setSpeechRate(Integer.parseInt(prefs.getString("rate_pref", "140")));
-    }
-
-    @Override
-    public void onDestroy() {
-        super.onDestroy();
-        // Don't hog the media player
-        cleanUpPlayer();
-
-        nativeSynth.shutdown();
-
-        // Unregister all callbacks.
-        mCallbacks.kill();
-    }
-
-    private void setSpeechRate(int rate) {
-        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
-            // not allowed to change the defaults.
-            rate = Integer.parseInt(prefs.getString("rate_pref", "140"));
-        }
-        nativeSynth.setSpeechRate(rate);
-    }
-
-    private void setLanguage(String lang) {
-        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
-            // not
-            // allowed to change the defaults.
-            lang = prefs.getString("lang_pref", "en-rUS");
-        }
-        nativeSynth.setLanguage(lang);
-    }
-
-    /**
-     * Adds a sound resource to the TTS.
-     *
-     * @param text
-     *            The text that should be associated with the sound resource
-     * @param packageName
-     *            The name of the package which has the sound resource
-     * @param resId
-     *            The resource ID of the sound within its package
-     */
-    private void addSpeech(String text, String packageName, int resId) {
-        mUtterances.put(text, new SoundResource(packageName, resId));
-    }
-
-    /**
-     * Adds a sound resource to the TTS.
-     *
-     * @param text
-     *            The text that should be associated with the sound resource
-     * @param filename
-     *            The filename of the sound resource. This must be a complete
-     *            path like: (/sdcard/mysounds/mysoundbite.mp3).
-     */
-    private void addSpeech(String text, String filename) {
-        mUtterances.put(text, new SoundResource(filename));
-    }
-
-    /**
-     * Adds a sound resource to the TTS as an earcon.
-     *
-     * @param earcon
-     *            The text that should be associated with the sound resource
-     * @param packageName
-     *            The name of the package which has the sound resource
-     * @param resId
-     *            The resource ID of the sound within its package
-     */
-    private void addEarcon(String earcon, String packageName, int resId) {
-        mEarcons.put(earcon, new SoundResource(packageName, resId));
-    }
-
-    /**
-     * Adds a sound resource to the TTS as an earcon.
-     *
-     * @param earcon
-     *            The text that should be associated with the sound resource
-     * @param filename
-     *            The filename of the sound resource. This must be a complete
-     *            path like: (/sdcard/mysounds/mysoundbite.mp3).
-     */
-    private void addEarcon(String earcon, String filename) {
-        mEarcons.put(earcon, new SoundResource(filename));
-    }
-
-    /**
-     * Speaks the given text using the specified queueing mode and parameters.
-     *
-     * @param text
-     *            The text that should be spoken
-     * @param queueMode
-     *            0 for no queue (interrupts all previous utterances), 1 for
-     *            queued
-     * @param params
-     *            An ArrayList of parameters. This is not implemented for all
-     *            engines.
-     */
-    private void speak(String text, int queueMode, ArrayList<String> params) {
-        if (queueMode == 0) {
-            stop();
-        }
-        mSpeechQueue.add(new SpeechItem(text, params, SpeechItem.SPEECH));
-        if (!mIsSpeaking) {
-            processSpeechQueue();
-        }
-    }
-
-    /**
-     * Plays the earcon using the specified queueing mode and parameters.
-     *
-     * @param earcon
-     *            The earcon that should be played
-     * @param queueMode
-     *            0 for no queue (interrupts all previous utterances), 1 for
-     *            queued
-     * @param params
-     *            An ArrayList of parameters. This is not implemented for all
-     *            engines.
-     */
-    private void playEarcon(String earcon, int queueMode,
-            ArrayList<String> params) {
-        if (queueMode == 0) {
-            stop();
-        }
-        mSpeechQueue.add(new SpeechItem(earcon, params, SpeechItem.EARCON));
-        if (!mIsSpeaking) {
-            processSpeechQueue();
-        }
-    }
-
-    /**
-     * Stops all speech output and removes any utterances still in the queue.
-     */
-    private void stop() {
-        Log.i("TTS", "Stopping");
-        mSpeechQueue.clear();
-
-        nativeSynth.stop();
-        mIsSpeaking = false;
-        if (mPlayer != null) {
-            try {
-                mPlayer.stop();
-            } catch (IllegalStateException e) {
-                // Do nothing, the player is already stopped.
-            }
-        }
-        Log.i("TTS", "Stopped");
-    }
-
-    public void onCompletion(MediaPlayer arg0) {
-        processSpeechQueue();
-    }
-
-    private void playSilence(long duration, int queueMode,
-            ArrayList<String> params) {
-        if (queueMode == 0) {
-            stop();
-        }
-        mSpeechQueue.add(new SpeechItem(duration));
-        if (!mIsSpeaking) {
-            processSpeechQueue();
-        }
-    }
-
-    private void silence(final long duration) {
-        class SilenceThread implements Runnable {
-            public void run() {
-                try {
-                    Thread.sleep(duration);
-                } catch (InterruptedException e) {
-                    e.printStackTrace();
-                } finally {
-                    processSpeechQueue();
-                }
-            }
-        }
-        Thread slnc = (new Thread(new SilenceThread()));
-        slnc.setPriority(Thread.MIN_PRIORITY);
-        slnc.start();
-    }
-
-    private void speakInternalOnly(final String text,
-            final ArrayList<String> params) {
-        class SynthThread implements Runnable {
-            public void run() {
-                boolean synthAvailable = false;
-                try {
-                    synthAvailable = synthesizerLock.tryLock();
-                    if (!synthAvailable) {
-                        Thread.sleep(100);
-                        Thread synth = (new Thread(new SynthThread()));
-                        synth.setPriority(Thread.MIN_PRIORITY);
-                        synth.start();
-                        return;
-                    }
-                    nativeSynth.speak(text);
-                } catch (InterruptedException e) {
-                    e.printStackTrace();
-                } finally {
-                    // This check is needed because finally will always run;
-                    // even if the
-                    // method returns somewhere in the try block.
-                    if (synthAvailable) {
-                        synthesizerLock.unlock();
-                    }
-                }
-            }
-        }
-        Thread synth = (new Thread(new SynthThread()));
-        synth.setPriority(Thread.MIN_PRIORITY);
-        synth.start();
-    }
-
-    private SoundResource getSoundResource(SpeechItem speechItem) {
-        SoundResource sr = null;
-        String text = speechItem.mText;
-        if (speechItem.mType == SpeechItem.SILENCE) {
-            // Do nothing if this is just silence
-        } else if (speechItem.mType == SpeechItem.EARCON) {
-            sr = mEarcons.get(text);
-        } else {
-            sr = mUtterances.get(text);
-        }
-        return sr;
-    }
-
-    private void dispatchSpeechCompletedCallbacks(String mark) {
-        Log.i("TTS callback", "dispatch started");
-        // Broadcast to all clients the new value.
-        final int N = mCallbacks.beginBroadcast();
-        for (int i = 0; i < N; i++) {
-            try {
-                mCallbacks.getBroadcastItem(i).markReached(mark);
-            } catch (RemoteException e) {
-                // The RemoteCallbackList will take care of removing
-                // the dead object for us.
-            }
-        }
-        mCallbacks.finishBroadcast();
-        Log.i("TTS callback", "dispatch completed to " + N);
-    }
-
-    private void processSpeechQueue() {
-        boolean speechQueueAvailable = false;
-        try {
-            speechQueueAvailable = speechQueueLock.tryLock();
-            if (!speechQueueAvailable) {
-                return;
-            }
-            if (mSpeechQueue.size() < 1) {
-                mIsSpeaking = false;
-                // Dispatch a completion here as this is the
-                // only place where speech completes normally.
-                // Nothing left to say in the queue is a special case
-                // that is always a "mark" - associated text is null.
-                dispatchSpeechCompletedCallbacks("");
-                return;
-            }
-
-            SpeechItem currentSpeechItem = mSpeechQueue.get(0);
-            mIsSpeaking = true;
-            SoundResource sr = getSoundResource(currentSpeechItem);
-            // Synth speech as needed - synthesizer should call
-            // processSpeechQueue to continue running the queue
-            Log.i("TTS processing: ", currentSpeechItem.mText);
-            if (sr == null) {
-                if (currentSpeechItem.mType == SpeechItem.SPEECH) {
-                    // TODO: Split text up into smaller chunks before accepting
-                    // them for processing.
-                    speakInternalOnly(currentSpeechItem.mText,
-                            currentSpeechItem.mParams);
-                } else {
-                    // This is either silence or an earcon that was missing
-                    silence(currentSpeechItem.mDuration);
-                }
-            } else {
-                cleanUpPlayer();
-                if (sr.mSourcePackageName == PKGNAME) {
-                    // Utterance is part of the TTS library
-                    mPlayer = MediaPlayer.create(this, sr.mResId);
-                } else if (sr.mSourcePackageName != null) {
-                    // Utterance is part of the app calling the library
-                    Context ctx;
-                    try {
-                        ctx = this.createPackageContext(sr.mSourcePackageName,
-                                0);
-                    } catch (NameNotFoundException e) {
-                        e.printStackTrace();
-                        mSpeechQueue.remove(0); // Remove it from the queue and
-                        // move on
-                        mIsSpeaking = false;
-                        return;
-                    }
-                    mPlayer = MediaPlayer.create(ctx, sr.mResId);
-                } else {
-                    // Utterance is coming from a file
-                    mPlayer = MediaPlayer.create(this, Uri.parse(sr.mFilename));
-                }
-
-                // Check if Media Server is dead; if it is, clear the queue and
-                // give up for now - hopefully, it will recover itself.
-                if (mPlayer == null) {
-                    mSpeechQueue.clear();
-                    mIsSpeaking = false;
-                    return;
-                }
-                mPlayer.setOnCompletionListener(this);
-                try {
-                    mPlayer.start();
-                } catch (IllegalStateException e) {
-                    mSpeechQueue.clear();
-                    mIsSpeaking = false;
-                    cleanUpPlayer();
-                    return;
-                }
-            }
-            if (mSpeechQueue.size() > 0) {
-                mSpeechQueue.remove(0);
-            }
-        } finally {
-            // This check is needed because finally will always run; even if the
-            // method returns somewhere in the try block.
-            if (speechQueueAvailable) {
-                speechQueueLock.unlock();
-            }
-        }
-    }
-
-    private void cleanUpPlayer() {
-        if (mPlayer != null) {
-            mPlayer.release();
-            mPlayer = null;
-        }
-    }
-
-    /**
-     * Synthesizes the given text using the specified queuing mode and
-     * parameters.
-     *
-     * @param text
-     *            The String of text that should be synthesized
-     * @param params
-     *            An ArrayList of parameters. The first element of this array
-     *            controls the type of voice to use.
-     * @param filename
-     *            The string that gives the full output filename; it should be
-     *            something like "/sdcard/myappsounds/mysound.wav".
-     * @return A boolean that indicates if the synthesis succeeded
-     */
-    private boolean synthesizeToFile(String text, ArrayList<String> params,
-            String filename, boolean calledFromApi) {
-        // Only stop everything if this is a call made by an outside app trying
-        // to
-        // use the API. Do NOT stop if this is a call from within the service as
-        // clearing the speech queue here would be a mistake.
-        if (calledFromApi) {
-            stop();
-        }
-        Log.i("TTS", "Synthesizing to " + filename);
-        boolean synthAvailable = false;
-        try {
-            synthAvailable = synthesizerLock.tryLock();
-            if (!synthAvailable) {
-                return false;
-            }
-            // Don't allow a filename that is too long
-            // TODO use platform constant
-            if (filename.length() > 250) {
-                return false;
-            }
-            nativeSynth.synthesizeToFile(text, filename);
-        } finally {
-            // This check is needed because finally will always run; even if the
-            // method returns somewhere in the try block.
-            if (synthAvailable) {
-                synthesizerLock.unlock();
-            }
-        }
-        Log.i("TTS", "Completed synthesis for " + filename);
-        return true;
-    }
-
-    @Override
-    public IBinder onBind(Intent intent) {
-        if (ACTION.equals(intent.getAction())) {
-            for (String category : intent.getCategories()) {
-                if (category.equals(CATEGORY)) {
-                    return mBinder;
-                }
-            }
-        }
-        return null;
-    }
-
-    private final ITts.Stub mBinder = new Stub() {
-
-        public void registerCallback(ITtsCallback cb) {
-            if (cb != null)
-                mCallbacks.register(cb);
-        }
-
-        public void unregisterCallback(ITtsCallback cb) {
-            if (cb != null)
-                mCallbacks.unregister(cb);
-        }
-
-        /**
-         * Speaks the given text using the specified queueing mode and
-         * parameters.
-         *
-         * @param text
-         *            The text that should be spoken
-         * @param queueMode
-         *            0 for no queue (interrupts all previous utterances), 1 for
-         *            queued
-         * @param params
-         *            An ArrayList of parameters. The first element of this
-         *            array controls the type of voice to use.
-         */
-        public void speak(String text, int queueMode, String[] params) {
-            ArrayList<String> speakingParams = new ArrayList<String>();
-            if (params != null) {
-                speakingParams = new ArrayList<String>(Arrays.asList(params));
-            }
-            mSelf.speak(text, queueMode, speakingParams);
-        }
-
-        /**
-         * Plays the earcon using the specified queueing mode and parameters.
-         *
-         * @param earcon
-         *            The earcon that should be played
-         * @param queueMode
-         *            0 for no queue (interrupts all previous utterances), 1 for
-         *            queued
-         * @param params
-         *            An ArrayList of parameters.
-         */
-        public void playEarcon(String earcon, int queueMode, String[] params) {
-            ArrayList<String> speakingParams = new ArrayList<String>();
-            if (params != null) {
-                speakingParams = new ArrayList<String>(Arrays.asList(params));
-            }
-            mSelf.playEarcon(earcon, queueMode, speakingParams);
-        }
-
-        /**
-         * Plays the silence using the specified queueing mode and parameters.
-         *
-         * @param duration
-         *            The duration of the silence that should be played
-         * @param queueMode
-         *            0 for no queue (interrupts all previous utterances), 1 for
-         *            queued
-         * @param params
-         *            An ArrayList of parameters.
-         */
-        public void playSilence(long duration, int queueMode, String[] params) {
-            ArrayList<String> speakingParams = new ArrayList<String>();
-            if (params != null) {
-                speakingParams = new ArrayList<String>(Arrays.asList(params));
-            }
-            mSelf.playSilence(duration, queueMode, speakingParams);
-        }
-
-        /**
-         * Stops all speech output and removes any utterances still in the
-         * queue.
-         */
-        public void stop() {
-            mSelf.stop();
-        }
-
-        /**
-         * Returns whether or not the TTS is speaking.
-         *
-         * @return Boolean to indicate whether or not the TTS is speaking
-         */
-        public boolean isSpeaking() {
-            return (mSelf.mIsSpeaking && (mSpeechQueue.size() < 1));
-        }
-
-        /**
-         * Adds a sound resource to the TTS.
-         *
-         * @param text
-         *            The text that should be associated with the sound resource
-         * @param packageName
-         *            The name of the package which has the sound resource
-         * @param resId
-         *            The resource ID of the sound within its package
-         */
-        public void addSpeech(String text, String packageName, int resId) {
-            mSelf.addSpeech(text, packageName, resId);
-        }
-
-        /**
-         * Adds a sound resource to the TTS.
-         *
-         * @param text
-         *            The text that should be associated with the sound resource
-         * @param filename
-         *            The filename of the sound resource. This must be a
-         *            complete path like: (/sdcard/mysounds/mysoundbite.mp3).
-         */
-        public void addSpeechFile(String text, String filename) {
-            mSelf.addSpeech(text, filename);
-        }
-
-        /**
-         * Adds a sound resource to the TTS as an earcon.
-         *
-         * @param earcon
-         *            The text that should be associated with the sound resource
-         * @param packageName
-         *            The name of the package which has the sound resource
-         * @param resId
-         *            The resource ID of the sound within its package
-         */
-        public void addEarcon(String earcon, String packageName, int resId) {
-            mSelf.addEarcon(earcon, packageName, resId);
-        }
-
-        /**
-         * Adds a sound resource to the TTS as an earcon.
-         *
-         * @param earcon
-         *            The text that should be associated with the sound resource
-         * @param filename
-         *            The filename of the sound resource. This must be a
-         *            complete path like: (/sdcard/mysounds/mysoundbite.mp3).
-         */
-        public void addEarconFile(String earcon, String filename) {
-            mSelf.addEarcon(earcon, filename);
-        }
-
-        /**
-         * 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.
-         *
-         * @param speechRate
-         *            The speech rate that should be used
-         */
-        public void setSpeechRate(int speechRate) {
-            mSelf.setSpeechRate(speechRate);
-        }
-
-        /**
-         * 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.
-         *
-         * @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".
-         */
-        public void setLanguage(String language) {
-            mSelf.setLanguage(language);
-        }
-
-        /**
-         * Speaks the given text using the specified queueing mode and
-         * parameters.
-         *
-         * @param text
-         *            The String of text that should be synthesized
-         * @param params
-         *            An ArrayList of parameters. The first element of this
-         *            array controls the type of voice to use.
-         * @param filename
-         *            The string that gives the full output filename; it should
-         *            be something like "/sdcard/myappsounds/mysound.wav".
-         * @return A boolean that indicates if the synthesis succeeded
-         */
-        public boolean synthesizeToFile(String text, String[] params,
-                String filename) {
-            ArrayList<String> speakingParams = new ArrayList<String>();
-            if (params != null) {
-                speakingParams = new ArrayList<String>(Arrays.asList(params));
-            }
-            return mSelf.synthesizeToFile(text, speakingParams, filename, true);
-        }
-    };
-
-}
diff --git a/tts/jni/Android.mk b/tts/jni/Android.mk
deleted file mode 100755
index 665d6d2..0000000
--- a/tts/jni/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	android_tts_SynthProxy.cpp
-
-LOCAL_C_INCLUDES += \
-	$(JNI_H_INCLUDE)
-
-LOCAL_SHARED_LIBRARIES := \
-	libandroid_runtime \
-	libnativehelper \
-	libmedia \
-	libutils \
-	libcutils
-
-ifeq ($(TARGET_SIMULATOR),true)
- LOCAL_LDLIBS += -ldl
-else
- LOCAL_SHARED_LIBRARIES += libdl
-endif
-
-
-LOCAL_MODULE:= libttssynthproxy
-
-LOCAL_ARM_MODE := arm
-
-LOCAL_PRELINK_MODULE := false
-
-include $(BUILD_SHARED_LIBRARY)
-
diff --git a/tts/jni/android_tts_SynthProxy.cpp b/tts/jni/android_tts_SynthProxy.cpp
deleted file mode 100644
index 582e621..0000000
--- a/tts/jni/android_tts_SynthProxy.cpp
+++ /dev/null
@@ -1,616 +0,0 @@
-/*
- * Copyright (C) 2009 Google Inc.
- *
- * 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.
- */
-
-
-#include <stdio.h>
-#include <unistd.h>
-
-#define LOG_TAG "SynthProxy"
-
-#include <utils/Log.h>
-#include <nativehelper/jni.h>
-#include <nativehelper/JNIHelp.h>
-#include <android_runtime/AndroidRuntime.h>
-#include <tts/TtsEngine.h>
-#include <media/AudioTrack.h>
-
-#include <dlfcn.h>
-
-#define DEFAULT_TTS_RATE        16000
-#define DEFAULT_TTS_FORMAT      AudioSystem::PCM_16_BIT
-#define DEFAULT_TTS_NB_CHANNELS 1
-#define DEFAULT_TTS_BUFFERSIZE  1024
-
-#define USAGEMODE_PLAY_IMMEDIATELY 0
-#define USAGEMODE_WRITE_TO_FILE    1
-
-using namespace android;
-
-// ----------------------------------------------------------------------------
-struct fields_t {
-    jfieldID    synthProxyFieldJniData;
-    jclass      synthProxyClass;
-    jmethodID   synthProxyMethodPost;
-};
-
-struct afterSynthData_t {
-    jint jniStorage;
-    int  usageMode;
-    FILE* outputFile;
-};
-
-// ----------------------------------------------------------------------------
-static fields_t javaTTSFields;
-
-// ----------------------------------------------------------------------------
-class SynthProxyJniStorage {
-    public :
-        //jclass                    tts_class;
-        jobject                   tts_ref;
-        TtsEngine*                mNativeSynthInterface;
-        AudioTrack*               mAudioOut;
-        uint32_t                  mSampleRate;
-        AudioSystem::audio_format mAudFormat;
-        int                       mNbChannels;
-        int8_t *                  mBuffer;
-        size_t                    mBufferSize;
-
-        SynthProxyJniStorage() {
-            //tts_class = NULL;
-            tts_ref = NULL;
-            mNativeSynthInterface = NULL;
-            mAudioOut = NULL;
-            mSampleRate = DEFAULT_TTS_RATE;
-            mAudFormat  = DEFAULT_TTS_FORMAT;
-            mNbChannels = DEFAULT_TTS_NB_CHANNELS;
-            mBufferSize = DEFAULT_TTS_BUFFERSIZE;
-            mBuffer = new int8_t[mBufferSize];
-        }
-
-        ~SynthProxyJniStorage() {
-            killAudio();
-            if (mNativeSynthInterface) {
-                mNativeSynthInterface->shutdown();
-                mNativeSynthInterface = NULL;
-            }
-            delete mBuffer;
-        }
-
-        void killAudio() {
-            if (mAudioOut) {
-                mAudioOut->stop();
-                delete mAudioOut;
-                mAudioOut = NULL;
-            }
-        }
-
-        void createAudioOut(uint32_t rate, AudioSystem::audio_format format,
-                int channel) {
-            mSampleRate = rate;
-            mAudFormat  = format;
-            mNbChannels = channel;
-
-            // TODO use the TTS stream type
-            int streamType = AudioSystem::MUSIC;
-
-            // retrieve system properties to ensure successful creation of the
-            // AudioTrack object for playback
-            int afSampleRate;
-            if (AudioSystem::getOutputSamplingRate(&afSampleRate, streamType) != NO_ERROR) {
-                afSampleRate = 44100;
-            }
-            int afFrameCount;
-            if (AudioSystem::getOutputFrameCount(&afFrameCount, streamType) != NO_ERROR) {
-                afFrameCount = 2048;
-            }
-            uint32_t afLatency;
-            if (AudioSystem::getOutputLatency(&afLatency, streamType) != NO_ERROR) {
-                afLatency = 500;
-            }
-            uint32_t minBufCount = afLatency / ((1000 * afFrameCount)/afSampleRate);
-            if (minBufCount < 2) minBufCount = 2;
-            int minFrameCount = (afFrameCount * rate * minBufCount)/afSampleRate;
-
-            mAudioOut = new AudioTrack(streamType, rate, format, channel,
-                    minFrameCount > 4096 ? minFrameCount : 4096,
-                    0, 0, 0, 0); // not using an AudioTrack callback
-
-            if (mAudioOut->initCheck() != NO_ERROR) {
-              LOGI("AudioTrack error");
-              delete mAudioOut;
-              mAudioOut = NULL;
-            } else {
-              LOGI("AudioTrack OK");
-              mAudioOut->start();
-              LOGI("AudioTrack started");
-            }
-        }
-};
-
-
-// ----------------------------------------------------------------------------
-void prepAudioTrack(SynthProxyJniStorage* pJniData,
-        uint32_t rate, AudioSystem::audio_format format, int channel)
-{
-    // Don't bother creating a new audiotrack object if the current
-    // object is already set.
-    if ( pJniData->mAudioOut &&
-         (rate == pJniData->mSampleRate) &&
-         (format == pJniData->mAudFormat) &&
-         (channel == pJniData->mNbChannels) ){
-        return;
-    }
-    if (pJniData->mAudioOut){
-        pJniData->killAudio();
-    }
-    pJniData->createAudioOut(rate, format, channel);
-}
-
-
-// ----------------------------------------------------------------------------
-/*
- * Callback from TTS engine.
- * Directly speaks using AudioTrack or write to file
- */
-static tts_callback_status ttsSynthDoneCB(void *& userdata, uint32_t rate,
-                           AudioSystem::audio_format format, int channel,
-                           int8_t *&wav, size_t &bufferSize, tts_synth_status status) {
-    LOGI("ttsSynthDoneCallback: %d bytes", bufferSize);
-
-    if (userdata == NULL){
-        LOGE("userdata == NULL");
-        return TTS_CALLBACK_HALT;
-    }
-    afterSynthData_t* pForAfter = (afterSynthData_t*)userdata;
-    SynthProxyJniStorage* pJniData = (SynthProxyJniStorage*)(pForAfter->jniStorage);
-
-    if (pForAfter->usageMode == USAGEMODE_PLAY_IMMEDIATELY){
-        LOGI("Direct speech");
-
-        if (wav == NULL) {
-            delete pForAfter;
-            LOGI("Null: speech has completed");
-        }
-
-        if (bufferSize > 0) {
-            prepAudioTrack(pJniData, rate, format, channel);
-            if (pJniData->mAudioOut) {
-                pJniData->mAudioOut->write(wav, bufferSize);
-                LOGI("AudioTrack wrote: %d bytes", bufferSize);
-            } else {
-                LOGI("Can't play, null audiotrack");
-            }
-        }
-    } else  if (pForAfter->usageMode == USAGEMODE_WRITE_TO_FILE) {
-        LOGI("Save to file");
-        if (wav == NULL) {
-            delete pForAfter;
-            LOGI("Null: speech has completed");
-        }
-        if (bufferSize > 0){
-            fwrite(wav, 1, bufferSize, pForAfter->outputFile);
-        }
-    }
-    // TODO update to call back into the SynthProxy class through the
-    //      javaTTSFields.synthProxyMethodPost methode to notify
-    //      playback has completed if the synthesis is done, i.e.
-    //      if status == TTS_SYNTH_DONE
-    //delete pForAfter;
-
-    // we don't update the wav (output) parameter as we'll let the next callback
-    // write at the same location, we've consumed the data already, but we need
-    // to update bufferSize to let the TTS engine know how much it can write the
-    // next time it calls this function.
-    bufferSize = pJniData->mBufferSize;
-
-    return TTS_CALLBACK_CONTINUE;
-}
-
-
-// ----------------------------------------------------------------------------
-static void
-android_tts_SynthProxy_native_setup(JNIEnv *env, jobject thiz,
-        jobject weak_this, jstring nativeSoLib)
-{
-    SynthProxyJniStorage* pJniStorage = new SynthProxyJniStorage();
-
-    prepAudioTrack(pJniStorage,
-            DEFAULT_TTS_RATE, DEFAULT_TTS_FORMAT, DEFAULT_TTS_NB_CHANNELS);
-
-    const char *nativeSoLibNativeString =
-            env->GetStringUTFChars(nativeSoLib, 0);
-
-    void *engine_lib_handle = dlopen(nativeSoLibNativeString,
-            RTLD_NOW | RTLD_LOCAL);
-    if (engine_lib_handle==NULL) {
-       LOGI("engine_lib_handle==NULL");
-       // TODO report error so the TTS can't be used
-    } else {
-        TtsEngine *(*get_TtsEngine)() =
-            reinterpret_cast<TtsEngine* (*)()>(dlsym(engine_lib_handle, "getTtsEngine"));
-
-        pJniStorage->mNativeSynthInterface = (*get_TtsEngine)();
-
-        if (pJniStorage->mNativeSynthInterface) {
-            pJniStorage->mNativeSynthInterface->init(ttsSynthDoneCB);
-        }
-    }
-
-    // we use a weak reference so the SynthProxy object can be garbage collected.
-    pJniStorage->tts_ref = env->NewGlobalRef(weak_this);
-
-    // save the JNI resources so we can use them (and free them) later
-    env->SetIntField(thiz, javaTTSFields.synthProxyFieldJniData,
-            (int)pJniStorage);
-
-    env->ReleaseStringUTFChars(nativeSoLib, nativeSoLibNativeString);
-}
-
-
-static void
-android_tts_SynthProxy_native_finalize(JNIEnv *env, jobject thiz, jint jniData)
-{
-    if (jniData) {
-        SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
-        delete pSynthData;
-    }
-}
-
-
-static void
-android_tts_SynthProxy_setLanguage(JNIEnv *env, jobject thiz, jint jniData,
-        jstring language)
-{
-    if (jniData == 0) {
-        LOGE("android_tts_SynthProxy_setLanguage(): invalid JNI data");
-        return;
-    }
-
-    SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
-    const char *langNativeString = env->GetStringUTFChars(language, 0);
-    // TODO check return codes
-    if (pSynthData->mNativeSynthInterface) {
-        pSynthData->mNativeSynthInterface->setLanguage(langNativeString,
-                strlen(langNativeString));
-    }
-    env->ReleaseStringUTFChars(language, langNativeString);
-}
-
-
-static void
-android_tts_SynthProxy_setSpeechRate(JNIEnv *env, jobject thiz, jint jniData,
-        int speechRate)
-{
-    if (jniData == 0) {
-        LOGE("android_tts_SynthProxy_setSpeechRate(): invalid JNI data");
-        return;
-    }
-
-    int bufSize = 10;
-    char buffer [bufSize];
-    sprintf(buffer, "%d", speechRate);
-
-    SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
-    LOGI("setting speech rate to %d", speechRate);
-    // TODO check return codes
-    if (pSynthData->mNativeSynthInterface) {
-        pSynthData->mNativeSynthInterface->setProperty("rate", buffer, bufSize);
-    }
-}
-
-
-// TODO: Refactor this to get rid of any assumptions about sample rate, etc.
-static void
-android_tts_SynthProxy_synthesizeToFile(JNIEnv *env, jobject thiz, jint jniData,
-        jstring textJavaString, jstring filenameJavaString)
-{
-    if (jniData == 0) {
-        LOGE("android_tts_SynthProxy_synthesizeToFile(): invalid JNI data");
-        return;
-    }
-
-    SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
-
-    const char *filenameNativeString =
-            env->GetStringUTFChars(filenameJavaString, 0);
-    const char *textNativeString = env->GetStringUTFChars(textJavaString, 0);
-
-    afterSynthData_t* pForAfter = new (afterSynthData_t);
-    pForAfter->jniStorage = jniData;
-    pForAfter->usageMode  = USAGEMODE_WRITE_TO_FILE;
-
-    pForAfter->outputFile = fopen(filenameNativeString, "wb");
-
-    // Write 44 blank bytes for WAV header, then come back and fill them in
-    // after we've written the audio data
-    char header[44];
-    fwrite(header, 1, 44, pForAfter->outputFile);
-
-    unsigned int unique_identifier;
-
-    // TODO check return codes
-    if (pSynthData->mNativeSynthInterface) {
-        pSynthData->mNativeSynthInterface->synthesizeText(textNativeString, pSynthData->mBuffer, pSynthData->mBufferSize,
-                (void *)pForAfter);
-    }
-
-    long filelen = ftell(pForAfter->outputFile);
-
-    int samples = (((int)filelen) - 44) / 2;
-    header[0] = 'R';
-    header[1] = 'I';
-    header[2] = 'F';
-    header[3] = 'F';
-    ((uint32_t *)(&header[4]))[0] = filelen - 8;
-    header[8] = 'W';
-    header[9] = 'A';
-    header[10] = 'V';
-    header[11] = 'E';
-
-    header[12] = 'f';
-    header[13] = 'm';
-    header[14] = 't';
-    header[15] = ' ';
-
-    ((uint32_t *)(&header[16]))[0] = 16;  // size of fmt
-
-    ((unsigned short *)(&header[20]))[0] = 1;  // format
-    ((unsigned short *)(&header[22]))[0] = 1;  // channels
-    ((uint32_t *)(&header[24]))[0] = 22050;  // samplerate
-    ((uint32_t *)(&header[28]))[0] = 44100;  // byterate
-    ((unsigned short *)(&header[32]))[0] = 2;  // block align
-    ((unsigned short *)(&header[34]))[0] = 16;  // bits per sample
-
-    header[36] = 'd';
-    header[37] = 'a';
-    header[38] = 't';
-    header[39] = 'a';
-
-    ((uint32_t *)(&header[40]))[0] = samples * 2;  // size of data
-
-    // Skip back to the beginning and rewrite the header
-    fseek(pForAfter->outputFile, 0, SEEK_SET);
-    fwrite(header, 1, 44, pForAfter->outputFile);
-
-    fflush(pForAfter->outputFile);
-    fclose(pForAfter->outputFile);
-
-    env->ReleaseStringUTFChars(textJavaString, textNativeString);
-    env->ReleaseStringUTFChars(filenameJavaString, filenameNativeString);
-}
-
-
-static void
-android_tts_SynthProxy_speak(JNIEnv *env, jobject thiz, jint jniData,
-        jstring textJavaString)
-{
-    if (jniData == 0) {
-        LOGE("android_tts_SynthProxy_speak(): invalid JNI data");
-        return;
-    }
-
-    SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
-
-    if (pSynthData->mAudioOut) {
-        pSynthData->mAudioOut->stop();
-        pSynthData->mAudioOut->start();
-    }
-
-    afterSynthData_t* pForAfter = new (afterSynthData_t);
-    pForAfter->jniStorage = jniData;
-    pForAfter->usageMode  = USAGEMODE_PLAY_IMMEDIATELY;
-
-    if (pSynthData->mNativeSynthInterface) {
-        const char *textNativeString = env->GetStringUTFChars(textJavaString, 0);
-        pSynthData->mNativeSynthInterface->synthesizeText(textNativeString, pSynthData->mBuffer, pSynthData->mBufferSize,
-                (void *)pForAfter);
-        env->ReleaseStringUTFChars(textJavaString, textNativeString);
-    }
-}
-
-
-static void
-android_tts_SynthProxy_stop(JNIEnv *env, jobject thiz, jint jniData)
-{
-    if (jniData == 0) {
-        LOGE("android_tts_SynthProxy_stop(): invalid JNI data");
-        return;
-    }
-
-    SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
-
-    if (pSynthData->mNativeSynthInterface) {
-        pSynthData->mNativeSynthInterface->stop();
-    }
-    if (pSynthData->mAudioOut) {
-        pSynthData->mAudioOut->stop();
-    }
-}
-
-
-static void
-android_tts_SynthProxy_shutdown(JNIEnv *env, jobject thiz, jint jniData)
-{
-    if (jniData == 0) {
-        LOGE("android_tts_SynthProxy_shutdown(): invalid JNI data");
-        return;
-    }
-
-    SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
-    if (pSynthData->mNativeSynthInterface) {
-        pSynthData->mNativeSynthInterface->shutdown();
-        pSynthData->mNativeSynthInterface = NULL;
-    }
-}
-
-
-// TODO add buffer format
-static void
-android_tts_SynthProxy_playAudioBuffer(JNIEnv *env, jobject thiz, jint jniData,
-        int bufferPointer, int bufferSize)
-{
-LOGI("android_tts_SynthProxy_playAudioBuffer");
-    if (jniData == 0) {
-        LOGE("android_tts_SynthProxy_playAudioBuffer(): invalid JNI data");
-        return;
-    }
-
-    SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
-    short* wav = (short*) bufferPointer;
-    pSynthData->mAudioOut->write(wav, bufferSize);
-    LOGI("AudioTrack wrote: %d bytes", bufferSize);
-}
-
-
-JNIEXPORT jstring JNICALL
-android_tts_SynthProxy_getLanguage(JNIEnv *env, jobject thiz, jint jniData)
-{
-    if (jniData == 0) {
-        LOGE("android_tts_SynthProxy_getLanguage(): invalid JNI data");
-        return env->NewStringUTF("");
-    }
-
-    SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
-    size_t bufSize = 100;
-    char buf[bufSize];
-    memset(buf, 0, bufSize);
-    // TODO check return codes
-    if (pSynthData->mNativeSynthInterface) {
-        pSynthData->mNativeSynthInterface->getLanguage(buf, &bufSize);
-    }
-    return env->NewStringUTF(buf);
-}
-
-JNIEXPORT int JNICALL
-android_tts_SynthProxy_getRate(JNIEnv *env, jobject thiz, jint jniData)
-{
-    if (jniData == 0) {
-        LOGE("android_tts_SynthProxy_getRate(): invalid JNI data");
-        return 0;
-    }
-
-    SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
-    size_t bufSize = 100;
-
-    char buf[bufSize];
-    memset(buf, 0, bufSize);
-    // TODO check return codes
-    if (pSynthData->mNativeSynthInterface) {
-        pSynthData->mNativeSynthInterface->getProperty("rate", buf, &bufSize);
-    }
-    return atoi(buf);
-}
-
-// Dalvik VM type signatures
-static JNINativeMethod gMethods[] = {
-    {   "native_stop",
-        "(I)V",
-        (void*)android_tts_SynthProxy_stop
-    },
-    {   "native_speak",
-        "(ILjava/lang/String;)V",
-        (void*)android_tts_SynthProxy_speak
-    },
-    {   "native_synthesizeToFile",
-        "(ILjava/lang/String;Ljava/lang/String;)V",
-        (void*)android_tts_SynthProxy_synthesizeToFile
-    },
-    {   "native_setLanguage",
-        "(ILjava/lang/String;)V",
-        (void*)android_tts_SynthProxy_setLanguage
-    },
-    {   "native_setSpeechRate",
-        "(II)V",
-        (void*)android_tts_SynthProxy_setSpeechRate
-    },
-    {   "native_playAudioBuffer",
-        "(III)V",
-        (void*)android_tts_SynthProxy_playAudioBuffer
-    },
-    {   "native_getLanguage",
-        "(I)Ljava/lang/String;",
-        (void*)android_tts_SynthProxy_getLanguage
-    },
-    {   "native_getRate",
-        "(I)I",
-        (void*)android_tts_SynthProxy_getRate
-    },
-    {   "native_shutdown",
-        "(I)V",
-        (void*)android_tts_SynthProxy_shutdown
-    },
-    {   "native_setup",
-        "(Ljava/lang/Object;Ljava/lang/String;)V",
-        (void*)android_tts_SynthProxy_native_setup
-    },
-    {   "native_finalize",
-        "(I)V",
-        (void*)android_tts_SynthProxy_native_finalize
-    }
-};
-
-#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)
-{
-    JNIEnv* env = NULL;
-    jint result = -1;
-    jclass clazz;
-
-    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
-        LOGE("ERROR: GetEnv failed\n");
-        goto bail;
-    }
-    assert(env != NULL);
-
-    clazz = env->FindClass(kClassPathName);
-    if (clazz == NULL) {
-        LOGE("Can't find %s", kClassPathName);
-        goto bail;
-    }
-
-    javaTTSFields.synthProxyClass = clazz;
-    javaTTSFields.synthProxyFieldJniData = NULL;
-    javaTTSFields.synthProxyMethodPost = NULL;
-
-    javaTTSFields.synthProxyFieldJniData = env->GetFieldID(clazz,
-            SP_JNIDATA_FIELD_NAME, "I");
-    if (javaTTSFields.synthProxyFieldJniData == NULL) {
-        LOGE("Can't find %s.%s field", kClassPathName, SP_JNIDATA_FIELD_NAME);
-        goto bail;
-    }
-
-    javaTTSFields.synthProxyMethodPost = env->GetStaticMethodID(clazz,
-            SP_POSTSPEECHSYNTHESIZED_METHOD_NAME, "(Ljava/lang/Object;II)V");
-    if (javaTTSFields.synthProxyMethodPost == NULL) {
-        LOGE("Can't find %s.%s method", kClassPathName, SP_POSTSPEECHSYNTHESIZED_METHOD_NAME);
-        goto bail;
-    }
-
-    if (jniRegisterNativeMethods(
-            env, kClassPathName, gMethods, NELEM(gMethods)) < 0)
-        goto bail;
-
-    /* success -- return valid version number */
-    result = JNI_VERSION_1_4;
-
- bail:
-    return result;
-}
diff --git a/vpn/java/android/net/vpn/L2tpIpsecProfile.java b/vpn/java/android/net/vpn/L2tpIpsecProfile.java
index a7e53d1..181619d 100644
--- a/vpn/java/android/net/vpn/L2tpIpsecProfile.java
+++ b/vpn/java/android/net/vpn/L2tpIpsecProfile.java
@@ -22,7 +22,9 @@
  * The profile for L2TP-over-IPSec type of VPN.
  * {@hide}
  */
-public class L2tpIpsecProfile extends SingleServerProfile {
+public class L2tpIpsecProfile extends VpnProfile {
+    private static final long serialVersionUID = 1L;
+
     private String mUserCertificate;
     private String mCaCertificate;
     private String mUserkey;
diff --git a/vpn/java/android/net/vpn/L2tpProfile.java b/vpn/java/android/net/vpn/L2tpProfile.java
index ca4ef75..59d4981 100644
--- a/vpn/java/android/net/vpn/L2tpProfile.java
+++ b/vpn/java/android/net/vpn/L2tpProfile.java
@@ -20,7 +20,9 @@
  * The profile for L2TP type of VPN.
  * {@hide}
  */
-public class L2tpProfile extends SingleServerProfile {
+public class L2tpProfile extends VpnProfile {
+    private static final long serialVersionUID = 1L;
+
     @Override
     public VpnType getType() {
         return VpnType.L2TP;
diff --git a/vpn/java/android/net/vpn/SingleServerProfile.java b/vpn/java/android/net/vpn/SingleServerProfile.java
deleted file mode 100644
index 59b5a7b..0000000
--- a/vpn/java/android/net/vpn/SingleServerProfile.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2007, 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.net.vpn;
-
-import android.os.Parcel;
-
-/**
- * The profile for single-server type of VPN.
- * {@hide}
- */
-public abstract class SingleServerProfile extends VpnProfile {
-    private String mServerName;
-
-    public void setServerName(String name) {
-        mServerName = name;
-    }
-
-    public String getServerName() {
-        return mServerName;
-    }
-
-    @Override
-    protected void readFromParcel(Parcel in) {
-        super.readFromParcel(in);
-        mServerName = in.readString();
-    }
-
-    @Override
-    public void writeToParcel(Parcel parcel, int flags) {
-        super.writeToParcel(parcel, flags);
-        parcel.writeString(mServerName);
-    }
-}
diff --git a/vpn/java/android/net/vpn/VpnManager.java b/vpn/java/android/net/vpn/VpnManager.java
index 6c6e52a..98795bd 100644
--- a/vpn/java/android/net/vpn/VpnManager.java
+++ b/vpn/java/android/net/vpn/VpnManager.java
@@ -48,19 +48,8 @@
     private static final String PACKAGE_PREFIX =
             VpnManager.class.getPackage().getName() + ".";
 
-    /** Action to start the activity of installing a new profile. */
-    public static final String ACTION_VPN_INSTALL_PROFILE =
-            PACKAGE_PREFIX + "INSTALL_PROFILE";
-    /**
-     * Key to the installation path in the intent of installing a new profile.
-     */
-    public static final String KEY_INSTALLATION_PATH = "install_path";
-    public static final String DEFAULT_INSTALLATION_PATH =
-            "/data/local/tmp/vpn";
-
-    // Action to start VPN installation monitor service
-    private static final String SERVICE_VPN_INSTALL_MONITOR =
-            PACKAGE_PREFIX + "INSTALLATION_MONITOR";
+    // Action to start VPN service
+    private static final String ACTION_VPN_SERVICE = PACKAGE_PREFIX + "SERVICE";
 
     // Action to start VPN settings
     private static final String ACTION_VPN_SETTINGS = PACKAGE_PREFIX + "SETTINGS";
@@ -112,53 +101,29 @@
         }
     }
 
-    private String getServiceActionName(VpnType type) {
-        return PACKAGE_PREFIX + type.getServiceName();
+    /**
+     * Starts the VPN service to establish VPN connection.
+     */
+    public void startVpnService() {
+        mContext.startService(new Intent(ACTION_VPN_SERVICE));
     }
 
     /**
-     * Starts the VPN service of the specified type.
+     * Stops the VPN service.
      */
-    public boolean startService(VpnType type) {
-        String serviceAction = getServiceActionName(type);
-        if (serviceAction != null) {
-            Log.i(TAG, "start service: " + serviceAction);
-            mContext.startService(new Intent(serviceAction));
-            return true;
-        } else {
-            Log.w(TAG, "unknown vpn type to start service for: " + type);
-            return false;
-        }
+    public void stopVpnService() {
+        mContext.stopService(new Intent(ACTION_VPN_SERVICE));
     }
 
     /**
-     * Stops the VPN service of the specified type.
+     * Binds the specified ServiceConnection with the VPN service.
      */
-    public void stopService(VpnType type) {
-        String serviceAction = getServiceActionName(type);
-        if (serviceAction != null) {
-            Log.i(TAG, "stop service for: " + type);
-            mContext.stopService(new Intent(serviceAction));
-        } else {
-            Log.w(TAG, "unknown vpn type to stop service for: " + type);
-        }
-    }
-
-    /**
-     * Binds the specified ServiceConnection with the VPN service of the
-     * specified type.
-     */
-    public boolean bindService(VpnType type, ServiceConnection c) {
-        String serviceAction = getServiceActionName(type);
-        if (serviceAction == null) {
-            Log.w(TAG, "unknown vpn type to bind service for: " + type);
-            return false;
-        }
-        if (!mContext.bindService(new Intent(serviceAction), c, 0)) {
-            Log.w(TAG, "failed to connect to service: " + type);
+    public boolean bindVpnService(ServiceConnection c) {
+        if (!mContext.bindService(new Intent(ACTION_VPN_SERVICE), c, 0)) {
+            Log.w(TAG, "failed to connect to VPN service");
             return false;
         } else {
-            Log.v(TAG, "succeeded to connect to service: " + type);
+            Log.d(TAG, "succeeded to connect to VPN service");
             return true;
         }
     }
@@ -181,21 +146,6 @@
         mContext.unregisterReceiver(r);
     }
 
-    /**
-     * Starts the installation monitor service.
-     * The service monitors the default installtion path (under /data/local/tmp)
-     * and automatically starts the activity to create a new profile when new
-     * configuration files appear in that path.
-     */
-    public void startInstallationMonitorService() {
-        mContext.startService(new Intent(SERVICE_VPN_INSTALL_MONITOR));
-    }
-
-    /** Stops the installation monitor service. */
-    public void stopInstallationMonitorService() {
-        mContext.stopService(new Intent(SERVICE_VPN_INSTALL_MONITOR));
-    }
-
     /** Starts the VPN settings activity. */
     public void startSettingsActivity() {
         Intent intent = new Intent(ACTION_VPN_SETTINGS);
@@ -203,14 +153,10 @@
         mContext.startActivity(intent);
     }
 
-    /**
-     * Starts the activity to install a customized profile.
-     * @param installPath the path where all the configuration files are located
-     */
-    public void startInstallProfileActivity(String installPath) {
-        Intent intent = new Intent(ACTION_VPN_INSTALL_PROFILE);
-        intent.putExtra(KEY_INSTALLATION_PATH, installPath);
+    /** Creates an intent to start the VPN settings activity. */
+    public Intent createSettingsActivityIntent() {
+        Intent intent = new Intent(ACTION_VPN_SETTINGS);
         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        mContext.startActivity(intent);
+        return intent;
     }
 }
diff --git a/vpn/java/android/net/vpn/VpnProfile.java b/vpn/java/android/net/vpn/VpnProfile.java
index 7cf2608..9e24da4 100644
--- a/vpn/java/android/net/vpn/VpnProfile.java
+++ b/vpn/java/android/net/vpn/VpnProfile.java
@@ -27,11 +27,14 @@
  * A VPN profile.
  * {@hide}
  */
-public abstract class VpnProfile implements Parcelable {
+public abstract class VpnProfile implements Parcelable, Serializable {
+    private static final long serialVersionUID = 1L;
     private String mName; // unique display name
     private String mId; // unique identifier
+    private String mServerName; // VPN server name
     private String mDomainSuffices; // space separated list
     private String mRouteList; // space separated list
+    private String mSavedUsername;
     private boolean mIsCustomized;
     private transient VpnState mState = VpnState.IDLE;
 
@@ -57,6 +60,17 @@
     }
 
     /**
+     * Sets the name of the VPN server. Used for DNS lookup.
+     */
+    public void setServerName(String name) {
+        mServerName = name;
+    }
+
+    public String getServerName() {
+        return mServerName;
+    }
+
+    /**
      * Sets the domain suffices for DNS resolution.
      *
      * @param entries a comma-separated list of domain suffices
@@ -83,6 +97,14 @@
         return mRouteList;
     }
 
+    public void setSavedUsername(String name) {
+        mSavedUsername = name;
+    }
+
+    public String getSavedUsername() {
+        return mSavedUsername;
+    }
+
     public void setState(VpnState state) {
         mState = state;
     }
@@ -115,8 +137,10 @@
     protected void readFromParcel(Parcel in) {
         mName = in.readString();
         mId = in.readString();
+        mServerName = in.readString();
         mDomainSuffices = in.readString();
         mRouteList = in.readString();
+        mSavedUsername = in.readString();
     }
 
     public static final Parcelable.Creator<VpnProfile> CREATOR =
@@ -141,8 +165,10 @@
         parcel.writeInt(mIsCustomized ? 1 : 0);
         parcel.writeString(mName);
         parcel.writeString(mId);
+        parcel.writeString(mServerName);
         parcel.writeString(mDomainSuffices);
         parcel.writeString(mRouteList);
+        parcel.writeString(mSavedUsername);
     }
 
     public int describeContents() {
diff --git a/vpn/java/android/net/vpn/VpnState.java b/vpn/java/android/net/vpn/VpnState.java
index 78117e0..977d938 100644
--- a/vpn/java/android/net/vpn/VpnState.java
+++ b/vpn/java/android/net/vpn/VpnState.java
@@ -24,8 +24,10 @@
  * {@link CONNECTED} if successful; back to {@link IDLE} if failed.
  * When the connection is about to be torn down, it goes to
  * {@link DISCONNECTING} and then {@link IDLE}.
+ * {@link CANCELLED} is a state when a VPN connection attempt is aborted, and
+ * is in transition to {@link IDLE}.
  * {@hide}
  */
 public enum VpnState {
-    CONNECTING, DISCONNECTING, CONNECTED, IDLE
+    CONNECTING, DISCONNECTING, CANCELLED, CONNECTED, IDLE
 }
diff --git a/vpn/java/android/net/vpn/VpnType.java b/vpn/java/android/net/vpn/VpnType.java
index dcf2078..91b0ea2 100644
--- a/vpn/java/android/net/vpn/VpnType.java
+++ b/vpn/java/android/net/vpn/VpnType.java
@@ -39,8 +39,4 @@
     public Class<? extends VpnProfile> getProfileClass() {
         return mClass;
     }
-
-    public String getServiceName() {
-        return this.toString();
-    }
 }