Merge change 25628 into eclair

* changes:
  Inefficient but correct fix for 2122381: call finishBackup after every performBackup
diff --git a/Android.mk b/Android.mk
index 4e7b14e..90f2acb 100644
--- a/Android.mk
+++ b/Android.mk
@@ -341,6 +341,7 @@
     -since ./frameworks/base/api/2.xml 2 \
     -since ./frameworks/base/api/3.xml 3 \
     -since ./frameworks/base/api/4.xml 4 \
+    -since ./frameworks/base/api/current.xml Eclair \
 		-error 1 -error 2 -warning 3 -error 4 -error 6 -error 8 \
 		-overview $(LOCAL_PATH)/core/java/overview.html
 
diff --git a/api/current.xml b/api/current.xml
index b348555..b38176d 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -17165,27 +17165,6 @@
 <parameter name="id" type="int">
 </parameter>
 </method>
-<method name="startActivity"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="intent" type="android.app.PendingIntent">
-</parameter>
-<parameter name="fillInIntent" type="android.content.Intent">
-</parameter>
-<parameter name="flagsMask" type="int">
-</parameter>
-<parameter name="flagsValues" type="int">
-</parameter>
-<exception name="PendingIntent.CanceledException" type="android.app.PendingIntent.CanceledException">
-</exception>
-</method>
 <method name="startActivityForResult"
  return="void"
  abstract="false"
@@ -17201,29 +17180,6 @@
 <parameter name="requestCode" type="int">
 </parameter>
 </method>
-<method name="startActivityForResult"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="intent" type="android.app.PendingIntent">
-</parameter>
-<parameter name="requestCode" type="int">
-</parameter>
-<parameter name="fillInIntent" type="android.content.Intent">
-</parameter>
-<parameter name="flagsMask" type="int">
-</parameter>
-<parameter name="flagsValues" type="int">
-</parameter>
-<exception name="PendingIntent.CanceledException" type="android.app.PendingIntent.CanceledException">
-</exception>
-</method>
 <method name="startActivityFromChild"
  return="void"
  abstract="false"
@@ -17241,31 +17197,6 @@
 <parameter name="requestCode" type="int">
 </parameter>
 </method>
-<method name="startActivityFromChild"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="child" type="android.app.Activity">
-</parameter>
-<parameter name="intent" type="android.app.PendingIntent">
-</parameter>
-<parameter name="requestCode" type="int">
-</parameter>
-<parameter name="fillInIntent" type="android.content.Intent">
-</parameter>
-<parameter name="flagsMask" type="int">
-</parameter>
-<parameter name="flagsValues" type="int">
-</parameter>
-<exception name="PendingIntent.CanceledException" type="android.app.PendingIntent.CanceledException">
-</exception>
-</method>
 <method name="startActivityIfNeeded"
  return="boolean"
  abstract="false"
@@ -17281,6 +17212,58 @@
 <parameter name="requestCode" type="int">
 </parameter>
 </method>
+<method name="startIntentSenderForResult"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="intent" type="android.content.IntentSender">
+</parameter>
+<parameter name="requestCode" type="int">
+</parameter>
+<parameter name="fillInIntent" type="android.content.Intent">
+</parameter>
+<parameter name="flagsMask" type="int">
+</parameter>
+<parameter name="flagsValues" type="int">
+</parameter>
+<parameter name="extraFlags" type="int">
+</parameter>
+<exception name="IntentSender.SendIntentException" type="android.content.IntentSender.SendIntentException">
+</exception>
+</method>
+<method name="startIntentSenderFromChild"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="child" type="android.app.Activity">
+</parameter>
+<parameter name="intent" type="android.content.IntentSender">
+</parameter>
+<parameter name="requestCode" type="int">
+</parameter>
+<parameter name="fillInIntent" type="android.content.Intent">
+</parameter>
+<parameter name="flagsMask" type="int">
+</parameter>
+<parameter name="flagsValues" type="int">
+</parameter>
+<parameter name="extraFlags" type="int">
+</parameter>
+<exception name="IntentSender.SendIntentException" type="android.content.IntentSender.SendIntentException">
+</exception>
+</method>
 <method name="startManagingCursor"
  return="void"
  abstract="false"
@@ -31782,6 +31765,29 @@
 <parameter name="arguments" type="android.os.Bundle">
 </parameter>
 </method>
+<method name="startIntentSender"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="intent" type="android.content.IntentSender">
+</parameter>
+<parameter name="fillInIntent" type="android.content.Intent">
+</parameter>
+<parameter name="flagsMask" type="int">
+</parameter>
+<parameter name="flagsValues" type="int">
+</parameter>
+<parameter name="extraFlags" type="int">
+</parameter>
+<exception name="IntentSender.SendIntentException" type="android.content.IntentSender.SendIntentException">
+</exception>
+</method>
 <method name="startService"
  return="android.content.ComponentName"
  abstract="true"
@@ -33095,6 +33101,29 @@
 <parameter name="arguments" type="android.os.Bundle">
 </parameter>
 </method>
+<method name="startIntentSender"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="intent" type="android.content.IntentSender">
+</parameter>
+<parameter name="fillInIntent" type="android.content.Intent">
+</parameter>
+<parameter name="flagsMask" type="int">
+</parameter>
+<parameter name="flagsValues" type="int">
+</parameter>
+<parameter name="extraFlags" type="int">
+</parameter>
+<exception name="IntentSender.SendIntentException" type="android.content.IntentSender.SendIntentException">
+</exception>
+</method>
 <method name="startService"
  return="android.content.ComponentName"
  abstract="false"
@@ -77611,8 +77640,8 @@
 <parameter name="tag" type="java.lang.String">
 </parameter>
 </method>
-<method name="getDateTime"
- return="long"
+<method name="getAttributeInt"
+ return="int"
  abstract="false"
  native="false"
  synchronized="false"
@@ -77621,9 +77650,13 @@
  deprecated="not deprecated"
  visibility="public"
 >
+<parameter name="tag" type="java.lang.String">
+</parameter>
+<parameter name="defaultValue" type="int">
+</parameter>
 </method>
 <method name="getLatLong"
- return="float[]"
+ return="boolean"
  abstract="false"
  native="false"
  synchronized="false"
@@ -77632,17 +77665,8 @@
  deprecated="not deprecated"
  visibility="public"
 >
-</method>
-<method name="getOrientationString"
- return="java.lang.String"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
+<parameter name="output" type="float[]">
+</parameter>
 </method>
 <method name="getThumbnail"
  return="byte[]"
@@ -77655,17 +77679,6 @@
  visibility="public"
 >
 </method>
-<method name="getWhiteBalanceString"
- return="java.lang.String"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</method>
 <method name="hasThumbnail"
  return="boolean"
  abstract="false"
@@ -121613,6 +121626,153 @@
 </field>
 </class>
 </package>
+<package name="android.telephony.cdma"
+>
+<class name="CdmaCellLocation"
+ extends="android.telephony.CellLocation"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="CdmaCellLocation"
+ type="android.telephony.cdma.CdmaCellLocation"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<constructor name="CdmaCellLocation"
+ type="android.telephony.cdma.CdmaCellLocation"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="bundleWithValues" type="android.os.Bundle">
+</parameter>
+</constructor>
+<method name="fillInNotifierBundle"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="bundleToFill" type="android.os.Bundle">
+</parameter>
+</method>
+<method name="getBaseStationId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getBaseStationLatitude"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getBaseStationLongitude"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getNetworkId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSystemId"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="setCellLocationData"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="baseStationId" type="int">
+</parameter>
+<parameter name="baseStationLatitude" type="int">
+</parameter>
+<parameter name="baseStationLongitude" type="int">
+</parameter>
+</method>
+<method name="setCellLocationData"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="baseStationId" type="int">
+</parameter>
+<parameter name="baseStationLatitude" type="int">
+</parameter>
+<parameter name="baseStationLongitude" type="int">
+</parameter>
+<parameter name="systemId" type="int">
+</parameter>
+<parameter name="networkId" type="int">
+</parameter>
+</method>
+<method name="setStateInvalid"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+</package>
 <package name="android.telephony.gsm"
 >
 <class name="GsmCellLocation"
@@ -126597,6 +126757,29 @@
 <parameter name="arguments" type="android.os.Bundle">
 </parameter>
 </method>
+<method name="startIntentSender"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="intent" type="android.content.IntentSender">
+</parameter>
+<parameter name="fillInIntent" type="android.content.Intent">
+</parameter>
+<parameter name="flagsMask" type="int">
+</parameter>
+<parameter name="flagsValues" type="int">
+</parameter>
+<parameter name="extraFlags" type="int">
+</parameter>
+<exception name="IntentSender.SendIntentException" type="android.content.IntentSender.SendIntentException">
+</exception>
+</method>
 <method name="startService"
  return="android.content.ComponentName"
  abstract="false"
diff --git a/cmds/keystore/keystore.c b/cmds/keystore/keystore.c
new file mode 100644
index 0000000..2bcba97
--- /dev/null
+++ b/cmds/keystore/keystore.c
@@ -0,0 +1,532 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <arpa/inet.h>
+
+#include <openssl/aes.h>
+#include <openssl/evp.h>
+#include <openssl/md5.h>
+
+#define LOG_TAG "keystore"
+#include <cutils/log.h>
+#include <cutils/sockets.h>
+#include <private/android_filesystem_config.h>
+
+#include "keystore.h"
+
+/* KeyStore is a secured storage for key-value pairs. In this implementation,
+ * each file stores one key-value pair. Keys are encoded in file names, and
+ * values are encrypted with checksums. The encryption key is protected by a
+ * user-defined password. To keep things simple, buffers are always larger than
+ * the maximum space we needed, so boundary checks on buffers are omitted. */
+
+#define KEY_SIZE        120
+#define VALUE_SIZE      32768
+#define PASSWORD_SIZE   VALUE_SIZE
+
+/* Here is the encoding of keys. This is necessary in order to allow arbitrary
+ * characters in keys. Characters in [0-~] are not encoded. Others are encoded
+ * into two bytes. The first byte is one of [+-.] which represents the first
+ * two bits of the character. The second byte encodes the rest of the bits into
+ * [0-o]. Therefore in the worst case the length of a key gets doubled. Note
+ * that Base64 cannot be used here due to the need of prefix match on keys. */
+
+static int encode_key(char *out, uint8_t *in, int length)
+{
+    int i;
+    for (i = length; i > 0; --i, ++in, ++out) {
+        if (*in >= '0' && *in <= '~') {
+            *out = *in;
+        } else {
+            *out = '+' + (*in >> 6);
+            *++out = '0' + (*in & 0x3F);
+            ++length;
+        }
+    }
+    *out = 0;
+    return length;
+}
+
+static int decode_key(uint8_t *out, char *in, int length)
+{
+    int i;
+    for (i = 0; i < length; ++i, ++in, ++out) {
+        if (*in >= '0' && *in <= '~') {
+            *out = *in;
+        } else {
+            *out = (*in - '+') << 6;
+            *out |= (*++in - '0') & 0x3F;
+            --length;
+        }
+    }
+    *out = 0;
+    return length;
+}
+
+/* Here is the protocol used in both requests and responses:
+ *     code [length_1 message_1 ... length_n message_n] end-of-file
+ * where code is one byte long and lengths are unsigned 16-bit integers in
+ * network order. Thus the maximum length of a message is 65535 bytes. */
+
+static int the_socket = -1;
+
+static int recv_code(int8_t *code)
+{
+    return recv(the_socket, code, 1, 0) == 1;
+}
+
+static int recv_message(uint8_t *message, int length)
+{
+    uint8_t bytes[2];
+    if (recv(the_socket, &bytes[0], 1, 0) != 1 ||
+        recv(the_socket, &bytes[1], 1, 0) != 1) {
+        return -1;
+    } else {
+        int offset = bytes[0] << 8 | bytes[1];
+        if (length < offset) {
+            return -1;
+        }
+        length = offset;
+        offset = 0;
+        while (offset < length) {
+            int n = recv(the_socket, &message[offset], length - offset, 0);
+            if (n <= 0) {
+                return -1;
+            }
+            offset += n;
+        }
+    }
+    return length;
+}
+
+static void send_code(int8_t code)
+{
+    send(the_socket, &code, 1, 0);
+}
+
+static void send_message(uint8_t *message, int length)
+{
+    uint16_t bytes = htons(length);
+    send(the_socket, &bytes, 2, 0);
+    send(the_socket, message, length, 0);
+}
+
+/* Here is the file format. Values are encrypted by AES CBC, and MD5 is used to
+ * compute their checksums. To make the files portable, the length is stored in
+ * network order. Note that the first four bytes are reserved for future use and
+ * are always set to zero in this implementation. */
+
+static int the_entropy = -1;
+
+static struct __attribute__((packed)) {
+    uint32_t reserved;
+    uint8_t vector[AES_BLOCK_SIZE];
+    uint8_t encrypted[0];
+    uint8_t digest[MD5_DIGEST_LENGTH];
+    uint8_t digested[0];
+    int32_t length;
+    uint8_t value[VALUE_SIZE + AES_BLOCK_SIZE];
+} blob;
+
+static int8_t encrypt_blob(char *name, AES_KEY *aes_key)
+{
+    uint8_t vector[AES_BLOCK_SIZE];
+    int length = blob.length;
+    int fd;
+
+    if (read(the_entropy, vector, AES_BLOCK_SIZE) != AES_BLOCK_SIZE) {
+        return SYSTEM_ERROR;
+    }
+
+    length += blob.value - blob.digested;
+    blob.length = htonl(blob.length);
+    MD5(blob.digested, length, blob.digest);
+
+    length += blob.digested - blob.encrypted;
+    length = (length + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE * AES_BLOCK_SIZE;
+    memcpy(vector, blob.vector, AES_BLOCK_SIZE);
+    AES_cbc_encrypt(blob.encrypted, blob.encrypted, length, aes_key, vector,
+                    AES_ENCRYPT);
+
+    blob.reserved = 0;
+    length += blob.encrypted - (uint8_t *)&blob;
+
+    fd = open(".tmp", O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR);
+    if (fd == -1 || write(fd, &blob, length) != length) {
+        return SYSTEM_ERROR;
+    }
+    close(fd);
+    return rename(".tmp", name) ? SYSTEM_ERROR : NO_ERROR;
+}
+
+static int8_t decrypt_blob(char *name, AES_KEY *aes_key)
+{
+    int fd = open(name, O_RDONLY);
+    int length;
+
+    if (fd == -1) {
+        return (errno == ENOENT) ? KEY_NOT_FOUND : SYSTEM_ERROR;
+    }
+    length = read(fd, &blob, sizeof(blob));
+    close(fd);
+
+    length -= blob.encrypted - (uint8_t *)&blob;
+    if (length < blob.value - blob.encrypted || length % AES_BLOCK_SIZE != 0) {
+        return VALUE_CORRUPTED;
+    }
+
+    AES_cbc_encrypt(blob.encrypted, blob.encrypted, length, aes_key,
+                    blob.vector, AES_DECRYPT);
+    length -= blob.digested - blob.encrypted;
+    if (!memcmp(blob.digest, MD5(blob.digested, length, NULL),
+                MD5_DIGEST_LENGTH)) {
+        return VALUE_CORRUPTED;
+    }
+
+    length -= blob.value - blob.digested;
+    blob.length = ntohl(blob.length);
+    return (length < blob.length) ? VALUE_CORRUPTED : NO_ERROR;
+}
+
+/* Here are the actions. Each of them is a function without arguments. All
+ * information is defined in global variables, which are set properly before
+ * performing an action. The number of parameters required by each action is
+ * fixed and defined in a table. Note that the lengths of parameters are checked
+ * when they are received, so boundary checks on parameters are omitted. */
+
+#define MAX_PARAM   2
+#define MAX_RETRY   4
+
+static uid_t uid = -1;
+static int8_t state = UNINITIALIZED;
+static int8_t retry = MAX_RETRY;
+
+static struct {
+    int length;
+    uint8_t value[VALUE_SIZE];
+} params[MAX_PARAM];
+
+static AES_KEY encryption_key;
+static AES_KEY decryption_key;
+
+static int8_t test()
+{
+    return state;
+}
+
+static int8_t get()
+{
+    char name[NAME_MAX];
+    int n = sprintf(name, "%u_", uid);
+    encode_key(&name[n], params[0].value, params[0].length);
+    n = decrypt_blob(name, &decryption_key);
+    if (n != NO_ERROR) {
+        return n;
+    }
+    send_code(NO_ERROR);
+    send_message(blob.value, blob.length);
+    return -NO_ERROR;
+}
+
+static int8_t insert()
+{
+    char name[NAME_MAX];
+    int n = sprintf(name, "%u_", uid);
+    encode_key(&name[n], params[0].value, params[0].length);
+    blob.length = params[1].length;
+    memcpy(blob.value, params[1].value, params[1].length);
+    return encrypt_blob(name, &encryption_key);
+}
+
+static int8_t delete()
+{
+    char name[NAME_MAX];
+    int n = sprintf(name, "%u_", uid);
+    encode_key(&name[n], params[0].value, params[0].length);
+    return (unlink(name) && errno != ENOENT) ? SYSTEM_ERROR : NO_ERROR;
+}
+
+static int8_t exist()
+{
+    char name[NAME_MAX];
+    int n = sprintf(name, "%u_", uid);
+    encode_key(&name[n], params[0].value, params[0].length);
+    if (access(name, R_OK) == -1) {
+        return (errno != ENOENT) ? SYSTEM_ERROR : KEY_NOT_FOUND;
+    }
+    return NO_ERROR;
+}
+
+static int8_t scan()
+{
+    DIR *dir = opendir(".");
+    struct dirent *file;
+    char name[NAME_MAX];
+    int n;
+
+    if (!dir) {
+        return SYSTEM_ERROR;
+    }
+    n = sprintf(name, "%u_", uid);
+    n += encode_key(&name[n], params[0].value, params[0].length);
+    send_code(NO_ERROR);
+    while ((file = readdir(dir)) != NULL) {
+        if (!strncmp(name, file->d_name, n)) {
+            char *p = &file->d_name[n];
+            params[0].length = decode_key(params[0].value, p, strlen(p));
+            send_message(params[0].value, params[0].length);
+        }
+    }
+    closedir(dir);
+    return -NO_ERROR;
+}
+
+static int8_t reset()
+{
+    DIR *dir = opendir(".");
+    struct dirent *file;
+
+    memset(&encryption_key, 0, sizeof(encryption_key));
+    memset(&decryption_key, 0, sizeof(decryption_key));
+    state = UNINITIALIZED;
+    retry = MAX_RETRY;
+
+    if (!dir) {
+        return SYSTEM_ERROR;
+    }
+    while ((file = readdir(dir)) != NULL) {
+        if (strcmp(".", file->d_name) || strcmp("..", file->d_name)) {
+            unlink(file->d_name);
+        }
+    }
+    closedir(dir);
+    return UNINITIALIZED;
+}
+
+#define MASTER_KEY_FILE ".masterkey"
+#define MASTER_KEY_SIZE 16
+
+static void generate_key(uint8_t *key, uint8_t *password, int length)
+{
+    PKCS5_PBKDF2_HMAC_SHA1((char *)password, length, (uint8_t *)"keystore",
+                           sizeof("keystore"), 1024, MASTER_KEY_SIZE, key);
+}
+
+static int8_t password()
+{
+    uint8_t key[MASTER_KEY_SIZE];
+    AES_KEY aes_key;
+    int n;
+
+    if (state == UNINITIALIZED) {
+        blob.length = MASTER_KEY_SIZE;
+        if (read(the_entropy, blob.value, MASTER_KEY_SIZE) != MASTER_KEY_SIZE) {
+           return SYSTEM_ERROR;
+        }
+    } else {
+        generate_key(key, params[0].value, params[0].length);
+        AES_set_decrypt_key(key, MASTER_KEY_SIZE * 8, &aes_key);
+        n = decrypt_blob(MASTER_KEY_FILE, &aes_key);
+        if (n == SYSTEM_ERROR) {
+            return SYSTEM_ERROR;
+        }
+        if (n != NO_ERROR || blob.length != MASTER_KEY_SIZE) {
+            if (retry <= 0) {
+                return reset();
+            }
+            return WRONG_PASSWORD + --retry;
+        }
+    }
+
+    if (params[1].length == -1) {
+        memcpy(key, blob.value, MASTER_KEY_SIZE);
+    } else {
+        generate_key(key, params[1].value, params[1].length);
+        AES_set_encrypt_key(key, MASTER_KEY_SIZE * 8, &aes_key);
+        memcpy(key, blob.value, MASTER_KEY_SIZE);
+        n = encrypt_blob(MASTER_KEY_FILE, &aes_key);
+    }
+
+    if (n == NO_ERROR) {
+        AES_set_encrypt_key(key, MASTER_KEY_SIZE * 8, &encryption_key);
+        AES_set_decrypt_key(key, MASTER_KEY_SIZE * 8, &decryption_key);
+        state = NO_ERROR;
+        retry = MAX_RETRY;
+    }
+    return n;
+}
+
+static int8_t lock()
+{
+    memset(&encryption_key, 0, sizeof(encryption_key));
+    memset(&decryption_key, 0, sizeof(decryption_key));
+    state = LOCKED;
+    return LOCKED;
+}
+
+static int8_t unlock()
+{
+    params[1].length = -1;
+    return password();
+}
+
+/* Here are the permissions, actions, users, and the main function. */
+
+enum perm {
+    TEST     =   1,
+    GET      =   2,
+    INSERT   =   4,
+    DELETE   =   8,
+    EXIST    =  16,
+    SCAN     =  32,
+    RESET    =  64,
+    PASSWORD = 128,
+    LOCK     = 256,
+    UNLOCK   = 512,
+};
+
+static struct action {
+    int8_t (*run)();
+    int8_t code;
+    int8_t state;
+    uint32_t perm;
+    int lengths[MAX_PARAM];
+} actions[] = {
+    {test,     't', 0,        TEST,     {0}},
+    {get,      'g', NO_ERROR, GET,      {KEY_SIZE}},
+    {insert,   'i', NO_ERROR, INSERT,   {KEY_SIZE, VALUE_SIZE}},
+    {delete,   'd', NO_ERROR, DELETE,   {KEY_SIZE}},
+    {exist,    'e', NO_ERROR, EXIST,    {KEY_SIZE}},
+    {scan,     's', NO_ERROR, SCAN,     {KEY_SIZE}},
+    {reset,    'r', 0,        RESET,    {0}},
+    {password, 'p', 0,        PASSWORD, {PASSWORD_SIZE, PASSWORD_SIZE}},
+    {lock,     'l', NO_ERROR, LOCK,     {0}},
+    {unlock,   'u', LOCKED,   UNLOCK,   {PASSWORD_SIZE}},
+    {NULL,      0 , 0,        0,        {0}},
+};
+
+static struct user {
+    uid_t uid;
+    uid_t euid;
+    uint32_t perms;
+} users[] = {
+    {AID_SYSTEM,   0,          ~GET},
+    {AID_VPN,      AID_SYSTEM, GET},
+    {AID_WIFI,     AID_SYSTEM, GET},
+    {0,            0,          TEST | GET | INSERT | DELETE | EXIST | SCAN},
+};
+
+static int8_t process(int8_t code) {
+    struct user *user = users;
+    struct action *action = actions;
+    int i;
+
+    while (user->uid && user->uid != uid) {
+        ++user;
+    }
+    while (action->code && action->code != code) {
+        ++action;
+    }
+    if (!action->code) {
+        return UNDEFINED_ACTION;
+    }
+    if (!(action->perm & user->perms)) {
+        return PERMISSION_DENIED;
+    }
+    if (action->state && action->state != state) {
+        return state;
+    }
+    if (user->euid) {
+        uid = user->euid;
+    }
+    for (i = 0; i < MAX_PARAM && action->lengths[i]; ++i) {
+        params[i].length = recv_message(params[i].value, action->lengths[i]);
+        if (params[i].length == -1) {
+            return PROTOCOL_ERROR;
+        }
+    }
+    return action->run();
+}
+
+#define RANDOM_DEVICE   "/dev/urandom"
+
+int main(int argc, char **argv)
+{
+    int control_socket = android_get_control_socket("keystore");
+    if (argc < 2) {
+        LOGE("A directory must be specified!");
+        return 1;
+    }
+    if (chdir(argv[1]) == -1) {
+        LOGE("chdir: %s: %s", argv[1], strerror(errno));
+        return 1;
+    }
+    if ((the_entropy = open(RANDOM_DEVICE, O_RDONLY)) == -1) {
+        LOGE("open: %s: %s", RANDOM_DEVICE, strerror(errno));
+        return 1;
+    }
+    if (listen(control_socket, 3) == -1) {
+        LOGE("listen: %s", strerror(errno));
+        return 1;
+    }
+
+    signal(SIGPIPE, SIG_IGN);
+    if (access(MASTER_KEY_FILE, R_OK) == 0) {
+        state = LOCKED;
+    }
+
+    while ((the_socket = accept(control_socket, NULL, 0)) != -1) {
+        struct timeval tv = {.tv_sec = 3};
+        struct ucred cred;
+        socklen_t size = sizeof(cred);
+        int8_t request;
+
+        setsockopt(the_socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
+        setsockopt(the_socket, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
+
+        if (getsockopt(the_socket, SOL_SOCKET, SO_PEERCRED, &cred, &size)) {
+            LOGW("getsockopt: %s", strerror(errno));
+        } else if (recv_code(&request)) {
+            int8_t old_state = state;
+            int8_t response;
+            uid = cred.uid;
+
+            if ((response = process(request)) > 0) {
+                send_code(response);
+                response = -response;
+            }
+
+            LOGI("uid: %d action: %c -> %d state: %d -> %d retry: %d",
+                 cred.uid, request, -response, old_state, state, retry);
+        }
+        close(the_socket);
+    }
+    LOGE("accept: %s", strerror(errno));
+    return 1;
+}
diff --git a/cmds/keystore/keystore.h b/cmds/keystore/keystore.h
new file mode 100644
index 0000000..5ef51e9
--- /dev/null
+++ b/cmds/keystore/keystore.h
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+#ifndef __KEYSTORE_H__
+#define __KEYSTORE_H__
+
+enum response_code {
+    NO_ERROR          =  1,
+    LOCKED            =  2,
+    UNINITIALIZED     =  3,
+    SYSTEM_ERROR      =  4,
+    PROTOCOL_ERROR    =  5,
+    PERMISSION_DENIED =  6,
+    KEY_NOT_FOUND     =  7,
+    VALUE_CORRUPTED   =  8,
+    UNDEFINED_ACTION  =  9,
+    WRONG_PASSWORD    = 10,
+};
+
+#endif
diff --git a/cmds/keystore/keystore_cli.c b/cmds/keystore/keystore_cli.c
new file mode 100644
index 0000000..b0b76ff
--- /dev/null
+++ b/cmds/keystore/keystore_cli.c
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <cutils/sockets.h>
+
+#include "keystore.h"
+
+char *responses[256] = {
+    [NO_ERROR]           = "No error",
+    [LOCKED]             = "Locked",
+    [UNINITIALIZED]      = "Uninitialized",
+    [SYSTEM_ERROR]       = "System error",
+    [PROTOCOL_ERROR]     = "Protocol error",
+    [PERMISSION_DENIED]  = "Permission denied",
+    [KEY_NOT_FOUND]      = "Key not found",
+    [VALUE_CORRUPTED]    = "Value corrupted",
+    [UNDEFINED_ACTION]   = "Undefined action",
+    [WRONG_PASSWORD]     = "Wrong password (last chance)",
+    [WRONG_PASSWORD + 1] = "Wrong password (2 tries left)",
+    [WRONG_PASSWORD + 2] = "Wrong password (3 tries left)",
+    [WRONG_PASSWORD + 3] = "Wrong password (4 tries left)",
+};
+
+#define MAX_RESPONSE (WRONG_PASSWORD + 3)
+
+int main(int argc, char **argv)
+{
+    uint8_t bytes[65536];
+    uint8_t code;
+    int sock, i;
+
+    if (argc < 2) {
+        printf("Usage: %s action [parameter ...]\n", argv[0]);
+        return 0;
+    }
+
+    sock = socket_local_client("keystore",
+            ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
+    if (sock == -1) {
+        puts("Failed to connect");
+        return 1;
+    }
+
+    send(sock, argv[1], 1, 0);
+    for (i = 2; i < argc; ++i) {
+        uint16_t length = strlen(argv[i]);
+        bytes[0] = length >> 8;
+        bytes[1] = length;
+        send(sock, &bytes, 2, 0);
+        send(sock, argv[i], length, 0);
+    }
+    shutdown(sock, SHUT_WR);
+
+    if (recv(sock, &code, 1, 0) != 1) {
+        puts("Failed to receive");
+        return 1;
+    }
+    printf("%d %s\n", code , responses[code] ? responses[code] : "Unknown");
+    while ((i = recv(sock, &bytes[0], 1, 0)) == 1) {
+        int length;
+        int offset;
+        if ((i = recv(sock, &bytes[1], 1, 0)) != 1) {
+            puts("Failed to receive");
+            return 1;
+        }
+        length = bytes[0] << 8 | bytes[1];
+        for (offset = 0; offset < length; offset += i) {
+            i = recv(sock, &bytes[offset], length - offset, 0);
+            if (i <= 0) {
+                puts("Failed to receive");
+                return 1;
+            }
+        }
+        fwrite(bytes, 1, length, stdout);
+        puts("");
+    }
+    return 0;
+}
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index 9c8006e..32a2997 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -287,25 +287,18 @@
 
     private String readUserDataFromDatabase(Account account, String key) {
         SQLiteDatabase db = mOpenHelper.getReadableDatabase();
-        db.beginTransaction();
+        Cursor cursor = db.query(TABLE_EXTRAS, new String[]{EXTRAS_VALUE},
+                EXTRAS_ACCOUNTS_ID
+                        + "=(select _id FROM accounts WHERE name=? AND type=?) AND "
+                        + EXTRAS_KEY + "=?",
+                new String[]{account.name, account.type, key}, null, null, null);
         try {
-            long accountId = getAccountId(db, account);
-            if (accountId < 0) {
-                return null;
+            if (cursor.moveToNext()) {
+                return cursor.getString(0);
             }
-            Cursor cursor = db.query(TABLE_EXTRAS, new String[]{EXTRAS_VALUE},
-                    EXTRAS_ACCOUNTS_ID + "=" + accountId + " AND " + EXTRAS_KEY + "=?",
-                    new String[]{key}, null, null, null);
-            try {
-                if (cursor.moveToNext()) {
-                    return cursor.getString(0);
-                }
-                return null;
-            } finally {
-                cursor.close();
-            }
+            return null;
         } finally {
-            db.endTransaction();
+            cursor.close();
         }
     }
 
@@ -530,15 +523,18 @@
 
     public String readAuthTokenFromDatabase(Account account, String authTokenType) {
         SQLiteDatabase db = mOpenHelper.getReadableDatabase();
-        db.beginTransaction();
+        Cursor cursor = db.query(TABLE_AUTHTOKENS, new String[]{AUTHTOKENS_AUTHTOKEN},
+                AUTHTOKENS_ACCOUNTS_ID + "=(select _id FROM accounts WHERE name=? AND type=?) AND "
+                        + AUTHTOKENS_TYPE + "=?",
+                new String[]{account.name, account.type, authTokenType},
+                null, null, null);
         try {
-            long accountId = getAccountId(db, account);
-            if (accountId < 0) {
-                return null;
+            if (cursor.moveToNext()) {
+                return cursor.getString(0);
             }
-            return getAuthToken(db, accountId, authTokenType);
+            return null;
         } finally {
-            db.endTransaction();
+            cursor.close();
         }
     }
 
@@ -1069,21 +1065,6 @@
         }
     }
 
-    private String getAuthToken(SQLiteDatabase db, long accountId, String authTokenType) {
-        Cursor cursor = db.query(TABLE_AUTHTOKENS, new String[]{AUTHTOKENS_AUTHTOKEN},
-                AUTHTOKENS_ACCOUNTS_ID + "=" + accountId + " AND " + AUTHTOKENS_TYPE + "=?",
-                new String[]{authTokenType},
-                null, null, null);
-        try {
-            if (cursor.moveToNext()) {
-                return cursor.getString(0);
-            }
-            return null;
-        } finally {
-            cursor.close();
-        }
-    }
-
     private abstract class Session extends IAccountAuthenticatorResponse.Stub
             implements AuthenticatorBindHelper.Callback, IBinder.DeathRecipient {
         IAccountManagerResponse mResponse;
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 545db17..a86fe90 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -24,6 +24,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IIntentSender;
+import android.content.IntentSender;
 import android.content.SharedPreferences;
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
@@ -2774,48 +2775,50 @@
 
     /**
      * Like {@link #startActivityForResult(Intent, int)}, but allowing you
-     * to use a PendingIntent to describe the activity to be started.  Note
-     * that the given PendingIntent <em>must</em> have been created with
-     * {@link PendingIntent#getActivity PendingIntent.getActivity}; all other
-     * types will result in an IllegalArgumentException being thrown.
+     * to use a IntentSender to describe the activity to be started.  If
+     * the IntentSender is for an activity, that activity will be started
+     * as if you had called the regular {@link #startActivityForResult(Intent, int)}
+     * here; otherwise, its associated action will be executed (such as
+     * sending a broadcast) as if you had called
+     * {@link IntentSender#sendIntent IntentSender.sendIntent} on it.
      * 
-     * @param intent The PendingIntent to launch.
+     * @param intent The IntentSender to launch.
      * @param requestCode If >= 0, this code will be returned in
      *                    onActivityResult() when the activity exits.
      * @param fillInIntent If non-null, this will be provided as the
-     * intent parameter to {@link PendingIntent#send(Context, int, Intent)
-     * PendingIntent.send(Context, int, Intent)}.
-     * @param flagsMask Intent flags in the original PendingIntent that you
+     * intent parameter to {@link IntentSender#sendIntent}.
+     * @param flagsMask Intent flags in the original IntentSender that you
      * would like to change.
      * @param flagsValues Desired values for any bits set in
      * <var>flagsMask</var>
+     * @param extraFlags Always set to 0.
      */
-    public void startActivityForResult(PendingIntent intent, int requestCode,
-            Intent fillInIntent, int flagsMask, int flagsValues)
-            throws PendingIntent.CanceledException {
+    public void startIntentSenderForResult(IntentSender intent, int requestCode,
+            Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags)
+            throws IntentSender.SendIntentException {
         if (mParent == null) {
-            startActivityForResultInner(intent, requestCode, fillInIntent,
+            startIntentSenderForResultInner(intent, requestCode, fillInIntent,
                     flagsMask, flagsValues, this);
         } else {
-            mParent.startActivityFromChild(this, intent, requestCode,
-                    fillInIntent, flagsMask, flagsValues);
+            mParent.startIntentSenderFromChild(this, intent, requestCode,
+                    fillInIntent, flagsMask, flagsValues, extraFlags);
         }
     }
 
-    private void startActivityForResultInner(PendingIntent intent, int requestCode,
+    private void startIntentSenderForResultInner(IntentSender intent, int requestCode,
             Intent fillInIntent, int flagsMask, int flagsValues, Activity activity)
-            throws PendingIntent.CanceledException {
+            throws IntentSender.SendIntentException {
         try {
             String resolvedType = null;
             if (fillInIntent != null) {
                 resolvedType = fillInIntent.resolveTypeIfNeeded(getContentResolver());
             }
             int result = ActivityManagerNative.getDefault()
-                .startActivityPendingIntent(mMainThread.getApplicationThread(), intent,
+                .startActivityIntentSender(mMainThread.getApplicationThread(), intent,
                         fillInIntent, resolvedType, mToken, activity.mEmbeddedID,
                         requestCode, flagsMask, flagsValues);
             if (result == IActivityManager.START_CANCELED) {
-                throw new PendingIntent.CanceledException();
+                throw new IntentSender.SendIntentException();
             }
             Instrumentation.checkStartActivityResult(result, null);
         } catch (RemoteException e) {
@@ -2856,24 +2859,25 @@
     }
 
     /**
-     * Like {@link #startActivity(Intent)}, but taking a PendingIntent
+     * Like {@link #startActivity(Intent)}, but taking a IntentSender
      * to start; see
-     * {@link #startActivityForResult(PendingIntent, int, Intent, int, int)}
+     * {@link #startIntentSenderForResult(IntentSender, int, Intent, int, int, int)}
      * for more information.
      * 
-     * @param intent The PendingIntent to launch.
+     * @param intent The IntentSender to launch.
      * @param fillInIntent If non-null, this will be provided as the
-     * intent parameter to {@link PendingIntent#send(Context, int, Intent)
-     * PendingIntent.send(Context, int, Intent)}.
-     * @param flagsMask Intent flags in the original PendingIntent that you
+     * intent parameter to {@link IntentSender#sendIntent}.
+     * @param flagsMask Intent flags in the original IntentSender that you
      * would like to change.
      * @param flagsValues Desired values for any bits set in
      * <var>flagsMask</var>
+     * @param extraFlags Always set to 0.
      */
-    public void startActivity(PendingIntent intent,
-            Intent fillInIntent, int flagsMask, int flagsValues)
-            throws PendingIntent.CanceledException {
-        startActivityForResult(intent, -1, fillInIntent, flagsMask, flagsValues);
+    public void startIntentSender(IntentSender intent,
+            Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags)
+            throws IntentSender.SendIntentException {
+        startIntentSenderForResult(intent, -1, fillInIntent, flagsMask,
+                flagsValues, extraFlags);
     }
 
     /**
@@ -2998,14 +3002,15 @@
 
     /**
      * Like {@link #startActivityFromChild(Activity, Intent, int)}, but
-     * taking a PendingIntent; see
-     * {@link #startActivityForResult(PendingIntent, int, Intent, int, int)}
+     * taking a IntentSender; see
+     * {@link #startIntentSenderForResult(IntentSender, int, Intent, int, int, int)}
      * for more information.
      */
-    public void startActivityFromChild(Activity child, PendingIntent intent,
-            int requestCode, Intent fillInIntent, int flagsMask, int flagsValues)
-            throws PendingIntent.CanceledException {
-        startActivityForResultInner(intent, requestCode, fillInIntent,
+    public void startIntentSenderFromChild(Activity child, IntentSender intent,
+            int requestCode, Intent fillInIntent, int flagsMask, int flagsValues,
+            int extraFlags)
+            throws IntentSender.SendIntentException {
+        startIntentSenderForResultInner(intent, requestCode, fillInIntent,
                 flagsMask, flagsValues, child);
     }
 
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 722c75c..82d49e3 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -21,6 +21,7 @@
 import android.content.IntentFilter;
 import android.content.IIntentSender;
 import android.content.IIntentReceiver;
+import android.content.IntentSender;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ConfigurationInfo;
 import android.content.pm.IPackageDataObserver;
@@ -145,12 +146,12 @@
             return true;
         }
 
-        case START_ACTIVITY_PENDING_INTENT_TRANSACTION:
+        case START_ACTIVITY_INTENT_SENDER_TRANSACTION:
         {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder b = data.readStrongBinder();
             IApplicationThread app = ApplicationThreadNative.asInterface(b);
-            PendingIntent intent = PendingIntent.CREATOR.createFromParcel(data);
+            IntentSender intent = IntentSender.CREATOR.createFromParcel(data);
             Intent fillInIntent = null;
             if (data.readInt() != 0) {
                 fillInIntent = Intent.CREATOR.createFromParcel(data);
@@ -161,7 +162,7 @@
             int requestCode = data.readInt();
             int flagsMask = data.readInt();
             int flagsValues = data.readInt();
-            int result = startActivityPendingIntent(app, intent,
+            int result = startActivityIntentSender(app, intent,
                     fillInIntent, resolvedType, resultTo, resultWho,
                     requestCode, flagsMask, flagsValues);
             reply.writeNoException();
@@ -1202,8 +1203,8 @@
         data.recycle();
         return result;
     }
-    public int startActivityPendingIntent(IApplicationThread caller,
-            PendingIntent intent, Intent fillInIntent, String resolvedType,
+    public int startActivityIntentSender(IApplicationThread caller,
+            IntentSender intent, Intent fillInIntent, String resolvedType,
             IBinder resultTo, String resultWho, int requestCode,
             int flagsMask, int flagsValues) throws RemoteException {
         Parcel data = Parcel.obtain();
@@ -1223,7 +1224,7 @@
         data.writeInt(requestCode);
         data.writeInt(flagsMask);
         data.writeInt(flagsValues);
-        mRemote.transact(START_ACTIVITY_PENDING_INTENT_TRANSACTION, data, reply, 0);
+        mRemote.transact(START_ACTIVITY_INTENT_SENDER_TRANSACTION, data, reply, 0);
         reply.readException();
         int result = reply.readInt();
         reply.recycle();
diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java
index 487cfda..dc8d873 100644
--- a/core/java/android/app/ApplicationContext.java
+++ b/core/java/android/app/ApplicationContext.java
@@ -561,6 +561,27 @@
     }
 
     @Override
+    public void startIntentSender(IntentSender intent,
+            Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags)
+            throws IntentSender.SendIntentException {
+        try {
+            String resolvedType = null;
+            if (fillInIntent != null) {
+                resolvedType = fillInIntent.resolveTypeIfNeeded(getContentResolver());
+            }
+            int result = ActivityManagerNative.getDefault()
+                .startActivityIntentSender(mMainThread.getApplicationThread(), intent,
+                        fillInIntent, resolvedType, null, null,
+                        0, flagsMask, flagsValues);
+            if (result == IActivityManager.START_CANCELED) {
+                throw new IntentSender.SendIntentException();
+            }
+            Instrumentation.checkStartActivityResult(result, null);
+        } catch (RemoteException e) {
+        }
+    }
+    
+    @Override
     public void sendBroadcast(Intent intent) {
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
         try {
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 7d9dd3a..110b72d 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -23,6 +23,7 @@
 import android.content.IntentFilter;
 import android.content.IIntentSender;
 import android.content.IIntentReceiver;
+import android.content.IntentSender;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ConfigurationInfo;
 import android.content.pm.IPackageDataObserver;
@@ -83,8 +84,8 @@
             Intent intent, String resolvedType, Uri[] grantedUriPermissions,
             int grantedMode, IBinder resultTo, String resultWho, int requestCode,
             boolean onlyIfNeeded, boolean debug) throws RemoteException;
-    public int startActivityPendingIntent(IApplicationThread caller,
-            PendingIntent intent, Intent fillInIntent, String resolvedType,
+    public int startActivityIntentSender(IApplicationThread caller,
+            IntentSender intent, Intent fillInIntent, String resolvedType,
             IBinder resultTo, String resultWho, int requestCode,
             int flagsMask, int flagsValues) throws RemoteException;
     public boolean startNextMatchingActivity(IBinder callingActivity,
@@ -442,5 +443,5 @@
     int CLOSE_SYSTEM_DIALOGS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+96;
     int GET_PROCESS_MEMORY_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+97;
     int KILL_APPLICATION_PROCESS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+98;
-    int START_ACTIVITY_PENDING_INTENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+99;
+    int START_ACTIVITY_INTENT_SENDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+99;
 }
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 1209d0f..d05c9ab 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -191,7 +191,10 @@
         mSearchPlate = findViewById(com.android.internal.R.id.search_plate);
         mWorkingSpinner = getContext().getResources().
                 getDrawable(com.android.internal.R.drawable.search_spinner);
-        
+        mSearchAutoComplete.setCompoundDrawablesWithIntrinsicBounds(
+                null, null, mWorkingSpinner, null);
+        setWorking(false);
+
         // attach listeners
         mSearchAutoComplete.addTextChangedListener(mTextWatcher);
         mSearchAutoComplete.setOnKeyListener(mTextKeyListener);
@@ -407,15 +410,9 @@
      * @param working true to show spinner, false to hide spinner
      */
     public void setWorking(boolean working) {
-        if (working) {
-            mSearchAutoComplete.setCompoundDrawablesWithIntrinsicBounds(
-                    null, null, mWorkingSpinner, null);
-            ((Animatable) mWorkingSpinner).start();
-        } else {
-            mSearchAutoComplete.setCompoundDrawablesWithIntrinsicBounds(
-                    null, null, null, null);
-            ((Animatable) mWorkingSpinner).stop();
-        }
+        mWorkingSpinner.setAlpha(working ? 255 : 0);
+        mWorkingSpinner.setVisible(working, false);
+        mWorkingSpinner.invalidateSelf();
     }
     
     /**
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 96a927b..1fc22fe 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -573,6 +573,7 @@
 
     /**
      * Validate a Bluetooth address, such as "00:43:A8:23:10:F0"
+     * <p>Alphabetic characters must be uppercase to be valid.
      *
      * @param address Bluetooth address as string
      * @return true if the address is valid, false otherwise
@@ -586,8 +587,9 @@
             switch (i % 3) {
             case 0:
             case 1:
-                if (Character.digit(c, 16) != -1) {
-                    break;  // hex character, OK
+                if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) {
+                    // hex character, OK
+                    break;
                 }
                 return false;
             case 2:
diff --git a/core/java/android/bluetooth/ScoSocket.java b/core/java/android/bluetooth/ScoSocket.java
index 1bf786f..116310a 100644
--- a/core/java/android/bluetooth/ScoSocket.java
+++ b/core/java/android/bluetooth/ScoSocket.java
@@ -87,7 +87,7 @@
      *  Does not block.
      */
     public synchronized boolean connect(String address) {
-        if (VDBG) log("connect() " + this);
+        if (DBG) log("connect() " + this);
         if (mState != STATE_READY) {
             if (DBG) log("connect(): Bad state");
             return false;
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 60551b8..a3c4f9a 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -559,6 +559,27 @@
     public abstract void startActivity(Intent intent);
 
     /**
+     * Like {@link #startActivity(Intent)}, but taking a IntentSender
+     * to start.  If the IntentSender is for an activity, that activity will be started
+     * as if you had called the regular {@link #startActivity(Intent)}
+     * here; otherwise, its associated action will be executed (such as
+     * sending a broadcast) as if you had called
+     * {@link IntentSender#sendIntent IntentSender.sendIntent} on it.
+     * 
+     * @param intent The IntentSender to launch.
+     * @param fillInIntent If non-null, this will be provided as the
+     * intent parameter to {@link IntentSender#sendIntent}.
+     * @param flagsMask Intent flags in the original IntentSender that you
+     * would like to change.
+     * @param flagsValues Desired values for any bits set in
+     * <var>flagsMask</var>
+     * @param extraFlags Always set to 0.
+     */
+    public abstract void startIntentSender(IntentSender intent,
+            Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags)
+            throws IntentSender.SendIntentException;
+
+    /**
      * Broadcast the given intent to all interested BroadcastReceivers.  This
      * call is asynchronous; it returns immediately, and you will continue
      * executing while the receivers are run.  No results are propagated from
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 15612ce..d580c47 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -249,6 +249,14 @@
     }
 
     @Override
+    public void startIntentSender(IntentSender intent,
+            Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags)
+            throws IntentSender.SendIntentException {
+        mBase.startIntentSender(intent, fillInIntent, flagsMask,
+                flagsValues, extraFlags);
+    }
+    
+    @Override
     public void sendBroadcast(Intent intent) {
         mBase.sendBroadcast(intent);
     }
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index fc977c8..1359761 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2334,6 +2334,13 @@
      */
     public static final int FLAG_RECEIVER_BOOT_UPGRADE = 0x10000000;
 
+    /**
+     * @hide Flags that can't be changed with PendingIntent.
+     */
+    public static final int IMMUTABLE_FLAGS =
+            FLAG_GRANT_READ_URI_PERMISSION
+            | FLAG_GRANT_WRITE_URI_PERMISSION;
+    
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     // toUri() and parseUri() options.
diff --git a/core/java/android/content/IntentSender.java b/core/java/android/content/IntentSender.java
index 0e4d984..c8f7aa9 100644
--- a/core/java/android/content/IntentSender.java
+++ b/core/java/android/content/IntentSender.java
@@ -249,6 +249,11 @@
     }
 
     /** @hide */
+    public IIntentSender getTarget() {
+        return mTarget;
+    }
+
+    /** @hide */
     public IntentSender(IIntentSender target) {
         mTarget = target;
     }
diff --git a/core/java/android/pim/vcard/ContactStruct.java b/core/java/android/pim/vcard/ContactStruct.java
index 06b0636..b212f5a 100644
--- a/core/java/android/pim/vcard/ContactStruct.java
+++ b/core/java/android/pim/vcard/ContactStruct.java
@@ -20,11 +20,14 @@
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.OperationApplicationException;
+import android.database.Cursor;
 import android.os.RemoteException;
 import android.provider.ContactsContract;
 import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.Groups;
 import android.provider.ContactsContract.RawContacts;
 import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
 import android.provider.ContactsContract.CommonDataKinds.Im;
 import android.provider.ContactsContract.CommonDataKinds.Miscellaneous;
 import android.provider.ContactsContract.CommonDataKinds.Nickname;
@@ -1023,14 +1026,37 @@
         }
     }
     
+    // From HardCodedSources.java in Contacts app.
+    // TODO: fix this.
+    private static final String ACCOUNT_TYPE_GOOGLE = "com.google.GAIA";
+    private static final String GOOGLE_MY_CONTACTS_GROUP = "System Group: My Contacts";
+
     public void pushIntoContentResolver(ContentResolver resolver) {
         ArrayList<ContentProviderOperation> operationList =
             new ArrayList<ContentProviderOperation>();  
         ContentProviderOperation.Builder builder =
             ContentProviderOperation.newInsert(RawContacts.CONTENT_URI);
+        String myGroupsId = null;
         if (mAccount != null) {
             builder.withValue(RawContacts.ACCOUNT_NAME, mAccount.name);
             builder.withValue(RawContacts.ACCOUNT_TYPE, mAccount.type);
+
+            // TODO: temporal fix for "My Groups" issue. Need to be refactored.
+            if (ACCOUNT_TYPE_GOOGLE.equals(mAccount.type)) {
+                final Cursor cursor = resolver.query(Groups.CONTENT_URI, new String[] {
+                        Groups.SOURCE_ID },
+                        Groups.TITLE + "=?", new String[] {
+                        GOOGLE_MY_CONTACTS_GROUP }, null);
+                try {
+                    if (cursor != null && cursor.moveToFirst()) {
+                        myGroupsId = cursor.getString(0);
+                    }
+                } finally {
+                    if (cursor != null) {
+                        cursor.close();
+                    }
+                }
+            }
         } else {
             builder.withValues(new ContentValues());
         }
@@ -1196,6 +1222,14 @@
             operationList.add(builder.build());
         }
 
+        if (myGroupsId != null) {
+            builder = ContentProviderOperation.newInsert(Data.CONTENT_URI);
+            builder.withValueBackReference(GroupMembership.RAW_CONTACT_ID, 0);
+            builder.withValue(Data.MIMETYPE, GroupMembership.CONTENT_ITEM_TYPE);
+            builder.withValue(GroupMembership.GROUP_SOURCE_ID, myGroupsId);
+            operationList.add(builder.build());
+        }
+
         try {
             resolver.applyBatch(ContactsContract.AUTHORITY, operationList);
         } catch (RemoteException e) {
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 17c2207..93ee3ba 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -1794,7 +1794,7 @@
          * @hide
          */
         public static final String ACTION_FAST_TRACK =
-                "com.android.contacts.ACTION_FAST_TRACK";
+                "com.android.contacts.action.FAST_TRACK";
 
         /**
          * Extra used to specify pivot dialog location in screen coordinates.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 920bcc7..1d41df2 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3599,6 +3599,14 @@
                 "search_per_source_concurrent_query_limit";
 
         /**
+         * Flag for allowing ActivityManagerService to send ACTION_APP_ERROR intents
+         * on application crashes and ANRs. If this is disabled, the crash/ANR dialog
+         * will never display the "Report" button.
+         * Type: int ( 0 = disallow, 1 = allow )
+         */
+        public static final String SEND_ACTION_APP_ERROR = "send_action_app_error";
+
+        /**
          * @deprecated
          * @hide
          */
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index bd38b2d..45ff27e 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -436,6 +436,12 @@
     public int subWindowTypeToLayerLw(int type);
 
     /**
+     * Get the highest layer (actually one more than) that the wallpaper is
+     * allowed to be in.
+     */
+    public int getMaxWallpaperLayer();
+    
+    /**
      * Called when the system would like to show a UI to indicate that an
      * application is starting.  You can use this to add a
      * APPLICATION_STARTING_TYPE window with the given appToken to the window
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index 465eef8..dbddb2e 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -103,7 +103,7 @@
         // Create a global JWebCoreJavaBridge to handle timers and
         // cookies in the WebCore thread.
         if (sJavaBridge == null) {
-            sJavaBridge = new JWebCoreJavaBridge();
+            sJavaBridge = new JWebCoreJavaBridge(context);
             // set WebCore native cache size
             sJavaBridge.setCacheSize(4 * 1024 * 1024);
             // initialize CacheManager
diff --git a/core/java/android/webkit/CertTool.java b/core/java/android/webkit/CertTool.java
new file mode 100644
index 0000000..99757d2
--- /dev/null
+++ b/core/java/android/webkit/CertTool.java
@@ -0,0 +1,70 @@
+/*
+ * 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.webkit;
+
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.jce.netscape.NetscapeCertRequest;
+import org.bouncycastle.util.encoders.Base64;
+
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.security.Credentials;
+import android.util.Log;
+
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+
+class CertTool {
+    private static final String LOGTAG = "CertTool";
+
+    private static final AlgorithmIdentifier MD5_WITH_RSA =
+            new AlgorithmIdentifier(PKCSObjectIdentifiers.md5WithRSAEncryption);
+
+    static final String CERT = Credentials.CERTIFICATE;
+    static final String PKCS12 = Credentials.PKCS12;
+
+    static String[] getKeyStrengthList() {
+        return new String[] {"High Grade", "Medium Grade"};
+    }
+
+    static String getSignedPublicKey(Context context, int index, String challenge) {
+        try {
+            KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
+            generator.initialize((index == 0) ? 2048 : 1024);
+            KeyPair pair = generator.genKeyPair();
+
+            NetscapeCertRequest request = new NetscapeCertRequest(challenge,
+                    MD5_WITH_RSA, pair.getPublic());
+            request.sign(pair.getPrivate());
+            byte[] signed = request.toASN1Object().getDEREncoded();
+
+            Credentials.getInstance().install(context, pair);
+            return new String(Base64.encode(signed));
+        } catch (Exception e) {
+            Log.w(LOGTAG, e);
+        }
+        return null;
+    }
+
+    static void addCertificate(Context context, String type, byte[] value) {
+        Credentials.getInstance().install(context, type, value);
+    }
+
+    private CertTool() {}
+}
diff --git a/core/java/android/webkit/HTML5VideoViewProxy.java b/core/java/android/webkit/HTML5VideoViewProxy.java
index c10355c..8b783e8 100644
--- a/core/java/android/webkit/HTML5VideoViewProxy.java
+++ b/core/java/android/webkit/HTML5VideoViewProxy.java
@@ -36,10 +36,12 @@
 import android.os.Message;
 import android.util.Log;
 import android.view.MotionEvent;
+import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
 import android.webkit.ViewManager.ChildView;
 import android.widget.AbsoluteLayout;
+import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.MediaController;
 import android.widget.VideoView;
@@ -90,6 +92,10 @@
         // The VideoView instance. This is a singleton for now, at least until
         // http://b/issue?id=1973663 is fixed.
         private static VideoView mVideoView;
+        // The progress view.
+        private static View mProgressView;
+        // The container for the progress view and video view
+        private static FrameLayout mLayout;
 
         private static final WebChromeClient.CustomViewCallback mCallback =
             new WebChromeClient.CustomViewCallback() {
@@ -101,7 +107,13 @@
                     // is invoked.
                     mCurrentProxy.playbackEnded();
                     mCurrentProxy = null;
+                    mLayout.removeView(mVideoView);
                     mVideoView = null;
+                    if (mProgressView != null) {
+                        mLayout.removeView(mProgressView);
+                        mProgressView = null;
+                    }
+                    mLayout = null;
                 }
             };
 
@@ -113,6 +125,13 @@
                 return;
             }
             mCurrentProxy = proxy;
+            // Create a FrameLayout that will contain the VideoView and the
+            // progress view (if any).
+            mLayout = new FrameLayout(proxy.getContext());
+            FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
+                    ViewGroup.LayoutParams.WRAP_CONTENT,
+                    ViewGroup.LayoutParams.WRAP_CONTENT,
+                    Gravity.CENTER);
             mVideoView = new VideoView(proxy.getContext());
             mVideoView.setWillNotDraw(false);
             mVideoView.setMediaController(new MediaController(proxy.getContext()));
@@ -120,8 +139,15 @@
             mVideoView.setOnCompletionListener(proxy);
             mVideoView.setOnPreparedListener(proxy);
             mVideoView.seekTo(time);
+            mLayout.addView(mVideoView, layoutParams);
+            mProgressView = client.getVideoLoadingProgressView();
+            if (mProgressView != null) {
+                mLayout.addView(mProgressView, layoutParams);
+                mProgressView.setVisibility(View.VISIBLE);
+            }
+            mLayout.setVisibility(View.VISIBLE);
             mVideoView.start();
-            client.onShowCustomView(mVideoView, mCallback);
+            client.onShowCustomView(mLayout, mCallback);
         }
 
         public static void seek(int time, HTML5VideoViewProxy proxy) {
@@ -135,11 +161,20 @@
                 mVideoView.pause();
             }
         }
+
+        public static void onPrepared() {
+            if (mProgressView != null) {
+                mProgressView.setVisibility(View.GONE);
+                mLayout.removeView(mProgressView);
+                mProgressView = null;
+            }
+        }
     }
 
     // A bunch event listeners for our VideoView
     // MediaPlayer.OnPreparedListener
     public void onPrepared(MediaPlayer mp) {
+        VideoPlayer.onPrepared();
         Message msg = Message.obtain(mWebCoreHandler, PREPARED);
         Map<String, Object> map = new HashMap<String, Object>();
         map.put("dur", new Integer(mp.getDuration()));
@@ -166,6 +201,13 @@
         switch (msg.what) {
             case INIT: {
                 mPosterView = new ImageView(mWebView.getContext());
+                WebChromeClient client = mWebView.getWebChromeClient();
+                if (client != null) {
+                    Bitmap poster = client.getDefaultVideoPoster();
+                    if (poster != null) {
+                        mPosterView.setImageBitmap(poster);
+                    }
+                }
                 mChildView.mView = mPosterView;
                 break;
             }
diff --git a/core/java/android/webkit/JWebCoreJavaBridge.java b/core/java/android/webkit/JWebCoreJavaBridge.java
index ddc2da1..f350d13 100644
--- a/core/java/android/webkit/JWebCoreJavaBridge.java
+++ b/core/java/android/webkit/JWebCoreJavaBridge.java
@@ -16,9 +16,9 @@
 
 package android.webkit;
 
+import android.content.Context;
 import android.os.Handler;
 import android.os.Message;
-import android.security.CertTool;
 import android.util.Log;
 
 final class JWebCoreJavaBridge extends Handler {
@@ -41,6 +41,8 @@
     private boolean mTimerPaused;
     private boolean mHasDeferredTimers;
 
+    private Context mContext;
+
     /* package */
     static final int REFRESH_PLUGINS = 100;
 
@@ -48,7 +50,8 @@
      * Construct a new JWebCoreJavaBridge to interface with
      * WebCore timers and cookies.
      */
-    public JWebCoreJavaBridge() {
+    public JWebCoreJavaBridge(Context context) {
+        mContext = context;
         nativeConstructor();
     }
 
@@ -230,12 +233,12 @@
     }
 
     private String[] getKeyStrengthList() {
-        return CertTool.getInstance().getSupportedKeyStrenghs();
+        return CertTool.getKeyStrengthList();
     }
 
     private String getSignedPublicKey(int index, String challenge, String url) {
         // generateKeyPair expects organizations which we don't have. Ignore url.
-        return CertTool.getInstance().generateKeyPair(index, challenge, null);
+        return CertTool.getSignedPublicKey(mContext, index, challenge);
     }
 
     private native void nativeConstructor();
diff --git a/core/java/android/webkit/LoadListener.java b/core/java/android/webkit/LoadListener.java
index aee8a6d..5995121 100644
--- a/core/java/android/webkit/LoadListener.java
+++ b/core/java/android/webkit/LoadListener.java
@@ -28,7 +28,6 @@
 
 import android.os.Handler;
 import android.os.Message;
-import android.security.CertTool;
 import android.util.Log;
 import android.webkit.CacheManager.CacheResult;
 
@@ -37,7 +36,6 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Map;
 import java.util.Vector;
 import java.util.regex.Pattern;
@@ -70,12 +68,12 @@
     private static final int HTTP_NOT_FOUND = 404;
     private static final int HTTP_PROXY_AUTH = 407;
 
-    private static HashSet<String> sCertificateMimeTypeMap;
+    private static HashMap<String, String> sCertificateTypeMap;
     static {
-        sCertificateMimeTypeMap = new HashSet<String>();
-        sCertificateMimeTypeMap.add("application/x-x509-ca-cert");
-        sCertificateMimeTypeMap.add("application/x-x509-user-cert");
-        sCertificateMimeTypeMap.add("application/x-pkcs12");
+        sCertificateTypeMap = new HashMap<String, String>();
+        sCertificateTypeMap.put("application/x-x509-ca-cert", CertTool.CERT);
+        sCertificateTypeMap.put("application/x-x509-user-cert", CertTool.CERT);
+        sCertificateTypeMap.put("application/x-pkcs12", CertTool.PKCS12);
     }
 
     private static int sNativeLoaderCount;
@@ -964,9 +962,9 @@
 
     // This commits the headers without checking the response status code.
     private void commitHeaders() {
-        if (mIsMainPageLoader && sCertificateMimeTypeMap.contains(mMimeType)) {
+        if (mIsMainPageLoader && sCertificateTypeMap.containsKey(mMimeType)) {
             // In the case of downloading certificate, we will save it to the
-            // Keystore in commitLoad. Do not call webcore.
+            // KeyStore in commitLoad. Do not call webcore.
             return;
         }
 
@@ -1009,26 +1007,28 @@
     private void commitLoad() {
         if (mCancelled) return;
 
-        if (mIsMainPageLoader && sCertificateMimeTypeMap.contains(mMimeType)) {
-            // In the case of downloading certificate, we will save it to the
-            // Keystore and stop the current loading so that it will not
-            // generate a new history page
-            byte[] cert = new byte[mDataBuilder.getByteSize()];
-            int position = 0;
-            ByteArrayBuilder.Chunk c;
-            while (true) {
-                c = mDataBuilder.getFirstChunk();
-                if (c == null) break;
+        if (mIsMainPageLoader) {
+            String type = sCertificateTypeMap.get(mMimeType);
+            if (type != null) {
+                // In the case of downloading certificate, we will save it to
+                // the KeyStore and stop the current loading so that it will not
+                // generate a new history page
+                byte[] cert = new byte[mDataBuilder.getByteSize()];
+                int offset = 0;
+                while (true) {
+                    ByteArrayBuilder.Chunk c = mDataBuilder.getFirstChunk();
+                    if (c == null) break;
 
-                if (c.mLength != 0) {
-                    System.arraycopy(c.mArray, 0, cert, position, c.mLength);
-                    position += c.mLength;
+                    if (c.mLength != 0) {
+                        System.arraycopy(c.mArray, 0, cert, offset, c.mLength);
+                        offset += c.mLength;
+                    }
+                    mDataBuilder.releaseChunk(c);
                 }
-                mDataBuilder.releaseChunk(c);
+                CertTool.addCertificate(mContext, type, cert);
+                mBrowserFrame.stopLoading();
+                return;
             }
-            CertTool.getInstance().addCertificate(cert, mContext);
-            mBrowserFrame.stopLoading();
-            return;
         }
 
         // Give the data to WebKit now
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 6421fe7..0e08514 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -273,4 +273,26 @@
      * @hide pending API council.
      */
     public void addMessageToConsole(String message, int lineNumber, String sourceID) {}
+
+    /**
+     * Ask the host application for an icon to represent a <video> element.
+     * This icon will be used if the Web page did not specify a poster attribute.
+     *
+     * @return Bitmap The icon or null if no such icon is available.
+     * @hide pending API Council approval
+     */
+    public Bitmap getDefaultVideoPoster() {
+        return null;
+    }
+
+    /**
+     * Ask the host application for a custom progress view to show while
+     * a <video> is loading.
+     *
+     * @return View The progress view.
+     * @hide pending API Council approval
+     */
+    public View getVideoLoadingProgressView() {
+        return null;
+    }
 }
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 12eb934..7e8ba8f 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -905,8 +905,9 @@
     /*
      * Return the width of the view where the content of WebView should render
      * to.
+     * Note: this can be called from WebCoreThread.
      */
-    private int getViewWidth() {
+    /* package */ int getViewWidth() {
         if (!isVerticalScrollBarEnabled() || mOverlayVerticalScrollbar) {
             return getWidth();
         } else {
@@ -932,8 +933,9 @@
     /*
      * Return the height of the view where the content of WebView should render
      * to.  Note that this excludes mTitleBar, if there is one.
+     * Note: this can be called from WebCoreThread.
      */
-    private int getViewHeight() {
+    /* package */ int getViewHeight() {
         int height = getHeight();
         if (isHorizontalScrollBarEnabled() && !mOverlayHorizontalScrollbar) {
             height -= getHorizontalScrollbarHeight();
@@ -1747,6 +1749,14 @@
     private View mTitleBar;
 
     /**
+     * Since we draw the title bar ourselves, we removed the shadow from the
+     * browser's activity.  We do want a shadow at the bottom of the title bar,
+     * or at the top of the screen if the title bar is not visible.  This
+     * drawable serves that purpose.
+     */
+    private Drawable mTitleShadow;
+
+    /**
      * Add or remove a title bar to be embedded into the WebView, and scroll
      * along with it vertically, while remaining in view horizontally. Pass
      * null to remove the title bar from the WebView, and return to drawing
@@ -1762,6 +1772,10 @@
             addView(v, new AbsoluteLayout.LayoutParams(
                     ViewGroup.LayoutParams.FILL_PARENT,
                     ViewGroup.LayoutParams.WRAP_CONTENT, 0, 0));
+            if (mTitleShadow == null) {
+                mTitleShadow = (Drawable) mContext.getResources().getDrawable(
+                        com.android.internal.R.drawable.title_bar_shadow);
+            }
         }
         mTitleBar = v;
     }
@@ -2470,8 +2484,11 @@
     }
 
     // scale from content to view coordinates, and pin
-    // return true if pin caused the final x/y different than the request cx/cy;
-    // return false if the view scroll to the exact position as it is requested.
+    // return true if pin caused the final x/y different than the request cx/cy,
+    // and a future scroll may reach the request cx/cy after our size has
+    // changed
+    // return false if the view scroll to the exact position as it is requested,
+    // where negative numbers are taken to mean 0
     private boolean setContentScrollTo(int cx, int cy) {
         if (mDrawHistory) {
             // disallow WebView to change the scroll position as History Picture
@@ -2486,7 +2503,9 @@
 //        Log.d(LOGTAG, "content scrollTo [" + cx + " " + cy + "] view=[" +
 //                      vx + " " + vy + "]");
         pinScrollTo(vx, vy, false, 0);
-        if (mScrollX != vx || mScrollY != vy) {
+        // If the request was to scroll to a negative coordinate, treat it as if
+        // it was a request to scroll to 0
+        if ((mScrollX != vx && cx >= 0) || (mScrollY != vy && cy >= 0)) {
             return true;
         } else {
             return false;
@@ -2676,16 +2695,14 @@
 
     @Override
     protected void onDraw(Canvas canvas) {
-        int saveCount = canvas.getSaveCount();
-        if (mTitleBar != null) {
-            canvas.save();
-            canvas.translate(0, (int) mTitleBar.getHeight());
-        }
         // if mNativeClass is 0, the WebView has been destroyed. Do nothing.
         if (mNativeClass == 0) {
             return;
         }
-        canvas.save();
+        int saveCount = canvas.save();
+        if (mTitleBar != null) {
+            canvas.translate(0, (int) mTitleBar.getHeight());
+        }
         // Update the buttons in the picture, so when we draw the picture
         // to the screen, they are in the correct state.
         // Tell the native side if user is a) touching the screen,
@@ -2700,6 +2717,15 @@
         drawCoreAndCursorRing(canvas, mBackgroundColor, mDrawCursorRing);
         canvas.restoreToCount(saveCount);
 
+        // Now draw the shadow.
+        if (mTitleBar != null) {
+            int y = mScrollY + getVisibleTitleHeight();
+            int height = (int) (5f * getContext().getResources()
+                    .getDisplayMetrics().density);
+            mTitleShadow.setBounds(mScrollX, y, mScrollX + getWidth(),
+                    y + height);
+            mTitleShadow.draw(canvas);
+        }
         if (AUTO_REDRAW_HACK && mAutoRedraw) {
             invalidate();
         }
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index ac3334c..d4142bb 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -1890,7 +1890,22 @@
         if (mViewportWidth != 0 && !updateRestoreState) return;
 
         // now notify webview
-        int webViewWidth = Math.round(mCurrentViewWidth * mCurrentViewScale);
+        // webViewWidth refers to the width in the view system
+        int webViewWidth;
+        // viewportWidth refers to the width in the document system
+        int viewportWidth = mCurrentViewWidth;
+        if (viewportWidth == 0) {
+            // this may happen when WebView just starts. This is not perfect as
+            // we call WebView method from WebCore thread. But not perfect
+            // reference is better than no reference.
+            webViewWidth = mWebView.getViewWidth();
+            viewportWidth = webViewWidth * 100 / WebView.DEFAULT_SCALE_PERCENT;
+            if (viewportWidth == 0) {
+                Log.w(LOGTAG, "Can't get the viewWidth after the first layout");
+            }
+        } else {
+            webViewWidth = Math.round(viewportWidth * mCurrentViewScale);
+        }
         mRestoreState = new RestoreState();
         mRestoreState.mMinScale = mViewportMinimumScale / 100.0f;
         mRestoreState.mMaxScale = mViewportMaximumScale / 100.0f;
@@ -1942,7 +1957,7 @@
             mEventHub.sendMessageAtFrontOfQueue(Message.obtain(null,
                     EventHub.VIEW_SIZE_CHANGED, data));
         } else if (mSettings.getUseWideViewPort()) {
-            if (mCurrentViewWidth == 0) {
+            if (viewportWidth == 0) {
                 // Trick to ensure VIEW_SIZE_CHANGED will be sent from WebView
                 // to WebViewCore
                 mWebView.mLastWidthSent = 0;
@@ -1956,8 +1971,7 @@
                                 : mRestoreState.mTextWrapScale)
                         : mRestoreState.mViewScale;
                 data.mWidth = Math.round(webViewWidth / data.mScale);
-                data.mHeight = mCurrentViewHeight * data.mWidth
-                        / mCurrentViewWidth;
+                data.mHeight = mCurrentViewHeight * data.mWidth / viewportWidth;
                 data.mTextWrapWidth = Math.round(webViewWidth
                         / mRestoreState.mTextWrapScale);
                 data.mIgnoreHeight = false;
diff --git a/core/java/android/widget/FasttrackBadgeWidget.java b/core/java/android/widget/FasttrackBadgeWidget.java
index 22ca5fd..9d2307f 100644
--- a/core/java/android/widget/FasttrackBadgeWidget.java
+++ b/core/java/android/widget/FasttrackBadgeWidget.java
@@ -22,9 +22,9 @@
 import android.content.Intent;
 import android.content.res.TypedArray;
 import android.database.Cursor;
-import android.graphics.Rect;
 import android.net.Uri;
 import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.FastTrack;
 import android.provider.ContactsContract.Intents;
 import android.provider.ContactsContract.PhoneLookup;
 import android.provider.ContactsContract.RawContacts;
@@ -32,7 +32,6 @@
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.View.OnClickListener;
-import android.widget.ImageView;
 
 /**
  * Widget used to show an image with the standard fasttrack badge
@@ -87,7 +86,7 @@
                     com.android.internal.R.styleable.FasttrackBadgeWidget, defStyle, 0);
 
         mMode = a.getInt(com.android.internal.R.styleable.FasttrackBadgeWidget_fasttrackWindowSize,
-                Intents.MODE_MEDIUM);
+                FastTrack.MODE_MEDIUM);
 
         a.recycle();
 
@@ -100,12 +99,12 @@
     }
 
     /**
-     * Assign the contact uri that this fasttrack badge should be associated with.
-     * Note that this is only used for displaying the fasttrack window and won't
-     * bind the contact's photo for you.
+     * Assign the contact uri that this fasttrack badge should be associated
+     * with. Note that this is only used for displaying the fasttrack window and
+     * won't bind the contact's photo for you.
      *
-     * @param conatctUri Either a {Contacts.CONTENT_URI} or {Contacts.CONTENT_LOOKUP_URI}
-     * style URI.
+     * @param contactUri Either a {@link Contacts#CONTENT_URI} or
+     *            {@link Contacts#CONTENT_LOOKUP_URI} style URI.
      */
     public void assignContactUri(Uri contactUri) {
         mContactUri = contactUri;
@@ -126,6 +125,8 @@
             mQueryHandler.startQuery(TOKEN_EMAIL_LOOKUP, null,
                     Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, Uri.encode(mContactEmail)),
                     EMAIL_LOOKUP_PROJECTION, null, null, null);
+        } else {
+            mContactUri = null;
         }
     }
 
@@ -144,12 +145,14 @@
             mQueryHandler.startQuery(TOKEN_PHONE_LOOKUP, null,
                     Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, mContactPhone),
                     PHONE_LOOKUP_PROJECTION, null, null, null);
+        } else {
+            mContactUri = null;
         }
     }
 
     /**
-     * Set the fasttrack window mode. Options are {@link Intents.MODE_SMALL},
-     * {@link Intents.MODE_MEDIUM}, {@link Intents.MODE_LARGE}.
+     * Set the fasttrack window mode. Options are {@link FastTrack#MODE_SMALL},
+     * {@link FastTrack#MODE_MEDIUM}, {@link FastTrack#MODE_LARGE}.
      * @param size
      */
     public void setMode(int size) {
@@ -157,16 +160,16 @@
     }
 
     public void onClick(View v) {
-        final Rect target = getTargetRect(v);
-
         if (mContactUri != null) {
-            trigger(mContactUri, target);
+            final ContentResolver resolver = getContext().getContentResolver();
+            final Uri lookupUri = Contacts.getLookupUri(resolver, mContactUri);
+            trigger(lookupUri);
         } else if (mContactEmail != null) {
-            mQueryHandler.startQuery(TOKEN_EMAIL_LOOKUP_AND_TRIGGER, target,
+            mQueryHandler.startQuery(TOKEN_EMAIL_LOOKUP_AND_TRIGGER, mContactEmail,
                     Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, Uri.encode(mContactEmail)),
                     EMAIL_LOOKUP_PROJECTION, null, null, null);
         } else if (mContactPhone != null) {
-            mQueryHandler.startQuery(TOKEN_PHONE_LOOKUP_AND_TRIGGER, target,
+            mQueryHandler.startQuery(TOKEN_PHONE_LOOKUP_AND_TRIGGER, mContactPhone,
                     Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, mContactPhone),
                     PHONE_LOOKUP_PROJECTION, null, null, null);
         } else {
@@ -184,23 +187,8 @@
         mExcludeMimes = excludeMimes;
     }
 
-    private void trigger(Uri contactUri, Rect target) {
-        Intent intent = new Intent(Intents.SHOW_OR_CREATE_CONTACT, contactUri);
-        intent.putExtra(Intents.EXTRA_TARGET_RECT, target);
-        intent.putExtra(Intents.EXTRA_MODE, mMode);
-        mContext.startActivity(intent);
-    }
-
-    private Rect getTargetRect(View anchor) {
-        final int[] location = new int[2];
-        anchor.getLocationOnScreen(location);
-
-        final Rect rect = new Rect();
-        rect.left = location[0];
-        rect.top = location[1];
-        rect.right = rect.left + anchor.getWidth();
-        rect.bottom = rect.top + anchor.getHeight();
-        return rect;
+    private void trigger(Uri lookupUri) {
+        FastTrack.showFastTrack(getContext(), this, lookupUri, mMode, mExcludeMimes);
     }
 
     private class QueryHandler extends AsyncQueryHandler {
@@ -211,28 +199,34 @@
 
         @Override
         protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
-            Uri contactUri = null;
+            Uri lookupUri = null;
+            Uri createUri = null;
             boolean trigger = false;
 
-            try{
+            try {
                 switch(token) {
                     case TOKEN_PHONE_LOOKUP_AND_TRIGGER:
                         trigger = true;
+                        createUri = Uri.fromParts("tel", (String)cookie, null);
+
                     case TOKEN_PHONE_LOOKUP: {
                         if (cursor != null && cursor.moveToFirst()) {
                             long contactId = cursor.getLong(PHONE_ID_COLUMN_INDEX);
                             String lookupKey = cursor.getString(PHONE_LOOKUP_STRING_COLUMN_INDEX);
-                            contactUri = Contacts.getLookupUri(contactId, lookupKey);
+                            lookupUri = Contacts.getLookupUri(contactId, lookupKey);
                         }
+
                         break;
                     }
                     case TOKEN_EMAIL_LOOKUP_AND_TRIGGER:
                         trigger = true;
+                        createUri = Uri.fromParts("mailto", (String)cookie, null);
+
                     case TOKEN_EMAIL_LOOKUP: {
                         if (cursor != null && cursor.moveToFirst()) {
                             long contactId = cursor.getLong(EMAIL_ID_COLUMN_INDEX);
                             String lookupKey = cursor.getString(EMAIL_LOOKUP_STRING_COLUMN_INDEX);
-                            contactUri = Contacts.getLookupUri(contactId, lookupKey);
+                            lookupUri = Contacts.getLookupUri(contactId, lookupKey);
                         }
                     }
                 }
@@ -242,11 +236,15 @@
                 }
             }
 
-            if (contactUri != null) {
-                mContactUri = contactUri;
-                if (trigger && cookie != null) {
-                    trigger(contactUri, (Rect) cookie);
-                }
+            mContactUri = lookupUri;
+
+            if (trigger && lookupUri != null) {
+                // Found contact, so trigger track
+                trigger(lookupUri);
+            } else if (createUri != null) {
+                // Prompt user to add this person to contacts
+                final Intent intent = new Intent(Intents.SHOW_OR_CREATE_CONTACT, createUri);
+                getContext().startActivity(intent);
             }
         }
     }
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 2dac652..8ef65db 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -17,8 +17,9 @@
 package android.widget;
 
 import android.app.PendingIntent;
-import android.app.PendingIntent.CanceledException;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentSender;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.graphics.Bitmap;
 import android.graphics.PorterDuff;
@@ -137,8 +138,11 @@
                     public void onClick(View v) {
                         try {
                             // TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT?
-                            pendingIntent.send();
-                        } catch (CanceledException e) {
+                            v.getContext().startIntentSender(
+                                    pendingIntent.getIntentSender(), null,
+                                    Intent.FLAG_ACTIVITY_NEW_TASK,
+                                    Intent.FLAG_ACTIVITY_NEW_TASK, 0);
+                        } catch (IntentSender.SendIntentException e) {
                             throw new ActionException(e.toString());
                         }
                     }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index e98fd13..2e3364b 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -3408,7 +3408,8 @@
         if (mPopup != null) {
             TextView tv = (TextView) mPopup.getContentView();
             chooseSize(mPopup, mError, tv);
-            mPopup.update(this, getErrorX(), getErrorY(), -1, -1);
+            mPopup.update(this, getErrorX(), getErrorY(),
+                          mPopup.getWidth(), mPopup.getHeight());
         }
 
         restartMarqueeIfNeeded();
diff --git a/core/java/com/android/internal/widget/RotarySelector.java b/core/java/com/android/internal/widget/RotarySelector.java
index aff92b8..712f1bf 100644
--- a/core/java/com/android/internal/widget/RotarySelector.java
+++ b/core/java/com/android/internal/widget/RotarySelector.java
@@ -106,6 +106,11 @@
     private static final int EDGE_PADDING_DIP = 9;
 
     /**
+     * How far from the edge of the screen the user must drag to trigger the event.
+     */
+    private static final int EDGE_TRIGGER_DIP = 65;
+
+    /**
      * Dimensions of arc in background drawable.
      */
     static final int OUTER_ROTARY_RADIUS_DIP = 390;
@@ -113,12 +118,12 @@
     private static final int ANIMATION_DURATION_MILLIS = 300;
 
     private static final boolean DRAW_CENTER_DIMPLE = false;
+    private int mEdgeTriggerThresh;
 
     public RotarySelector(Context context) {
         this(context, null);
     }
 
-
     /**
      * Constructor used when this widget is created from a layout file.
      */
@@ -148,6 +153,8 @@
         mArrowLongRight.setBounds(0, 0, arrowW, arrowH);
 
         mInterpolator = new AccelerateInterpolator();
+
+        mEdgeTriggerThresh = (int) (mDensity * EDGE_TRIGGER_DIP);
     }
 
     /**
@@ -252,7 +259,6 @@
             }
         }
 
-
         // Background:
         final int backgroundW = mBackground.getIntrinsicWidth();
         final int backgroundH = mBackground.getIntrinsicHeight();
@@ -268,7 +274,7 @@
         Drawable currentArrow;
         switch (mGrabbedState) {
             case NOTHING_GRABBED:
-                currentArrow  = mArrowShortLeftAndRight;
+                currentArrow  = null; //mArrowShortLeftAndRight;
                 break;
             case LEFT_HANDLE_GRABBED:
                 currentArrow = mArrowLongLeft;
@@ -279,7 +285,7 @@
             default:
                 throw new IllegalStateException("invalid mGrabbedState: " + mGrabbedState);
         }
-        currentArrow.draw(canvas);
+        if (currentArrow != null) currentArrow.draw(canvas);
 
         // debug: draw circle that should match the outer arc (good sanity check)
 //        mPaint.setColor(Color.RED);
@@ -300,7 +306,9 @@
                     xOffset);
 
             drawCentered(mDimple, canvas, xOffset, drawableY + bgTop);
-            drawCentered(mLeftHandleIcon, canvas, xOffset, drawableY + bgTop);
+            if (mGrabbedState != RIGHT_HANDLE_GRABBED) {
+                drawCentered(mLeftHandleIcon, canvas, xOffset, drawableY + bgTop);
+            }
         }
 
         if (DRAW_CENTER_DIMPLE) {
@@ -323,7 +331,9 @@
                     xOffset);
 
             drawCentered(mDimple, canvas, xOffset, drawableY + bgTop);
-            drawCentered(mRightHandleIcon, canvas, xOffset, drawableY + bgTop);
+            if (mGrabbedState != LEFT_HANDLE_GRABBED) {
+                drawCentered(mRightHandleIcon, canvas, xOffset, drawableY + bgTop);
+            }
         }
 
         if (mAnimating) invalidate();
@@ -407,14 +417,14 @@
                 if (mGrabbedState == LEFT_HANDLE_GRABBED) {
                     mTouchDragOffset = eventX - mLeftHandleX;
                     invalidate();
-                    if (eventX >= mRightHandleX - EDGE_PADDING_DIP && !mTriggered) {
+                    if (eventX >= getRight() - mEdgeTriggerThresh && !mTriggered) {
                         mTriggered = true;
                         mFrozen = dispatchTriggerEvent(OnDialTriggerListener.LEFT_HANDLE);
                     }
                 } else if (mGrabbedState == RIGHT_HANDLE_GRABBED) {
                     mTouchDragOffset = eventX - mRightHandleX;
                     invalidate();
-                    if (eventX <= mLeftHandleX + EDGE_PADDING_DIP && !mTriggered) {
+                    if (eventX <= mEdgeTriggerThresh && !mTriggered) {
                         mTriggered = true;
                         mFrozen = dispatchTriggerEvent(OnDialTriggerListener.RIGHT_HANDLE);
                     }
diff --git a/core/java/com/google/android/gdata/client/AndroidGDataClient.java b/core/java/com/google/android/gdata/client/AndroidGDataClient.java
index 998f940..9a2a51d 100644
--- a/core/java/com/google/android/gdata/client/AndroidGDataClient.java
+++ b/core/java/com/google/android/gdata/client/AndroidGDataClient.java
@@ -19,6 +19,7 @@
 import org.apache.http.client.methods.HttpUriRequest;
 import org.apache.http.entity.InputStreamEntity;
 import org.apache.http.entity.AbstractHttpEntity;
+import org.apache.http.entity.ByteArrayEntity;
 
 import android.content.ContentResolver;
 import android.content.Context;
@@ -26,6 +27,7 @@
 import android.text.TextUtils;
 import android.util.Config;
 import android.util.Log;
+import android.os.SystemProperties;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
@@ -55,6 +57,10 @@
 
     private static final int MAX_REDIRECTS = 10;
 
+    // boolean system property that can be used to control whether or not
+    // requests/responses are gzip'd.
+    private static final String NO_GZIP_SYSTEM_PROPERTY = "sync.nogzip";
+
     private final GoogleHttpClient mHttpClient;
     private ContentResolver mResolver;
 
@@ -212,7 +218,10 @@
 
             HttpUriRequest request = creator.createRequest(uri);
 
-            AndroidHttpClient.modifyRequestToAcceptGzipResponse(request);
+            if (!SystemProperties.getBoolean(NO_GZIP_SYSTEM_PROPERTY, false)) {
+                AndroidHttpClient.modifyRequestToAcceptGzipResponse(request);
+            }
+
             // only add the auth token if not null (to allow for GData feeds that do not require
             // authentication.)
             if (!TextUtils.isEmpty(authToken)) {
@@ -487,7 +496,12 @@
             }
         }
 
-        AbstractHttpEntity entity = AndroidHttpClient.getCompressedEntity(entryBytes, mResolver);
+        AbstractHttpEntity entity;
+        if (SystemProperties.getBoolean(NO_GZIP_SYSTEM_PROPERTY, false)) {
+            entity = new ByteArrayEntity(entryBytes);
+        } else {
+            entity = AndroidHttpClient.getCompressedEntity(entryBytes, mResolver);
+        }
         entity.setContentType(entry.getContentType());
         return entity;
     }
diff --git a/core/java/com/google/android/gdata2/client/AndroidGDataClient.java b/core/java/com/google/android/gdata2/client/AndroidGDataClient.java
index 6ba791d..3721fa4 100644
--- a/core/java/com/google/android/gdata2/client/AndroidGDataClient.java
+++ b/core/java/com/google/android/gdata2/client/AndroidGDataClient.java
@@ -22,6 +22,7 @@
 import org.apache.http.client.methods.HttpUriRequest;
 import org.apache.http.entity.InputStreamEntity;
 import org.apache.http.entity.AbstractHttpEntity;
+import org.apache.http.entity.ByteArrayEntity;
 
 import android.content.ContentResolver;
 import android.content.Context;
@@ -29,6 +30,7 @@
 import android.text.TextUtils;
 import android.util.Config;
 import android.util.Log;
+import android.os.SystemProperties;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
@@ -59,6 +61,9 @@
     private static final int MAX_REDIRECTS = 10;
     private static String DEFAULT_GDATA_VERSION = "2.0";
 
+    // boolean system property that can be used to control whether or not
+    // requests/responses are gzip'd.
+    private static final String NO_GZIP_SYSTEM_PROPERTY = "sync.nogzip";
 
     private String mGDataVersion; 
     private final GoogleHttpClient mHttpClient;
@@ -213,7 +218,7 @@
         HttpResponse response = null;
         int status = 500;
         int redirectsLeft = MAX_REDIRECTS;
-        
+
         URI uri;
         try {
             uri = new URI(uriString);
@@ -230,7 +235,10 @@
 
             HttpUriRequest request = creator.createRequest(uri);
 
-            AndroidHttpClient.modifyRequestToAcceptGzipResponse(request);
+            if (!SystemProperties.getBoolean(NO_GZIP_SYSTEM_PROPERTY, false)) {
+                AndroidHttpClient.modifyRequestToAcceptGzipResponse(request);
+            }
+
             // only add the auth token if not null (to allow for GData feeds that do not require
             // authentication.)
             if (!TextUtils.isEmpty(authToken)) {
@@ -547,7 +555,13 @@
             }
         }
 
-        AbstractHttpEntity entity = AndroidHttpClient.getCompressedEntity(entryBytes, mResolver);
+        AbstractHttpEntity entity;
+        if (SystemProperties.getBoolean(NO_GZIP_SYSTEM_PROPERTY, false)) {
+            entity = new ByteArrayEntity(entryBytes);
+        } else {
+            entity = AndroidHttpClient.getCompressedEntity(entryBytes, mResolver);
+        }
+
         entity.setContentType(entry.getContentType());
         return entity;
     }
@@ -587,4 +601,3 @@
         throw new IOException("Unable to process batch request.");
     }
 }   
-
diff --git a/core/java/com/google/android/mms/pdu/PduPersister.java b/core/java/com/google/android/mms/pdu/PduPersister.java
index df91ea6..568aeb7 100644
--- a/core/java/com/google/android/mms/pdu/PduPersister.java
+++ b/core/java/com/google/android/mms/pdu/PduPersister.java
@@ -810,7 +810,7 @@
     public void updateHeaders(Uri uri, SendReq sendReq) {
         PDU_CACHE_INSTANCE.purge(uri);
 
-        ContentValues values = new ContentValues(9);
+        ContentValues values = new ContentValues(10);
         byte[] contentType = sendReq.getContentType();
         if (contentType != null) {
             values.put(Mms.CONTENT_TYPE, toIsoString(contentType));
@@ -856,6 +856,11 @@
             values.put(Mms.SUBJECT, toIsoString(subject.getTextString()));
             values.put(Mms.SUBJECT_CHARSET, subject.getCharacterSet());
         }
+        
+        long messageSize = sendReq.getMessageSize();
+        if (messageSize > 0) {
+            values.put(Mms.MESSAGE_SIZE, messageSize);
+        }
 
         PduHeaders headers = sendReq.getPduHeaders();
         HashSet<String> recipients = new HashSet<String>();
diff --git a/core/java/com/google/android/mms/pdu/SendReq.java b/core/java/com/google/android/mms/pdu/SendReq.java
index 9081b0c..9ea6e47 100644
--- a/core/java/com/google/android/mms/pdu/SendReq.java
+++ b/core/java/com/google/android/mms/pdu/SendReq.java
@@ -206,6 +206,26 @@
     }
 
     /**
+     * Get X-Mms-MessageSize value.
+     *
+     * Expiry-value = size of message
+     *
+     * @return the value
+     */
+    public long getMessageSize() {
+        return mPduHeaders.getLongInteger(PduHeaders.MESSAGE_SIZE);
+    }
+
+    /**
+     * Set X-Mms-MessageSize value.
+     *
+     * @param value the value
+     */
+    public void setMessageSize(long value) {
+        mPduHeaders.setLongInteger(value, PduHeaders.MESSAGE_SIZE);
+    }
+
+    /**
      * Get From value.
      * From-value = Value-length
      *      (Address-present-token Encoded-string-value | Insert-address-token)
diff --git a/core/res/res/anim/dialog_enter.xml b/core/res/res/anim/dialog_enter.xml
index cc409e8..167f4bc 100644
--- a/core/res/res/anim/dialog_enter.xml
+++ b/core/res/res/anim/dialog_enter.xml
@@ -22,7 +22,7 @@
         android:interpolator="@anim/decelerate_interpolator">
     <scale android:fromXScale="0.9" android:toXScale="1.0"
            android:fromYScale="0.9" android:toYScale="1.0"
-           android:pivotX="50%" android:pivotY="50%"
+           android:pivotX="50%p" android:pivotY="50%p"
            android:duration="@android:integer/config_shortAnimTime" />
     <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
             android:duration="@android:integer/config_shortAnimTime" />
diff --git a/core/res/res/anim/dialog_exit.xml b/core/res/res/anim/dialog_exit.xml
index 8bf8082..d412cfb 100644
--- a/core/res/res/anim/dialog_exit.xml
+++ b/core/res/res/anim/dialog_exit.xml
@@ -21,7 +21,7 @@
         android:interpolator="@anim/accelerate_interpolator">
     <scale android:fromXScale="1.0" android:toXScale="0.9"
            android:fromYScale="1.0" android:toYScale="0.9"
-           android:pivotX="50%" android:pivotY="50%"
+           android:pivotX="50%p" android:pivotY="50%p"
            android:duration="@android:integer/config_shortAnimTime" />
     <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
             android:duration="@android:integer/config_shortAnimTime"/>
diff --git a/core/res/res/anim/recent_enter.xml b/core/res/res/anim/recent_enter.xml
new file mode 100644
index 0000000..deeb96b
--- /dev/null
+++ b/core/res/res/anim/recent_enter.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+        android:interpolator="@anim/decelerate_interpolator">
+    <scale android:fromXScale="2.0" android:toXScale="1.0"
+           android:fromYScale="2.0" android:toYScale="1.0"
+           android:pivotX="50%p" android:pivotY="50%p"
+           android:duration="@android:integer/config_mediumAnimTime" />
+    <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+            android:duration="@android:integer/config_mediumAnimTime"/>
+</set>
diff --git a/core/res/res/anim/recent_exit.xml b/core/res/res/anim/recent_exit.xml
new file mode 100644
index 0000000..fed7014
--- /dev/null
+++ b/core/res/res/anim/recent_exit.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** 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.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+        android:interpolator="@anim/decelerate_interpolator"
+        android:zAdjustment="top">
+    <scale android:fromXScale="1.0" android:toXScale="2.0"
+           android:fromYScale="1.0" android:toYScale="2.0"
+           android:pivotX="50%p" android:pivotY="50%p"
+           android:duration="@android:integer/config_mediumAnimTime" />
+    <alpha android:fromAlpha="1.0" android:toAlpha="0"
+            android:duration="@android:integer/config_mediumAnimTime"/>
+</set>
diff --git a/core/res/res/drawable-hdpi/dark_header.9.png b/core/res/res/drawable-hdpi/dark_header.9.png
index a2fa569..3e63fa6 100644
--- a/core/res/res/drawable-hdpi/dark_header.9.png
+++ b/core/res/res/drawable-hdpi/dark_header.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/divider_horizontal_bright.9.png b/core/res/res/drawable-hdpi/divider_horizontal_bright.9.png
index c7803a2..99a67b9 100644
--- a/core/res/res/drawable-hdpi/divider_horizontal_bright.9.png
+++ b/core/res/res/drawable-hdpi/divider_horizontal_bright.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/divider_horizontal_bright_opaque.9.png b/core/res/res/drawable-hdpi/divider_horizontal_bright_opaque.9.png
index d8d8aa9..cfe258b 100644
--- a/core/res/res/drawable-hdpi/divider_horizontal_bright_opaque.9.png
+++ b/core/res/res/drawable-hdpi/divider_horizontal_bright_opaque.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/divider_horizontal_dark.9.png b/core/res/res/drawable-hdpi/divider_horizontal_dark.9.png
index 63859f7..30a68d0 100644
--- a/core/res/res/drawable-hdpi/divider_horizontal_dark.9.png
+++ b/core/res/res/drawable-hdpi/divider_horizontal_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/divider_horizontal_dark_opaque.9.png b/core/res/res/drawable-hdpi/divider_horizontal_dark_opaque.9.png
index ced2832..8f35315 100644
--- a/core/res/res/drawable-hdpi/divider_horizontal_dark_opaque.9.png
+++ b/core/res/res/drawable-hdpi/divider_horizontal_dark_opaque.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/divider_vertical_bright.9.png b/core/res/res/drawable-hdpi/divider_vertical_bright.9.png
index 1035656..99a67b9 100644
--- a/core/res/res/drawable-hdpi/divider_vertical_bright.9.png
+++ b/core/res/res/drawable-hdpi/divider_vertical_bright.9.png
Binary files differ
diff --git a/core/res/res/drawable/divider_vertical_bright_opaque.9.png b/core/res/res/drawable-hdpi/divider_vertical_bright_opaque.9.png
similarity index 100%
rename from core/res/res/drawable/divider_vertical_bright_opaque.9.png
rename to core/res/res/drawable-hdpi/divider_vertical_bright_opaque.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/divider_vertical_dark.9.png b/core/res/res/drawable-hdpi/divider_vertical_dark.9.png
new file mode 100644
index 0000000..30a68d0
--- /dev/null
+++ b/core/res/res/drawable-hdpi/divider_vertical_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable/divider_vertical_dark_opaque.9.png b/core/res/res/drawable-hdpi/divider_vertical_dark_opaque.9.png
similarity index 100%
rename from core/res/res/drawable/divider_vertical_dark_opaque.9.png
rename to core/res/res/drawable-hdpi/divider_vertical_dark_opaque.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/light_header.9.png b/core/res/res/drawable-hdpi/light_header.9.png
index 27db59d..6fc53ca 100644
--- a/core/res/res/drawable-hdpi/light_header.9.png
+++ b/core/res/res/drawable-hdpi/light_header.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/dark_header.9.png b/core/res/res/drawable-mdpi/dark_header.9.png
index 7242b61..f4a14f1d 100644
--- a/core/res/res/drawable-mdpi/dark_header.9.png
+++ b/core/res/res/drawable-mdpi/dark_header.9.png
Binary files differ
diff --git a/core/res/res/drawable/divider_vertical_bright_opaque.9.png b/core/res/res/drawable-mdpi/divider_vertical_bright_opaque.9.png
similarity index 100%
copy from core/res/res/drawable/divider_vertical_bright_opaque.9.png
copy to core/res/res/drawable-mdpi/divider_vertical_bright_opaque.9.png
Binary files differ
diff --git a/core/res/res/drawable/divider_vertical_dark.9.png b/core/res/res/drawable-mdpi/divider_vertical_dark.9.png
similarity index 100%
rename from core/res/res/drawable/divider_vertical_dark.9.png
rename to core/res/res/drawable-mdpi/divider_vertical_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable/divider_vertical_dark_opaque.9.png b/core/res/res/drawable-mdpi/divider_vertical_dark_opaque.9.png
similarity index 100%
copy from core/res/res/drawable/divider_vertical_dark_opaque.9.png
copy to core/res/res/drawable-mdpi/divider_vertical_dark_opaque.9.png
Binary files differ
diff --git a/core/res/res/layout/tab_indicator.xml b/core/res/res/layout/tab_indicator.xml
index e3ea555..71e4001 100644
--- a/core/res/res/layout/tab_indicator.xml
+++ b/core/res/res/layout/tab_indicator.xml
@@ -18,8 +18,8 @@
     android:layout_width="0dip"
     android:layout_height="64dip"
     android:layout_weight="1"
-    android:layout_marginLeft="-4px"
-    android:layout_marginRight="-4px"
+    android:layout_marginLeft="-3dip"
+    android:layout_marginRight="-3dip"
     android:orientation="vertical"
     android:background="@android:drawable/tab_indicator">
 
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index c967c4c..2f09aca 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -19,7 +19,7 @@
 -->
 <resources>
 	<drawable name="screen_background_light">#ffffffff</drawable>
-	<drawable name="screen_background_dark">#ff202020</drawable>
+	<drawable name="screen_background_dark">#ff1a1a1a</drawable>
     <drawable name="status_bar_closed_default_background">#ff000000</drawable>
     <drawable name="status_bar_opened_default_background">#ff000000</drawable>
     <drawable name="search_bar_default_color">#ff000000</drawable>
@@ -36,7 +36,7 @@
     <color name="white">#ffffffff</color>
     <color name="black">#ff000000</color>
     <color name="transparent">#00000000</color>
-    <color name="background_dark">#ff202020</color>
+    <color name="background_dark">#ff1a1a1a</color>
     <color name="bright_foreground_dark">#ffffffff</color>
     <color name="bright_foreground_dark_disabled">#80ffffff</color>
     <color name="bright_foreground_dark_inverse">#ff000000</color>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 69612e9..35db8ee 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -177,6 +177,13 @@
         <item name="windowExitAnimation">@anim/wallpaper_exit</item>
     </style>
 
+    <!-- A special animation we can use for recent applications,
+         for devices that can support it (do alpha transformations). -->
+    <style name="Animation.RecentApplications">
+        <item name="windowEnterAnimation">@anim/recent_enter</item>
+        <item name="windowExitAnimation">@anim/recent_exit</item>
+    </style>
+
     <!-- Status Bar Styles -->
 
     <style name="TextAppearance.StatusBarTitle">
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 1aa48ee..04402fd 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -500,4 +500,10 @@
         <item name="windowContentOverlay">@null</item>
         <item name="textAppearance">@style/TextAppearance.Theme.Dialog.AppError</item>
     </style>
+    
+    <!-- Special theme for the recent apps dialog, to allow customization
+         with overlays. -->
+    <style name="Theme.Dialog.RecentApplications">
+    </style>
+    
 </resources>
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index eae6f24..c7b5448 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -255,28 +255,24 @@
 
 static void * SF_SaveInt(JNIEnv *_env, jobject _obj, jfieldID _field, void *buffer)
 {
-    LOGE("Save Int");
     _env->SetIntField(_obj, _field, ((int32_t *)buffer)[0]);
     return ((uint8_t *)buffer) + 4;
 }
 
 static void * SF_SaveShort(JNIEnv *_env, jobject _obj, jfieldID _field, void *buffer)
 {
-    LOGE("Save Short");
     _env->SetShortField(_obj, _field, ((int16_t *)buffer)[0]);
     return ((uint8_t *)buffer) + 2;
 }
 
 static void * SF_SaveByte(JNIEnv *_env, jobject _obj, jfieldID _field, void *buffer)
 {
-    LOGE("Save Byte");
     _env->SetByteField(_obj, _field, ((int8_t *)buffer)[0]);
     return ((uint8_t *)buffer) + 1;
 }
 
 static void * SF_SaveFloat(JNIEnv *_env, jobject _obj, jfieldID _field, void *buffer)
 {
-    LOGE("Save Float");
     _env->SetFloatField(_obj, _field, ((float *)buffer)[0]);
     return ((uint8_t *)buffer) + 4;
 }
@@ -601,11 +597,8 @@
     void * buf = bufAlloc;
     rsAllocationRead(con, (RsAllocation)alloc, bufAlloc);
 
-    LOGE("size %i, ", tc->size);
-
     for (int ct=0; ct < tc->fieldCount; ct++) {
         const TypeFieldCache *tfc = &tc->fields[ct];
-        LOGE("ct=%i, buf=%p", ct, buf);
         buf = tfc->readPtr(_env, _o, tfc->field, buf);
     }
     free(bufAlloc);
diff --git a/include/ui/FramebufferNativeWindow.h b/include/ui/FramebufferNativeWindow.h
index 68144b5..8ea3ab9 100644
--- a/include/ui/FramebufferNativeWindow.h
+++ b/include/ui/FramebufferNativeWindow.h
@@ -54,6 +54,7 @@
 
     bool isUpdateOnDemand() const { return mUpdateOnDemand; }
     status_t setUpdateRectangle(const Rect& updateRect);
+    status_t compositionComplete();
     
 private:
     friend class LightRefBase<FramebufferNativeWindow>;    
diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java
new file mode 100644
index 0000000..28c2992
--- /dev/null
+++ b/keystore/java/android/security/Credentials.java
@@ -0,0 +1,98 @@
+/*
+ * 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.security;
+
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+import java.security.KeyPair;
+
+/**
+ * {@hide}
+ */
+public class Credentials {
+    private static final String LOGTAG = "Credentials";
+    private static final String UNLOCK_ACTION = "android.credentials.UNLOCK";
+    private static final String INSTALL_ACTION = "android.credentials.INSTALL";
+    private static Credentials singleton;
+
+    /** Key prefix for CA certificates. */
+    public static final String CA_CERTIFICATE = "CACERT_";
+
+    /** Key prefix for user certificates. */
+    public static final String USER_CERTIFICATE = "USRCERT_";
+
+    /** Key prefix for user private keys. */
+    public static final String USER_PRIVATE_KEY = "USRPKEY_";
+
+    /** Key prefix for VPN. */
+    public static final String VPN = "VPN_";
+
+    /** Key prefix for WIFI. */
+    public static final String WIFI = "WIFI_";
+
+    /** Data type for public keys. */
+    public static final String PUBLIC_KEY = "KEY";
+
+    /** Data type for private keys. */
+    public static final String PRIVATE_KEY = "PKEY";
+
+    /** Data type for certificates. */
+    public static final String CERTIFICATE = "CERT";
+
+    /** Data type for PKCS12. */
+    public static final String PKCS12 = "PKCS12";
+
+    public static Credentials getInstance() {
+        if (singleton == null) {
+            singleton = new Credentials();
+        }
+        return singleton;
+    }
+
+    public void unlock(Context context) {
+        try {
+            Intent intent = new Intent(UNLOCK_ACTION);
+            context.startActivity(intent);
+        } catch (ActivityNotFoundException e) {
+            Log.w(LOGTAG, e.toString());
+        }
+    }
+
+    public void install(Context context, KeyPair pair) {
+        try {
+            Intent intent = new Intent(INSTALL_ACTION);
+            intent.putExtra(PRIVATE_KEY, pair.getPrivate().getEncoded());
+            intent.putExtra(PUBLIC_KEY, pair.getPublic().getEncoded());
+            context.startActivity(intent);
+        } catch (ActivityNotFoundException e) {
+            Log.w(LOGTAG, e.toString());
+        }
+    }
+
+    public void install(Context context, String type, byte[] value) {
+        try {
+            Intent intent = new Intent(INSTALL_ACTION);
+            intent.putExtra(type, value);
+            context.startActivity(intent);
+        } catch (ActivityNotFoundException e) {
+            Log.w(LOGTAG, e.toString());
+        }
+    }
+}
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index add358b..e534447 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -307,6 +307,9 @@
     if (lStatus == NO_ERROR) {
         trackHandle = new TrackHandle(track);
     } else {
+        // remove local strong reference to Client before deleting the Track so that the Client
+        // destructor is called by the TrackBase destructor with mLock held
+        client.clear();
         track.clear();
     }
 
@@ -707,10 +710,10 @@
     }
 }
 
-void AudioFlinger::removeClient(pid_t pid)
+// removeClient_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::removeClient_l(pid_t pid)
 {
-    LOGV("removeClient() pid %d, tid %d, calling tid %d", pid, gettid(), IPCThreadState::self()->getCallingPid());
-    Mutex::Autolock _l(mLock);
+    LOGV("removeClient_l() pid %d, tid %d, calling tid %d", pid, gettid(), IPCThreadState::self()->getCallingPid());
     mClients.removeItem(pid);
 }
 
@@ -2078,7 +2081,10 @@
         }
     }
     mCblkMemory.clear();            // and free the shared memory
-    mClient.clear();
+    if (mClient != NULL) {
+        Mutex::Autolock _l(mClient->audioFlinger()->mLock);
+        mClient.clear();
+    }
 }
 
 void AudioFlinger::ThreadBase::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer)
@@ -2712,9 +2718,10 @@
     // 1 MB of address space is good for 32 tracks, 8 buffers each, 4 KB/buffer
 }
 
+// Client destructor must be called with AudioFlinger::mLock held
 AudioFlinger::Client::~Client()
 {
-    mAudioFlinger->removeClient(mPid);
+    mAudioFlinger->removeClient_l(mPid);
 }
 
 const sp<MemoryDealer>& AudioFlinger::Client::heap() const
@@ -2820,6 +2827,9 @@
                                                    format, channelCount, frameCount, flags);
     }
     if (recordTrack->getCblk() == NULL) {
+        // remove local strong reference to Client before deleting the RecordTrack so that the Client
+        // destructor is called by the TrackBase destructor with mLock held
+        client.clear();
         recordTrack.clear();
         lStatus = NO_MEMORY;
         goto Exit;
diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h
index 7a6641f..3699019 100644
--- a/libs/audioflinger/AudioFlinger.h
+++ b/libs/audioflinger/AudioFlinger.h
@@ -189,6 +189,8 @@
         virtual             ~Client();
         const sp<MemoryDealer>&     heap() const;
         pid_t               pid() const { return mPid; }
+        sp<AudioFlinger>    audioFlinger() { return mAudioFlinger; }
+
     private:
                             Client(const Client&);
                             Client& operator = (const Client&);
@@ -641,7 +643,7 @@
     friend class PlaybackThread::Track;
 
 
-                void        removeClient(pid_t pid);
+                void        removeClient_l(pid_t pid);
 
 
     // record thread
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
index d10076b..6dc3e8b 100644
--- a/libs/rs/rsScriptC_Lib.cpp
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -321,6 +321,16 @@
     return v * v;
 }
 
+static float SC_fracf(float v)
+{
+    return v - floorf(v);
+}
+
+static float SC_roundf(float v)
+{
+    return floorf(v + 0.4999999999);
+}
+
 static float SC_distf2(float x1, float y1, float x2, float y2)
 {
     float x = x2 - x1;
@@ -1014,8 +1024,12 @@
         "float", "(float, float)" },
     { "floorf", (void *)&floorf,
         "float", "(float)" },
+    { "fracf", (void *)&SC_fracf,
+        "float", "(float)" },
     { "ceilf", (void *)&ceilf,
         "float", "(float)" },
+    { "roundf", (void *)&SC_roundf,
+        "float", "(float)" },
     { "expf", (void *)&expf,
         "float", "(float)" },
     { "logf", (void *)&logf,
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index cc913cb..7bdf885 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -297,9 +297,9 @@
     return mPageFlipCount;
 }
 
-/*
- * "Flip" the front and back buffers.
- */
+status_t DisplayHardware::compositionComplete() const {
+    return mNativeWindow->compositionComplete();
+}
 
 void DisplayHardware::flip(const Region& dirty) const
 {
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
index 8972d51..b7f1cdb 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -80,6 +80,8 @@
     EGLDisplay getEGLDisplay() const { return mDisplay; }
     overlay_control_device_t* getOverlayEngine() const { return mOverlayEngine; }
     
+    status_t compositionComplete() const;
+    
     Rect bounds() const {
         return Rect(mWidth, mHeight);
     }
diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp
index 7387c85..8dfc2cf 100644
--- a/libs/surfaceflinger/Layer.cpp
+++ b/libs/surfaceflinger/Layer.cpp
@@ -176,7 +176,7 @@
                     // this failed, for instance, because we don't support
                     // NPOT.
                     // FIXME: do something!
-                    LOGD("layer=%p, glEGLImageTargetTexture2DOES(%d) "
+                    LOGD("layer=%p, glEGLImageTargetTexture2DOES(%p) "
                          "failed err=0x%04x",
                          this, mTextures[index].image, error);
                     mFlags &= ~DisplayHardware::DIRECT_TEXTURE;
@@ -256,11 +256,17 @@
         w = mWidth;
         h = mHeight;
         buffer = mBuffers[index];
+        
+        // destroy() could have been called before we get here, we log it
+        // because it's uncommon, and the code below should handle it
+        LOGW_IF(buffer==0, 
+                "mBuffers[%d] is null (mWidth=%d, mHeight=%d)",
+                index, w, h);
+        
         mBuffers[index].clear();
     }
 
-
-    if (buffer->getStrongCount() == 1) {
+    if (buffer!=0 && buffer->getStrongCount() == 1) {
         err = buffer->reallocate(w, h, mFormat, usage, mBufferFlags);
     } else {
         // here we have to reallocate a new buffer because we could have a
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index 31b5128c..e87b563 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -495,6 +495,9 @@
         // repaint the framebuffer (if needed)
         handleRepaint();
 
+        // inform the h/w that we're done compositing
+        hw.compositionComplete();
+
         // release the clients before we flip ('cause flip might block)
         unlockClients();
 
diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp
index 90b5163..fc2e2f6 100644
--- a/libs/ui/FramebufferNativeWindow.cpp
+++ b/libs/ui/FramebufferNativeWindow.cpp
@@ -158,6 +158,14 @@
     return fbDev->setUpdateRect(fbDev, r.left, r.top, r.width(), r.height());
 }
 
+status_t FramebufferNativeWindow::compositionComplete()
+{
+    if (fbDev->compositionComplete) {
+        return fbDev->compositionComplete(fbDev);
+    }
+    return INVALID_OPERATION;
+}
+
 int FramebufferNativeWindow::setSwapInterval(
         android_native_window_t* window, int interval) 
 {
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 73b6483..29409ab 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -63,12 +63,12 @@
 
     private String mFilename;
     private HashMap<String, String> mAttributes;
-    private boolean mHasThumbnail = false;
+    private boolean mHasThumbnail;
 
     // Because the underlying implementation (jhead) uses static variables,
     // there can only be one user at a time for the native functions (and
     // they cannot keep state in the native code across function calls). We
-    // use sLock the serialize the accesses.
+    // use sLock to serialize the accesses.
     private static Object sLock = new Object();
 
     /**
@@ -81,7 +81,7 @@
 
     /**
      * Returns the value of the specified tag or {@code null} if there
-     * is no such tag in the file.
+     * is no such tag in the JPEG file.
      *
      * @param tag the name of the tag.
      */
@@ -90,6 +90,24 @@
     }
 
     /**
+     * Returns the integer value of the specified tag. If there is no such tag
+     * in the JPEG file or the value cannot be parsed as integer, return
+     * @{code defaultValue}.
+     *
+     * @param tag the name of the tag.
+     * @param defaultValue the value to return if the tag is not available.
+     */
+    public int getAttributeInt(String tag, int defaultValue) {
+        String value = mAttributes.get(tag);
+        if (value == null) return defaultValue;
+        try {
+            return Integer.valueOf(value);
+        } catch (NumberFormatException ex) {
+            return defaultValue;
+        }
+    }
+
+    /**
      * Set the value of the specified tag.
      *
      * @param tag the name of the tag.
@@ -109,7 +127,7 @@
      * This function also initialize mHasThumbnail to indicate whether the
      * file has a thumbnail inside.
      */
-    private void loadAttributes() {
+    private void loadAttributes() throws IOException {
         // format of string passed from native C code:
         // "attrCnt attr1=valueLen value1attr2=value2Len value2..."
         // example:
@@ -153,9 +171,9 @@
     /**
      * Save the tag data into the JPEG file. This is expensive because it involves
      * copying all the JPG data from one file to another and deleting the old file
-     * and renaming the other. It's best to use {@link #setAttribute(String,String)} to set all
-     * attributes to write and make a single call rather than multiple calls for
-     * each attribute.
+     * and renaming the other. It's best to use {@link #setAttribute(String,String)}
+     * to set all attributes to write and make a single call rather than multiple
+     * calls for each attribute.
      */
     public void saveAttributes() throws IOException {
         // format of string passed to native C code:
@@ -195,6 +213,8 @@
 
     /**
      * Returns the thumbnail inside the JPEG file, or {@code null} if there is no thumbnail.
+     * The returned data is in JPEG format and can be decoded using
+     * {@link android.graphics.BitmapFactory#decodeByteArray(byte[],int,int)}
      */
     public byte[] getThumbnail() {
         synchronized (sLock) {
@@ -203,98 +223,23 @@
     }
 
     /**
-     * Returns a human-readable string describing the white balance value. Returns empty
-     * string if there is no white balance value or it is not recognized.
+     * Stores the latitude and longitude value in a float array. The first element is
+     * the latitude, and the second element is the longitude. Returns false if the
+     * Exif tags are not available.
      */
-    public String getWhiteBalanceString() {
-        String value = getAttribute(TAG_WHITE_BALANCE);
-        if (value == null) return "";
-
-        int whitebalance;
-        try {
-            whitebalance = Integer.parseInt(value);
-        } catch (NumberFormatException ex) {
-            return "";
-        }
-
-        switch (whitebalance) {
-            case WHITEBALANCE_AUTO:
-                return "Auto";
-            case WHITEBALANCE_MANUAL:
-                return "Manual";
-            default:
-                return "";
-        }
-    }
-
-    /**
-     * Returns a human-readable string describing the orientation value. Returns empty
-     * string if there is no orientation value or it it not recognized.
-     */
-    public String getOrientationString() {
-        // TODO: this function needs to be localized.
-        String value = getAttribute(TAG_ORIENTATION);
-        if (value == null) return "";
-
-        int orientation;
-        try {
-            orientation = Integer.parseInt(value);
-        } catch (NumberFormatException ex) {
-            return "";
-        }
-
-        String orientationString;
-        switch (orientation) {
-            case ORIENTATION_NORMAL:
-                orientationString = "Normal";
-                break;
-            case ORIENTATION_FLIP_HORIZONTAL:
-                orientationString = "Flipped horizontal";
-                break;
-            case ORIENTATION_ROTATE_180:
-                orientationString = "Rotated 180 degrees";
-                break;
-            case ORIENTATION_FLIP_VERTICAL:
-                orientationString = "Upside down mirror";
-                break;
-            case ORIENTATION_TRANSPOSE:
-                orientationString = "Transposed";
-                break;
-            case ORIENTATION_ROTATE_90:
-                orientationString = "Rotated 90 degrees";
-                break;
-            case ORIENTATION_TRANSVERSE:
-                orientationString = "Transversed";
-                break;
-            case ORIENTATION_ROTATE_270:
-                orientationString = "Rotated 270 degrees";
-                break;
-            default:
-                orientationString = "Undefined";
-                break;
-        }
-        return orientationString;
-    }
-
-    /**
-     * Returns the latitude and longitude value in a float array. The first element is
-     * the latitude, and the second element is the longitude.
-     */
-    public float[] getLatLong() {
+    public boolean getLatLong(float output[]) {
         String latValue = mAttributes.get(ExifInterface.TAG_GPS_LATITUDE);
         String latRef = mAttributes.get(ExifInterface.TAG_GPS_LATITUDE_REF);
         String lngValue = mAttributes.get(ExifInterface.TAG_GPS_LONGITUDE);
         String lngRef = mAttributes.get(ExifInterface.TAG_GPS_LONGITUDE_REF);
-        float[] latlng = null;
 
-        if (latValue != null && latRef != null
-                && lngValue != null && lngRef != null) {
-            latlng = new float[2];
-            latlng[0] = convertRationalLatLonToFloat(latValue, latRef);
-            latlng[1] = convertRationalLatLonToFloat(lngValue, lngRef);
+        if (latValue != null && latRef != null && lngValue != null && lngRef != null) {
+            output[0] = convertRationalLatLonToFloat(latValue, latRef);
+            output[1] = convertRationalLatLonToFloat(lngValue, lngRef);
+            return true;
+        } else {
+            return false;
         }
-
-        return latlng;
     }
 
     private static SimpleDateFormat sFormatter =
@@ -303,6 +248,7 @@
     /**
      * Returns number of milliseconds since Jan. 1, 1970, midnight GMT.
      * Returns -1 if the date time information if not available.
+     * @hide
      */
     public long getDateTime() {
         String dateTimeString = mAttributes.get(TAG_DATETIME);
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index d9127e7..37a3bd5 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -726,8 +726,8 @@
                     // exif is null
                 }
                 if (exif != null) {
-                    float[] latlng = exif.getLatLong();
-                    if (latlng != null) {
+                    float[] latlng = new float[2];
+                    if (exif.getLatLong(latlng)) {
                         values.put(Images.Media.LATITUDE, latlng[0]);
                         values.put(Images.Media.LONGITUDE, latlng[1]);
                     }
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
index ef211b3..9b7ff6c 100755
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
@@ -490,17 +490,17 @@
   
   //Streaming test files
   public static final String STREAM_H264_480_360_1411k = 
-      "http://sridharg.googlejunta.com/yslau/stress_media/h264_regular.mp4"; 
+      "http://75.17.48.204:10088/yslau/stress_media/h264_regular.mp4";
   public static final String STREAM_WMV = 
-      "http://sridharg.googlejunta.com/yslau/stress_media/bugs.wmv"; 
+      "http://75.17.48.204:10088/yslau/stress_media/bugs.wmv";
   public static final String STREAM_H263_176x144_325k = 
-      "http://sridharg.googlejunta.com/yslau/stress_media/h263_regular.3gp";
+      "http://75.17.48.204:10088/yslau/stress_media/h263_regular.3gp";
   public static final String STREAM_H264_352x288_1536k = 
-      "http://sridharg.googlejunta.com/yslau/stress_media/h264_highBitRate.mp4";
+      "http://75.17.48.204:10088/yslau/stress_media/h264_highBitRate.mp4";
   public static final String STREAM_MP3= 
-      "http://sridharg.googlejunta.com/yslau/stress_media/mp3_regular.mp3";
+      "http://75.17.48.204:10088/yslau/stress_media/mp3_regular.mp3";
   public static final String STREAM_MPEG4_QVGA_128k = 
-      "http://sridharg.googlejunta.com/yslau/stress_media/mpeg4_qvga_24fps.3gp";
+      "http://75.17.48.204:10088/yslau/stress_media/mpeg4_qvga_24fps.3gp";
   public static final int STREAM_H264_480_360_1411k_DURATION = 46000;
   public static final int VIDEO_H263_AAC_DURATION = 501000;
 }
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java
index 39846c6..4a4ad6f 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java
@@ -214,8 +214,10 @@
             Log.v(TAG, "before getduration");
             mOutputDuration = mediaPlayer.getDuration();
             Log.v(TAG, "get video dimension");
-            mOutputVideoHeight = CodecTest.videoHeight(outputFilePath);
-            mOutputVideoWidth = CodecTest.videoWidth(outputFilePath);
+            mOutputVideoHeight = mediaPlayer.getVideoHeight();
+            mOutputVideoWidth = mediaPlayer.getVideoWidth();
+            //mOutputVideoHeight = CodecTest.videoHeight(outputFilePath);
+            //mOutputVideoWidth = CodecTest.videoWidth(outputFilePath);
             mediaPlayer.release();    
         } catch (Exception e) {
             Log.v(TAG, e.toString());
@@ -321,10 +323,10 @@
             recordVideo(15, 352, 288, MediaRecorder.VideoEncoder.H263,
                     MediaRecorder.OutputFormat.THREE_GPP, 
                     MediaNames.RECORDED_PORTRAIT_H263, true);
-            videoRecordedResult = 
-                validateVideo(MediaNames.RECORDED_PORTRAIT_H263, 352, 288);
             mCamera.lock();
             mCamera.release();
+            videoRecordedResult =
+                validateVideo(MediaNames.RECORDED_PORTRAIT_H263, 352, 288);
         } catch (Exception e) {
             Log.v(TAG, e.toString());
         }
@@ -453,4 +455,3 @@
         }
     }
 }
-
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 408a4d2..63845e9 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -809,6 +809,8 @@
                     intent.putExtra(ConnectivityManager.
                             EXTRA_OTHER_NETWORK_INFO, switchTo);
                 } else {
+                    intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY,
+                            true);
                     newNet.reconnect();
                 }
             } else {
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 45e0ceb..323a11f 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -6376,7 +6376,10 @@
                 if (mBackupSettingsFilename.exists()) {
                     mBackupSettingsFilename.delete();
                 }
-                mSettingsFilename.renameTo(mBackupSettingsFilename);
+                if (!mSettingsFilename.renameTo(mBackupSettingsFilename)) {
+                    Log.w(TAG, "Unable to backup package manager settings, current changes will be lost at reboot");
+                    return;
+                }
             }
 
             mPastSignatures.clear();
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index d53f002..0cd5949 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -1384,12 +1384,18 @@
                     (mLowerWallpaperTarget == null && foundW.mAppToken != null)
                     ? foundW.mAppToken.animLayerAdjustment : 0;
             
+            final int maxLayer = mPolicy.getMaxWallpaperLayer()
+                    * TYPE_LAYER_MULTIPLIER
+                    + TYPE_LAYER_OFFSET;
+            
             // Now w is the window we are supposed to be behind...  but we
             // need to be sure to also be behind any of its attached windows,
-            // AND any starting window associated with it.
+            // AND any starting window associated with it, AND below the
+            // maximum layer the policy allows for wallpapers.
             while (foundI > 0) {
                 WindowState wb = (WindowState)localmWindows.get(foundI-1);
-                if (wb.mAttachedWindow != foundW &&
+                if (wb.mBaseLayer < maxLayer &&
+                        wb.mAttachedWindow != foundW &&
                         (wb.mAttrs.type != TYPE_APPLICATION_STARTING ||
                                 wb.mToken != foundW.mToken)) {
                     // This window is not related to the previous one in any
@@ -2266,6 +2272,12 @@
                             // Currently in a hide animation... turn this into
                             // an exit.
                             win.mExiting = true;
+                        } else if (win == mWallpaperTarget) {
+                            // If the wallpaper is currently behind this
+                            // window, we need to change both of them inside
+                            // of a transaction to avoid artifacts.
+                            win.mExiting = true;
+                            win.mAnimating = true;
                         } else {
                             if (mInputMethodWindow == win) {
                                 mInputMethodWindow = null;
@@ -3158,6 +3170,10 @@
                     return;
                 }
                 if (ent.array.getBoolean(
+                        com.android.internal.R.styleable.Window_windowIsFloating, false)) {
+                    return;
+                }
+                if (ent.array.getBoolean(
                         com.android.internal.R.styleable.Window_windowShowWallpaper, false)) {
                     return;
                 }
@@ -7087,8 +7103,8 @@
                     mAppToken.firstWindowDrawn = true;
                     
                     if (mAppToken.startingData != null) {
-                        if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Finish starting "
-                                + mToken
+                        if (DEBUG_STARTING_WINDOW || DEBUG_ANIM) Log.v(TAG,
+                                "Finish starting " + mToken
                                 + ": first real window is shown, no animation");
                         // If this initial window is animating, stop it -- we
                         // will do an animation to reveal it from behind the
@@ -7305,13 +7321,13 @@
                 // Compute the desired transformation.
                 tmpMatrix.setTranslate(frame.left, frame.top);
                 if (selfTransformation) {
-                    tmpMatrix.preConcat(mTransformation.getMatrix());
+                    tmpMatrix.postConcat(mTransformation.getMatrix());
                 }
                 if (attachedTransformation != null) {
-                    tmpMatrix.preConcat(attachedTransformation.getMatrix());
+                    tmpMatrix.postConcat(attachedTransformation.getMatrix());
                 }
                 if (appTransformation != null) {
-                    tmpMatrix.preConcat(appTransformation.getMatrix());
+                    tmpMatrix.postConcat(appTransformation.getMatrix());
                 }
 
                 // "convert" it into SurfaceFlinger's format
@@ -8928,11 +8944,14 @@
                                 wallpaperMayChange = true;
                             }
                         }
+                        boolean wasAnimating = w.mAnimating;
                         if (w.stepAnimationLocked(currentTime, dw, dh)) {
                             animating = true;
                             //w.dump("  ");
                         }
-
+                        if (wasAnimating && !w.mAnimating && mWallpaperTarget == w) {
+                            wallpaperMayChange = true;
+                        }
                         mPolicy.animatingWindowLw(w, attrs);
                     }
 
@@ -9269,6 +9288,7 @@
             boolean covered = false;
             boolean syswin = false;
             boolean backgroundFillerShown = false;
+            boolean forceHiding = false;
 
             final int N = mWindows.size();
             
@@ -9401,7 +9421,10 @@
                         }
                     }
 
-                    if (w.mAttachedHidden) {
+                    if ((forceHiding
+                            && attrs.type != WindowManager.LayoutParams.TYPE_STATUS_BAR
+                            && attrs.type != WindowManager.LayoutParams.TYPE_WALLPAPER)
+                            || w.mAttachedHidden) {
                         if (!w.mLastHidden) {
                             //dump();
                             w.mLastHidden = true;
@@ -9515,6 +9538,9 @@
                     }
 
                     if (displayed) {
+                        if (attrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD) {
+                            forceHiding = true;
+                        }
                         if (!covered) {
                             if (attrs.width == LayoutParams.FILL_PARENT
                                     && attrs.height == LayoutParams.FILL_PARENT) {
@@ -9597,7 +9623,7 @@
                         }
                         backgroundFillerShown = true;
                         mBackgroundFillerShown = true;
-                    } else if (canBeSeen && !obscured &&
+                    } else if (canBeSeen && !obscured && !forceHiding &&
                             (attrFlags&FLAG_BLUR_BEHIND|FLAG_DIM_BEHIND) != 0) {
                         if (localLOGV) Log.v(TAG, "Win " + w
                                 + ": blurring=" + blurring
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 1597270..4db5239 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -33,7 +33,6 @@
 import android.app.ApplicationErrorReport;
 import android.app.Dialog;
 import android.app.IActivityController;
-import android.app.IActivityManager;
 import android.app.IActivityWatcher;
 import android.app.IApplicationThread;
 import android.app.IInstrumentationWatcher;
@@ -53,6 +52,7 @@
 import android.content.IntentFilter;
 import android.content.IIntentReceiver;
 import android.content.IIntentSender;
+import android.content.IntentSender;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ConfigurationInfo;
@@ -3613,8 +3613,8 @@
         }
     }
 
-    public int startActivityPendingIntent(IApplicationThread caller,
-            PendingIntent intent, Intent fillInIntent, String resolvedType,
+    public int startActivityIntentSender(IApplicationThread caller,
+            IntentSender intent, Intent fillInIntent, String resolvedType,
             IBinder resultTo, String resultWho, int requestCode,
             int flagsMask, int flagsValues) {
         // Refuse possible leaked file descriptors
@@ -3628,8 +3628,15 @@
         }
         
         PendingIntentRecord pir = (PendingIntentRecord)sender;
-        if (pir.key.type != IActivityManager.INTENT_SENDER_ACTIVITY) {
-            return START_NOT_ACTIVITY;
+        
+        synchronized (this) {
+            // If this is coming from the currently resumed activity, it is
+            // effectively saying that app switches are allowed at this point.
+            if (mResumedActivity != null
+                    && mResumedActivity.info.applicationInfo.uid ==
+                            Binder.getCallingUid()) {
+                mAppSwitchesAllowedTime = 0;
+            }
         }
         
         return pir.sendInner(0, fillInIntent, resolvedType,
@@ -8424,6 +8431,13 @@
     }
 
     private ComponentName getErrorReportReceiver(ProcessRecord app) {
+        // check if error reporting is enabled in Gservices
+        int enabled = Settings.Gservices.getInt(mContext.getContentResolver(),
+                Settings.Gservices.SEND_ACTION_APP_ERROR, 0);
+        if (enabled == 0) {
+            return null;
+        }
+
         IPackageManager pm = ActivityThread.getPackageManager();
 
         try {
diff --git a/services/java/com/android/server/am/PendingIntentRecord.java b/services/java/com/android/server/am/PendingIntentRecord.java
index d994362..a753d05 100644
--- a/services/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/java/com/android/server/am/PendingIntentRecord.java
@@ -198,6 +198,7 @@
                 } else {
                     resolvedType = key.requestResolvedType;
                 }
+                flagsMask &= ~Intent.IMMUTABLE_FLAGS;
                 flagsValues &= flagsMask;
                 finalIntent.setFlags((finalIntent.getFlags()&~flagsMask) | flagsValues);
                 
diff --git a/telephony/java/android/telephony/cdma/CdmaCellLocation.java b/telephony/java/android/telephony/cdma/CdmaCellLocation.java
index b8778f8..676fba7 100644
--- a/telephony/java/android/telephony/cdma/CdmaCellLocation.java
+++ b/telephony/java/android/telephony/cdma/CdmaCellLocation.java
@@ -20,8 +20,7 @@
 import android.telephony.CellLocation;
 
 /**
- * Represents the cell location on a GSM phone.
- * @hide
+ * Represents the cell location on a CDMA phone.
  */
 public class CdmaCellLocation extends CellLocation {
     private int mBaseStationId = -1;
@@ -31,7 +30,8 @@
     private int mNetworkId = -1;
 
     /**
-     * Empty constructor.  Initializes the LAC and CID to -1.
+     * Empty constructor.
+     * Initializes the BID, SID, NID and base station latitude and longitude to -1.
      */
     public CdmaCellLocation() {
         this.mBaseStationId = -1;
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index 8d2785a..5581a24 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -127,7 +127,7 @@
 
     /** Retry configuration for secondary networks: 4 tries in 20 sec */
     protected static final String SECONDARY_DATA_RETRY_CONFIG =
-            "max_retries=3; 5000, 5000, 5000";
+            "max_retries=3, 5000, 5000, 5000";
 
     /** Slow poll when attempting connection recovery. */
     protected static final int POLL_NETSTAT_SLOW_MILLIS = 5000;
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java
index 0c94e6a..2f4d238 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java
@@ -492,6 +492,8 @@
 
         newParent = parentFromDCState(dc.state);
 
+        if (Phone.DEBUG_PHONE) log("parent= " +parent +", newParent= " + newParent);
+
         if (!equalsHandlesNulls(address, dc.number)) {
             if (Phone.DEBUG_PHONE) log("update: phone # changed!");
             address = dc.number;
@@ -509,7 +511,7 @@
             cnapName = dc.name;
         }
 
-        log("--dssds----"+cnapName);
+        if (Phone.DEBUG_PHONE) log("--dssds----"+cnapName);
         cnapNamePresentation = dc.namePresentation;
         numberPresentation = dc.numberPresentation;
 
@@ -529,9 +531,7 @@
         /** Some state-transition events */
 
         if (Phone.DEBUG_PHONE) log(
-                "update: parent=" + parent +
-                ", hasNewParent=" + (newParent != parent) +
-                ", wasConnectingInOrOut=" + wasConnectingInOrOut +
+                "Update, wasConnectingInOrOut=" + wasConnectingInOrOut +
                 ", wasHolding=" + wasHolding +
                 ", isConnectingInOrOut=" + isConnectingInOrOut() +
                 ", changed=" + changed);
@@ -860,10 +860,13 @@
         // Append the PW char
         ret = (isPause(c)) ? PhoneNumberUtils.PAUSE : PhoneNumberUtils.WAIT;
 
-        // if there is a PAUSE in at the beginning of PW character sequences, and this
-        // PW character sequences has more than 2 PAUSE and WAIT Characters,skip PAUSE,
-        // append WAIT.
-        if (isPause(c) && (nextNonPwCharIndex > (currPwIndex + 2))) {
+        // If the nextNonPwCharIndex is greater than currPwIndex + 1,
+        // it means the PW sequence contains not only P characters.
+        // Since for the sequence that only contains P character,
+        // the P character is handled one by one, the nextNonPwCharIndex
+        // equals to currPwIndex + 1.
+        // In this case, skip P, append W.
+        if (nextNonPwCharIndex > (currPwIndex + 1)) {
             ret = PhoneNumberUtils.WAIT;
         }
         return ret;
@@ -882,6 +885,11 @@
      *    and if there is any WAIT in PAUSE/WAIT sequence, treat them like WAIT.
      */
     public static String formatDialString(String phoneNumber) {
+        /**
+         * TODO(cleanup): This function should move to PhoneNumberUtils, and
+         * tests should be added.
+         */
+
         if (phoneNumber == null) {
             return null;
         }
@@ -901,9 +909,9 @@
                         char pC = findPOrWCharToAppend(phoneNumber, currIndex, nextIndex);
                         ret.append(pC);
                         // If PW char sequence has more than 2 PW characters,
-                        // skip to the last character since the sequence already be
+                        // skip to the last PW character since the sequence already be
                         // converted to WAIT character
-                        if (nextIndex > (currIndex + 2)) {
+                        if (nextIndex > (currIndex + 1)) {
                             currIndex = nextIndex - 1;
                         }
                     } else if (nextIndex == length) {
diff --git a/test-runner/android/test/mock/MockContext.java b/test-runner/android/test/mock/MockContext.java
index 9fb1e61..5368526 100644
--- a/test-runner/android/test/mock/MockContext.java
+++ b/test-runner/android/test/mock/MockContext.java
@@ -22,6 +22,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.BroadcastReceiver;
+import android.content.IntentSender;
 import android.content.ServiceConnection;
 import android.content.SharedPreferences;
 import android.content.pm.ApplicationInfo;
@@ -228,6 +229,13 @@
     }
 
     @Override
+    public void startIntentSender(IntentSender intent,
+            Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags)
+            throws IntentSender.SendIntentException {
+        throw new UnsupportedOperationException();
+    }
+    
+    @Override
     public void sendBroadcast(Intent intent) {
         throw new UnsupportedOperationException();
     }
diff --git a/tests/AndroidTests/Android.mk b/tests/AndroidTests/Android.mk
index f5e49d7..ced796a 100644
--- a/tests/AndroidTests/Android.mk
+++ b/tests/AndroidTests/Android.mk
@@ -8,7 +8,7 @@
 LOCAL_STATIC_JAVA_LIBRARIES := googlelogin-client
 
 # Resource unit tests use a private locale
-LOCAL_AAPT_FLAGS = -c xx_YY -c cs
+LOCAL_AAPT_FLAGS = -c xx_YY -c cs -c 160dpi -c 32dpi -c 240dpi
 
 LOCAL_SRC_FILES := \
 	$(call all-subdir-java-files) \
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
index f48c8db..4e7e925 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
@@ -27,6 +27,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.IntentSender;
 import android.content.ServiceConnection;
 import android.content.SharedPreferences;
 import android.content.pm.ApplicationInfo;
@@ -1124,6 +1125,13 @@
     }
 
     @Override
+    public void startIntentSender(IntentSender intent,
+            Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags)
+            throws IntentSender.SendIntentException {
+        // TODO Auto-generated method stub
+    }
+    
+    @Override
     public boolean startInstrumentation(ComponentName arg0, String arg1,
             Bundle arg2) {
         // TODO Auto-generated method stub