Merge change 25879 into eclair

* changes:
  Setting the default HTTP user agent at runtime init.
diff --git a/api/current.xml b/api/current.xml
index b38176d..68a1c76 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -2825,6 +2825,28 @@
  visibility="public"
 >
 </field>
+<field name="detailColumn"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843427"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="detailSocialSummary"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843428"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="dial"
  type="int"
  transient="false"
@@ -7522,6 +7544,17 @@
  visibility="public"
 >
 </field>
+<field name="summaryColumn"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843426"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="summaryOff"
  type="int"
  transient="false"
@@ -7841,6 +7874,28 @@
  visibility="public"
 >
 </field>
+<field name="textAppearanceSearchResultSubtitle"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843424"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="textAppearanceSearchResultTitle"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843425"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="textAppearanceSmall"
  type="int"
  transient="false"
@@ -31692,6 +31747,29 @@
 <parameter name="intent" type="android.content.Intent">
 </parameter>
 </method>
+<method name="sendStickyOrderedBroadcast"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+<parameter name="resultReceiver" type="android.content.BroadcastReceiver">
+</parameter>
+<parameter name="scheduler" type="android.os.Handler">
+</parameter>
+<parameter name="initialCode" type="int">
+</parameter>
+<parameter name="initialData" type="java.lang.String">
+</parameter>
+<parameter name="initialExtras" type="android.os.Bundle">
+</parameter>
+</method>
 <method name="setTheme"
  return="void"
  abstract="true"
@@ -33028,6 +33106,29 @@
 <parameter name="intent" type="android.content.Intent">
 </parameter>
 </method>
+<method name="sendStickyOrderedBroadcast"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+<parameter name="resultReceiver" type="android.content.BroadcastReceiver">
+</parameter>
+<parameter name="scheduler" type="android.os.Handler">
+</parameter>
+<parameter name="initialCode" type="int">
+</parameter>
+<parameter name="initialData" type="java.lang.String">
+</parameter>
+<parameter name="initialExtras" type="android.os.Bundle">
+</parameter>
+</method>
 <method name="setTheme"
  return="void"
  abstract="false"
@@ -35761,17 +35862,6 @@
  visibility="public"
 >
 </field>
-<field name="ACTION_REMOTE_INTENT"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;android.intent.action.REMOTE_INTENT&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="ACTION_RUN"
  type="java.lang.String"
  transient="false"
@@ -36684,6 +36774,17 @@
  visibility="public"
 >
 </field>
+<field name="FLAG_ACTIVITY_NO_ANIMATION"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="65536"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="FLAG_ACTIVITY_NO_HISTORY"
  type="int"
  transient="false"
@@ -36805,6 +36906,17 @@
  visibility="public"
 >
 </field>
+<field name="METADATA_DOCK_HOME"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.dock_home&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="URI_INTENT_SCHEME"
  type="int"
  transient="false"
@@ -61078,6 +61190,17 @@
  visibility="public"
 >
 </field>
+<field name="YCbCr_422_I"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="20"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="YCbCr_422_SP"
  type="int"
  transient="false"
@@ -67260,6 +67383,17 @@
  visibility="public"
 >
 </method>
+<method name="lock"
+ return="void"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="open"
  return="android.hardware.Camera"
  abstract="false"
@@ -67420,6 +67554,17 @@
 <parameter name="jpeg" type="android.hardware.Camera.PictureCallback">
 </parameter>
 </method>
+<method name="unlock"
+ return="void"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <field name="CAMERA_ERROR_SERVER_DIED"
  type="int"
  transient="false"
@@ -67554,6 +67699,17 @@
  visibility="public"
 >
 </method>
+<method name="getFocusMode"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getInt"
  return="int"
  abstract="false"
@@ -67699,6 +67855,17 @@
  visibility="public"
 >
 </method>
+<method name="getSupportedFocusModes"
+ return="java.util.List&lt;java.lang.String&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getSupportedPictureFormats"
  return="java.util.List&lt;java.lang.Integer&gt;"
  abstract="false"
@@ -67880,6 +68047,19 @@
 <parameter name="value" type="java.lang.String">
 </parameter>
 </method>
+<method name="setFocusMode"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="java.lang.String">
+</parameter>
+</method>
 <method name="setGpsAltitude"
  return="void"
  abstract="false"
@@ -68281,6 +68461,61 @@
  visibility="public"
 >
 </field>
+<field name="FLASH_MODE_VIDEO_LIGHT"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;video-light&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FOCUS_MODE_AUTO"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;auto&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FOCUS_MODE_FIXED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;fixed&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FOCUS_MODE_INFINITY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;infinity&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FOCUS_MODE_MACRO"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;macro&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="SCENE_MODE_ACTION"
  type="java.lang.String"
  transient="false"
@@ -98695,6 +98930,116 @@
  visibility="public"
 >
 </field>
+<field name="EXTRA_HEALTH"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;health&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_ICON_SMALL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;icon-small&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_LEVEL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;level&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_PLUGGED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;plugged&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_PRESENT"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;present&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_SCALE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;scale&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_STATUS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;status&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_TECHNOLOGY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;technology&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_TEMPERATURE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;temperature&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_VOLTAGE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;voltage&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 </class>
 <class name="Binder"
  extends="java.lang.Object"
@@ -126684,6 +127029,29 @@
 <parameter name="intent" type="android.content.Intent">
 </parameter>
 </method>
+<method name="sendStickyOrderedBroadcast"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="intent" type="android.content.Intent">
+</parameter>
+<parameter name="resultReceiver" type="android.content.BroadcastReceiver">
+</parameter>
+<parameter name="scheduler" type="android.os.Handler">
+</parameter>
+<parameter name="initialCode" type="int">
+</parameter>
+<parameter name="initialData" type="java.lang.String">
+</parameter>
+<parameter name="initialExtras" type="android.os.Bundle">
+</parameter>
+</method>
 <method name="setTheme"
  return="void"
  abstract="false"
@@ -134507,6 +134875,21 @@
 <parameter name="addr" type="int">
 </parameter>
 </method>
+<method name="formatShortFileSize"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="number" type="long">
+</parameter>
+</method>
 </class>
 <class name="Time"
  extends="java.lang.Object"
@@ -160056,6 +160439,17 @@
  visibility="public"
 >
 </field>
+<field name="FLAG_DISMISS_KEYGUARD"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4194304"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="FLAG_DITHER"
  type="int"
  transient="false"
diff --git a/cmds/keystore/Android.mk b/cmds/keystore/Android.mk
index 8804636..15a199f 100644
--- a/cmds/keystore/Android.mk
+++ b/cmds/keystore/Android.mk
@@ -1,22 +1,36 @@
+#
+# 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.
+#
+
 ifneq ($(TARGET_SIMULATOR),true)
 
 LOCAL_PATH:= $(call my-dir)
+
 include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-    netkeystore.c netkeystore_main.c keymgmt.c
-
-LOCAL_C_INCLUDES := \
-    $(call include-path-for, system-core)/cutils \
-    external/openssl/include
-
-LOCAL_SHARED_LIBRARIES := \
-    libcutils libssl
-
-LOCAL_STATIC_LIBRARIES :=
-
+LOCAL_SRC_FILES := keystore.c
+LOCAL_C_INCLUDES := external/openssl/include
+LOCAL_SHARED_LIBRARIES := libcutils libcrypto
 LOCAL_MODULE:= keystore
-
 include $(BUILD_EXECUTABLE)
 
-endif # !simulator))
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := keystore_cli.c
+LOCAL_C_INCLUDES := external/openssl/include
+LOCAL_SHARED_LIBRARIES := libcutils libcrypto
+LOCAL_MODULE:= keystore_cli
+LOCAL_MODULE_TAGS := debug
+include $(BUILD_EXECUTABLE)
+
+endif
diff --git a/cmds/keystore/keystore.c b/cmds/keystore/keystore.c
index 2bcba97..ba74c78 100644
--- a/cmds/keystore/keystore.c
+++ b/cmds/keystore/keystore.c
@@ -125,6 +125,12 @@
     return length;
 }
 
+static int recv_end_of_file()
+{
+    uint8_t byte;
+    return recv(the_socket, &byte, 1, 0) == 0;
+}
+
 static void send_code(int8_t code)
 {
     send(the_socket, &code, 1, 0);
@@ -217,8 +223,10 @@
 /* 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. */
+ * fixed and defined in a table. If the return value of an action is positive,
+ * it will be treated as a response code and transmitted to the client. 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
@@ -283,7 +291,7 @@
     return NO_ERROR;
 }
 
-static int8_t scan()
+static int8_t saw()
 {
     DIR *dir = opendir(".");
     struct dirent *file;
@@ -321,12 +329,10 @@
         return SYSTEM_ERROR;
     }
     while ((file = readdir(dir)) != NULL) {
-        if (strcmp(".", file->d_name) || strcmp("..", file->d_name)) {
-            unlink(file->d_name);
-        }
+        unlink(file->d_name);
     }
     closedir(dir);
-    return UNINITIALIZED;
+    return NO_ERROR;
 }
 
 #define MASTER_KEY_FILE ".masterkey"
@@ -358,7 +364,8 @@
         }
         if (n != NO_ERROR || blob.length != MASTER_KEY_SIZE) {
             if (retry <= 0) {
-                return reset();
+                reset();
+                return UNINITIALIZED;
             }
             return WRONG_PASSWORD + --retry;
         }
@@ -387,7 +394,7 @@
     memset(&encryption_key, 0, sizeof(encryption_key));
     memset(&decryption_key, 0, sizeof(decryption_key));
     state = LOCKED;
-    return LOCKED;
+    return NO_ERROR;
 }
 
 static int8_t unlock()
@@ -404,7 +411,7 @@
     INSERT   =   4,
     DELETE   =   8,
     EXIST    =  16,
-    SCAN     =  32,
+    SAW      =  32,
     RESET    =  64,
     PASSWORD = 128,
     LOCK     = 256,
@@ -421,9 +428,9 @@
     {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}},
+    {delete,   'd', 0,        DELETE,   {KEY_SIZE}},
+    {exist,    'e', 0,        EXIST,    {KEY_SIZE}},
+    {saw,      's', 0,        SAW,      {KEY_SIZE}},
     {reset,    'r', 0,        RESET,    {0}},
     {password, 'p', 0,        PASSWORD, {PASSWORD_SIZE, PASSWORD_SIZE}},
     {lock,     'l', NO_ERROR, LOCK,     {0}},
@@ -439,7 +446,7 @@
     {AID_SYSTEM,   0,          ~GET},
     {AID_VPN,      AID_SYSTEM, GET},
     {AID_WIFI,     AID_SYSTEM, GET},
-    {0,            0,          TEST | GET | INSERT | DELETE | EXIST | SCAN},
+    {0,            0,          TEST | GET | INSERT | DELETE | EXIST | SAW},
 };
 
 static int8_t process(int8_t code) {
@@ -471,6 +478,9 @@
             return PROTOCOL_ERROR;
         }
     }
+    if (!recv_end_of_file()) {
+        return PROTOCOL_ERROR;
+    }
     return action->run();
 }
 
diff --git a/cmds/keystore/keystore_cli.c b/cmds/keystore/keystore_cli.c
index b0b76ff..e8afb5a 100644
--- a/cmds/keystore/keystore_cli.c
+++ b/cmds/keystore/keystore_cli.c
@@ -53,8 +53,8 @@
         return 0;
     }
 
-    sock = socket_local_client("keystore",
-            ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
+    sock = socket_local_client("keystore", ANDROID_SOCKET_NAMESPACE_RESERVED,
+                               SOCK_STREAM);
     if (sock == -1) {
         puts("Failed to connect");
         return 1;
diff --git a/cmds/keystore/keystore_get.h b/cmds/keystore/keystore_get.h
index 7665e81..0e7e1ae 100644
--- a/cmds/keystore/keystore_get.h
+++ b/cmds/keystore/keystore_get.h
@@ -1,53 +1,69 @@
 /*
-**
-** 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.
-*/
+ * 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_GET_H__
 #define __KEYSTORE_GET_H__
 
 #include <stdio.h>
-#include <stdlib.h>
+#include <stdint.h>
 #include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
 
-#include "certtool.h"
+#include <cutils/sockets.h>
 
-/* This function is provided to native components to get values from keystore.
- * Users are required to link against libcutils. If something goes wrong, NULL
- * is returned. Otherwise it returns the value in dynamically allocated memory
- * and sets the size if the pointer is not NULL. One can release the memory by
- * calling free(). */
-static char *keystore_get(const char *key, int *size)
+#define KEYSTORE_MESSAGE_SIZE 65535
+
+/* This function is provided for native components to get values from keystore.
+ * Users are required to link against libcutils. The lengths of keys and values
+ * are limited to KEYSTORE_MESSAGE_SIZE. This function returns the length of
+ * the requested value or -1 if something goes wrong. */
+static int keystore_get(const char *key, char *value)
 {
-    char buffer[MAX_KEY_VALUE_LENGTH];
-    char *value;
-    int length;
+    int length = strlen(key);
+    uint8_t bytes[2] = {length >> 8, length};
+    uint8_t code = 'g';
+    int sock;
 
-    if (get_cert(key, (unsigned char *)buffer, &length) != 0) {
-        return NULL;
+    if (length > KEYSTORE_MESSAGE_SIZE) {
+        return -1;
     }
-    value = malloc(length + 1);
-    if (!value) {
-        return NULL;
+    sock = socket_local_client("keystore", ANDROID_SOCKET_NAMESPACE_RESERVED,
+                               SOCK_STREAM);
+    if (sock == -1) {
+        return -1;
     }
-    memcpy(value, buffer, length);
-    value[length] = 0;
-    if (size) {
-        *size = length;
+    if (send(sock, &code, 1, 0) == 1 && send(sock, bytes, 2, 0) == 2 &&
+        send(sock, key, length, 0) == length && shutdown(sock, SHUT_WR) == 0 &&
+        recv(sock, &code, 1, 0) == 1 && code == /* NO_ERROR */ 1 &&
+        recv(sock, &bytes[0], 1, 0) == 1 && recv(sock, &bytes[1], 1, 0) == 1) {
+        int offset = 0;
+        length = bytes[0] << 8 | bytes[1];
+        while (offset < length) {
+            int n = recv(sock, &value[offset], length - offset, 0);
+            if (n <= 0) {
+                length = -1;
+                break;
+            }
+            offset += n;
+        }
     }
-    return value;
+    close(sock);
+    return length;
 }
 
 #endif
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index a86fe90..4561899 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -790,8 +790,8 @@
      * @see #onPostCreate
      */
     protected void onCreate(Bundle savedInstanceState) {
-        mVisibleFromClient = mWindow.getWindowStyle().getBoolean(
-                com.android.internal.R.styleable.Window_windowNoDisplay, true);
+        mVisibleFromClient = !mWindow.getWindowStyle().getBoolean(
+                com.android.internal.R.styleable.Window_windowNoDisplay, false);
         mCalled = true;
     }
 
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 8142d1a..6acd665 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1765,6 +1765,7 @@
         public static final int CREATE_BACKUP_AGENT     = 128;
         public static final int DESTROY_BACKUP_AGENT    = 129;
         public static final int SUICIDE                 = 130;
+        public static final int REMOVE_PROVIDER         = 131;
         String codeToString(int code) {
             if (localLOGV) {
                 switch (code) {
@@ -1799,6 +1800,7 @@
                     case CREATE_BACKUP_AGENT: return "CREATE_BACKUP_AGENT";
                     case DESTROY_BACKUP_AGENT: return "DESTROY_BACKUP_AGENT";
                     case SUICIDE: return "SUICIDE";
+                    case REMOVE_PROVIDER: return "REMOVE_PROVIDER";
                 }
             }
             return "(unknown)";
@@ -1911,9 +1913,10 @@
                     handleDestroyBackupAgent((CreateBackupAgentData)msg.obj);
                     break;
                 case SUICIDE:
-                    {
-                        Process.killProcess(Process.myPid());
-                    }
+                    Process.killProcess(Process.myPid());
+                    break;
+                case REMOVE_PROVIDER:
+                    completeRemoveProvider((IContentProvider)msg.obj);
                     break;
             }
         }
@@ -4029,15 +4032,28 @@
             } else {
                 prc.count--;
                 if(prc.count == 0) {
-                    mProviderRefCountMap.remove(jBinder);
-                    //invoke removeProvider to dereference provider
-                    removeProviderLocked(provider);
+                    // Schedule the actual remove asynchronously, since we
+                    // don't know the context this will be called in.
+                    Message msg = mH.obtainMessage(H.REMOVE_PROVIDER, provider);
+                    mH.sendMessage(msg);
                 } //end if
             } //end else
         } //end synchronized
         return true;
     }
 
+    final void completeRemoveProvider(IContentProvider provider) {
+        IBinder jBinder = provider.asBinder();
+        synchronized(mProviderMap) {
+            ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
+            if(prc != null && prc.count == 0) {
+                mProviderRefCountMap.remove(jBinder);
+                //invoke removeProvider to dereference provider
+                removeProviderLocked(provider);
+            }
+        }
+    }
+    
     public final void removeProviderLocked(IContentProvider provider) {
         if (provider == null) {
             return;
diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java
index dc8d873..afafe64 100644
--- a/core/java/android/app/ApplicationContext.java
+++ b/core/java/android/app/ApplicationContext.java
@@ -659,6 +659,38 @@
     }
 
     @Override
+    public void sendStickyOrderedBroadcast(Intent intent,
+            BroadcastReceiver resultReceiver,
+            Handler scheduler, int initialCode, String initialData,
+            Bundle initialExtras) {
+        IIntentReceiver rd = null;
+        if (resultReceiver != null) {
+            if (mPackageInfo != null) {
+                if (scheduler == null) {
+                    scheduler = mMainThread.getHandler();
+                }
+                rd = mPackageInfo.getReceiverDispatcher(
+                    resultReceiver, getOuterContext(), scheduler,
+                    mMainThread.getInstrumentation(), false);
+            } else {
+                if (scheduler == null) {
+                    scheduler = mMainThread.getHandler();
+                }
+                rd = new ActivityThread.PackageInfo.ReceiverDispatcher(
+                        resultReceiver, getOuterContext(), scheduler, null, false).getIIntentReceiver();
+            }
+        }
+        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
+        try {
+            ActivityManagerNative.getDefault().broadcastIntent(
+                mMainThread.getApplicationThread(), intent, resolvedType, rd,
+                initialCode, initialData, initialExtras, null,
+                true, true);
+        } catch (RemoteException e) {
+        }
+    }
+
+    @Override
     public void removeStickyBroadcast(Intent intent) {
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
         if (resolvedType != null) {
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index d05c9ab..a2c95f4 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -736,7 +736,8 @@
             return false;
         }
 
-        if (keyCode == KeyEvent.KEYCODE_SEARCH) {
+        if (keyCode == KeyEvent.KEYCODE_SEARCH && event.getRepeatCount() == 0) {
+            event.startTracking();
             // Consume search key for later use.
             return true;
         }
@@ -1143,7 +1144,7 @@
         String query = mSearchAutoComplete.getText().toString();
         String action = mGlobalSearchMode ? Intent.ACTION_WEB_SEARCH : Intent.ACTION_SEARCH;
         Intent intent = createIntent(action, null, null, query, null,
-                actionKey, actionMsg);
+                actionKey, actionMsg, null);
         // Allow GlobalSearch to log and create shortcut for searches launched by
         // the search button, enter key or an action key.
         if (mGlobalSearchMode) {
@@ -1181,7 +1182,7 @@
             // report back about the click
             if (mGlobalSearchMode) {
                 // in global search mode, do it via cursor
-                mSuggestionsAdapter.callCursorOnClick(c, position);
+                mSuggestionsAdapter.callCursorOnClick(c, position, actionKey, actionMsg);
             } else if (intent != null
                     && mPreviousComponents != null
                     && !mPreviousComponents.isEmpty()) {
@@ -1218,7 +1219,7 @@
         cv.put(SearchManager.SUGGEST_COLUMN_INTENT_ACTION, intent.getAction());
         cv.put(SearchManager.SUGGEST_COLUMN_INTENT_DATA, intent.getDataString());
         cv.put(SearchManager.SUGGEST_COLUMN_INTENT_COMPONENT_NAME,
-                        intent.getStringExtra(SearchManager.COMPONENT_NAME_KEY));
+                intent.getComponent().flattenToShortString());
 
         // ensure the icons will work for global search
         cv.put(SearchManager.SUGGEST_COLUMN_ICON_1,
@@ -1578,9 +1579,10 @@
 
             String query = getColumnString(c, SearchManager.SUGGEST_COLUMN_QUERY);
             String extraData = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA);
+            String mode = mGlobalSearchMode ? SearchManager.MODE_GLOBAL_SEARCH_SUGGESTION : null;
 
             return createIntent(action, dataUri, extraData, query, componentName, actionKey,
-                    actionMsg);
+                    actionMsg, mode);
         } catch (RuntimeException e ) {
             int rowNum;
             try {                       // be really paranoid now
@@ -1606,13 +1608,18 @@
      *        or {@link KeyEvent#KEYCODE_UNKNOWN} if none.
      * @param actionMsg The message for the action key that was pressed,
      *        or <code>null</code> if none.
+     * @param mode The search mode, one of the acceptable values for
+     *             {@link SearchManager#SEARCH_MODE}, or {@code null}.
      * @return The intent.
      */
     private Intent createIntent(String action, Uri data, String extraData, String query,
-            String componentName, int actionKey, String actionMsg) {
+            String componentName, int actionKey, String actionMsg, String mode) {
         // Now build the Intent
         Intent intent = new Intent(action);
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        // We need CLEAR_TOP to avoid reusing an old task that has other activities
+        // on top of the one we want.
+        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
         if (data != null) {
             intent.setData(data);
         }
@@ -1633,6 +1640,9 @@
             intent.putExtra(SearchManager.ACTION_KEY, actionKey);
             intent.putExtra(SearchManager.ACTION_MSG, actionMsg);
         }
+        if (mode != null) {
+            intent.putExtra(SearchManager.SEARCH_MODE, mode);
+        }
         // Only allow 3rd-party intents from GlobalSearch
         if (!mGlobalSearchMode) {
             intent.setComponent(mSearchable.getSearchActivity());
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 3a14f6f..f0876f4 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -1289,6 +1289,25 @@
     public final static String SOURCE = "source";
 
     /**
+     * Intent extra data key: Use {@link android.content.Intent#getBundleExtra
+     * content.Intent.getBundleExtra(SEARCH_MODE)} to get the search mode used
+     * to launch the intent.
+     * The only current value for this is {@link #MODE_GLOBAL_SEARCH_SUGGESTION}.
+     *
+     * @hide
+     */
+    public final static String SEARCH_MODE = "search_mode";
+
+    /**
+     * Value for the {@link #SEARCH_MODE} key.
+     * This is used if the intent was launched by clicking a suggestion in global search
+     * mode (Quick Search Box).
+     *
+     * @hide
+     */
+    public static final String MODE_GLOBAL_SEARCH_SUGGESTION = "global_search_suggestion";
+
+    /**
      * Intent extra data key: Use this key with Intent.ACTION_SEARCH and
      * {@link android.content.Intent#getIntExtra content.Intent.getIntExtra()}
      * to obtain the keycode that the user used to trigger this query.  It will be zero if the
@@ -1343,6 +1362,10 @@
                 = "DialogCursorProtocol.CLICK.sendPosition";
         public final static String CLICK_SEND_MAX_DISPLAY_POS
                 = "DialogCursorProtocol.CLICK.sendDisplayPosition";
+        public final static String CLICK_SEND_ACTION_KEY
+                = "DialogCursorProtocol.CLICK.sendActionKey";
+        public final static String CLICK_SEND_ACTION_MSG
+                = "DialogCursorProtocol.CLICK.sendActionMsg";
         public final static String CLICK_RECEIVE_SELECTED_POS
                 = "DialogCursorProtocol.CLICK.receiveSelectedPosition";
 
diff --git a/core/java/android/app/SuggestionsAdapter.java b/core/java/android/app/SuggestionsAdapter.java
index 4f9531e..9234a9c 100644
--- a/core/java/android/app/SuggestionsAdapter.java
+++ b/core/java/android/app/SuggestionsAdapter.java
@@ -26,7 +26,6 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
 import android.database.Cursor;
-import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.StateListDrawable;
@@ -37,6 +36,7 @@
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.SparseArray;
+import android.view.KeyEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.Filter;
@@ -47,7 +47,6 @@
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.List;
 import java.util.WeakHashMap;
 
 /**
@@ -290,12 +289,16 @@
      * @param cursor The cursor
      * @param position The position that was clicked.
      */
-    void callCursorOnClick(Cursor cursor, int position) {
+    void callCursorOnClick(Cursor cursor, int position, int actionKey, String actionMsg) {
         if (!mGlobalSearchMode) return;
-        final Bundle request = new Bundle(3);
+        final Bundle request = new Bundle(5);
         request.putInt(DialogCursorProtocol.METHOD, DialogCursorProtocol.CLICK);
         request.putInt(DialogCursorProtocol.CLICK_SEND_POSITION, position);
         request.putInt(DialogCursorProtocol.CLICK_SEND_MAX_DISPLAY_POS, mMaxDisplayed);
+        if (actionKey != KeyEvent.KEYCODE_UNKNOWN) {
+            request.putInt(DialogCursorProtocol.CLICK_SEND_ACTION_KEY, actionKey);
+            request.putString(DialogCursorProtocol.CLICK_SEND_ACTION_MSG, actionMsg);
+        }
         final Bundle response = cursor.respond(request);
         mMaxDisplayed = -1;
         mListItemToSelect = response.getInt(
@@ -569,69 +572,91 @@
         if (drawableId == null || drawableId.length() == 0 || "0".equals(drawableId)) {
             return null;
         }
-
-        // First, check the cache.
-        Drawable.ConstantState cached = mOutsideDrawablesCache.get(drawableId);
-        if (cached != null) {
-            if (DBG) Log.d(LOG_TAG, "Found icon in cache: " + drawableId);
-            return cached.newDrawable(mProviderContext.getResources());
-        }
-
-        Drawable drawable = null;
         try {
-            // Not cached, try using it as a plain resource ID in the provider's context.
+            // First, see if it's just an integer
             int resourceId = Integer.parseInt(drawableId);
+            // It's an int, look for it in the cache
+            String drawableUri = ContentResolver.SCHEME_ANDROID_RESOURCE
+                    + "://" + mProviderContext.getPackageName() + "/" + resourceId;
+            // Must use URI as cache key, since ints are app-specific
+            Drawable drawable = checkIconCache(drawableUri);
+            if (drawable != null) {
+                return drawable;
+            }
+            // Not cached, find it by resource ID
             drawable = mProviderContext.getResources().getDrawable(resourceId);
+            // Stick it in the cache, using the URI as key
+            storeInIconCache(drawableUri, drawable);
+            return drawable;
         } catch (NumberFormatException nfe) {
-            // The id was not an integer resource id, use it as a URI
-            try {
-                Uri uri = Uri.parse(drawableId);
-                String scheme = uri.getScheme();
-                if (ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)) {
-                    // Load drawables through Resources, to get the source density information
-                    OpenResourceIdResult r =
-                            mProviderContext.getContentResolver().getResourceId(uri);
+            // It's not an integer, use it as a URI
+            Drawable drawable = checkIconCache(drawableId);
+            if (drawable != null) {
+                return drawable;
+            }
+            Uri uri = Uri.parse(drawableId);
+            drawable = getDrawable(uri);
+            storeInIconCache(drawableId, drawable);
+            return drawable;
+        } catch (Resources.NotFoundException nfe) {
+            // It was an integer, but it couldn't be found, bail out
+            Log.w(LOG_TAG, "Icon resource not found: " + drawableId);
+            return null;
+        }
+    }
+
+    /**
+     * Gets a drawable by URI, without using the cache.
+     *
+     * @return A drawable, or {@code null} if the drawable could not be loaded.
+     */
+    private Drawable getDrawable(Uri uri) {
+        try {
+            String scheme = uri.getScheme();
+            if (ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)) {
+                // Load drawables through Resources, to get the source density information
+                OpenResourceIdResult r =
+                    mProviderContext.getContentResolver().getResourceId(uri);
+                try {
+                    return r.r.getDrawable(r.id);
+                } catch (Resources.NotFoundException ex) {
+                    throw new FileNotFoundException("Resource does not exist: " + uri);
+                }
+            } else {
+                // Let the ContentResolver handle content and file URIs.
+                InputStream stream = mProviderContext.getContentResolver().openInputStream(uri);
+                if (stream == null) {
+                    throw new FileNotFoundException("Failed to open " + uri);
+                }
+                try {
+                    return Drawable.createFromStream(stream, null);
+                } finally {
                     try {
-                        drawable = r.r.getDrawable(r.id);
-                    } catch (Resources.NotFoundException ex) {
-                        throw new FileNotFoundException("Resource does not exist: " + uri);
-                    }
-                } else {
-                    // Let the ContentResolver handle content and file URIs.
-                    InputStream stream = mProviderContext.getContentResolver().openInputStream(uri);
-                    if (stream == null) {
-                        throw new FileNotFoundException("Failed to open " + uri);
-                    }
-                    try {
-                        drawable = Drawable.createFromStream(stream, null);
-                    } finally {
-                        try {
-                            stream.close();
-                        } catch (IOException ex) {
-                            Log.e(LOG_TAG, "Error closing icon stream for " + uri, ex);
-                        }
+                        stream.close();
+                    } catch (IOException ex) {
+                        Log.e(LOG_TAG, "Error closing icon stream for " + uri, ex);
                     }
                 }
-            } catch (FileNotFoundException fnfe) {
-                Log.w(LOG_TAG, "Icon not found: " + drawableId + ", " + fnfe.getMessage());
-                // drawable = null;
             }
-        } catch (Resources.NotFoundException nfe) {
-            Log.w(LOG_TAG, "Icon resource not found: " + drawableId);
-            // drawable = null;
+        } catch (FileNotFoundException fnfe) {
+            Log.w(LOG_TAG, "Icon not found: " + uri + ", " + fnfe.getMessage());
+            return null;
         }
+    }
 
-        if (drawable == null) {
-            if (DBG) Log.d(LOG_TAG, "Didn't find icon: " + drawableId);
-        } else {
-            if (DBG) {
-                Log.d(LOG_TAG, "Found icon: " + drawableId);
-            }
-            // Cache it so we don't do this lookup again
-            mOutsideDrawablesCache.put(drawableId, drawable.getConstantState());
+    private Drawable checkIconCache(String resourceUri) {
+        Drawable.ConstantState cached = mOutsideDrawablesCache.get(resourceUri);
+        if (cached == null) {
+            return null;
         }
+        if (DBG) Log.d(LOG_TAG, "Found icon in cache: " + resourceUri);
+        return cached.newDrawable();
+    }
 
-        return drawable;
+    private void storeInIconCache(String resourceUri, Drawable drawable) {
+        if (drawable != null) {
+            mOutsideDrawablesCache.put(resourceUri, drawable.getConstantState());
+        }
     }
 
     /**
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/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index f81ba73..b52a822 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -28,6 +28,7 @@
 
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
+import java.util.UUID;
 
 /**
  * Represents a remote Bluetooth device.
@@ -226,6 +227,20 @@
     public static final String EXTRA_PASSKEY = "android.bluetooth.device.extra.PASSKEY";
 
     /**
+     * Broadcast Action: This intent is used to broadcast the {@link UUID}
+     * wrapped as a {@link ParcelUuid} of the remote device after it has been
+     * fetched. This intent is sent only when the UUIDs of the remote device
+     * are requested to be fetched using Service Discovery Protocol
+     * <p> Always contains the extra field {@link #EXTRA_DEVICE}
+     * <p> Always contains the extra filed {@link #EXTRA_UUID}
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_UUID =
+            "android.bleutooth.device.action.UUID";
+
+    /**
      * Broadcast Action: Indicates a failure to retrieve the name of a remote
      * device.
      * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
@@ -292,6 +307,15 @@
      * @hide */
     public static final int PAIRING_VARIANT_DISPLAY_PASSKEY = 4;
 
+    /**
+     * Used as an extra field in {@link #ACTION_UUID} intents,
+     * Contains the {@link ParcelUuid}s of the remote device which is a parcelable
+     * version of {@link UUID}.
+     * @hide
+     */
+    public static final String EXTRA_UUID = "android.bluetooth.device.extra.UUID";
+
+
     private static IBluetooth sService;  /* Guarenteed constant after first object constructed */
 
     private final String mAddress;
@@ -507,6 +531,27 @@
         return null;
     }
 
+     /**
+      *  Perform a SDP query on the remote device to get the UUIDs
+      *  supported. This API is asynchronous and an Intent is sent,
+      *  with the UUIDs supported by the remote end. If there is an error
+      *  in getting the SDP records or if the process takes a long time,
+      *  an Intent is sent with the UUIDs that is currently present in the
+      *  cache. Clients should use the {@link getUuids} to get UUIDs
+      *  is SDP is not to be performed.
+      *
+      *  @return False if the sanity check fails, True if the process
+      *               of initiating an ACL connection to the remote device
+      *               was started.
+      *  @hide
+      */
+     public boolean fetchUuidsWithSdp() {
+        try {
+            return sService.fetchRemoteUuidsWithSdp(mAddress);
+        } catch (RemoteException e) {Log.e(TAG, "", e);}
+        return false;
+    }
+
     /** @hide */
     public int getServiceChannel(ParcelUuid uuid) {
          try {
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index 409c744..24ad06a 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -83,6 +83,12 @@
      * @param uuid
      */
     public static boolean isUuidPresent(ParcelUuid[] uuidArray, ParcelUuid uuid) {
+        if ((uuidArray == null || uuidArray.length == 0) && uuid == null)
+            return true;
+
+        if (uuidArray == null)
+            return false;
+
         for (ParcelUuid element: uuidArray) {
             if (element.equals(uuid)) return true;
         }
@@ -98,7 +104,14 @@
      */
     public static boolean containsAnyUuid(ParcelUuid[] uuidA, ParcelUuid[] uuidB) {
         if (uuidA == null && uuidB == null) return true;
-        if (uuidA == null || uuidB == null) return false;
+
+        if (uuidA == null) {
+            return uuidB.length == 0 ? true : false;
+        }
+
+        if (uuidB == null) {
+            return uuidA.length == 0 ? true : false;
+        }
 
         HashSet<ParcelUuid> uuidSet = new HashSet<ParcelUuid> (Arrays.asList(uuidA));
         for (ParcelUuid uuid: uuidB) {
@@ -117,7 +130,12 @@
      */
     public static boolean containsAllUuids(ParcelUuid[] uuidA, ParcelUuid[] uuidB) {
         if (uuidA == null && uuidB == null) return true;
-        if (uuidA == null || uuidB == null) return false;
+
+        if (uuidA == null) {
+            return uuidB.length == 0 ? true : false;
+        }
+
+        if (uuidB == null) return true;
 
         HashSet<ParcelUuid> uuidSet = new HashSet<ParcelUuid> (Arrays.asList(uuidA));
         for (ParcelUuid uuid: uuidB) {
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index 04c8ec9..203a61d 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -53,6 +53,7 @@
     String getRemoteName(in String address);
     int getRemoteClass(in String address);
     ParcelUuid[] getRemoteUuids(in String address);
+    boolean fetchRemoteUuidsWithSdp(in String address);
     int getRemoteServiceChannel(in String address,in ParcelUuid uuid);
 
     boolean setPin(in String address, in byte[] pin);
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index a3c4f9a..fe4665e 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -657,8 +657,7 @@
      * supplying your own BroadcastReceiver when calling, which will be
      * treated as a final receiver at the end of the broadcast -- its
      * {@link BroadcastReceiver#onReceive} method will be called with
-     * the result values collected from the other receivers.  If you use
-     * an <var>resultReceiver</var> with this method, then the broadcast will
+     * the result values collected from the other receivers.  The broadcast will
      * be serialized in the same way as calling
      * {@link #sendOrderedBroadcast(Intent, String)}.
      *
@@ -689,6 +688,7 @@
      * @see #sendBroadcast(Intent, String)
      * @see #sendOrderedBroadcast(Intent, String)
      * @see #sendStickyBroadcast(Intent)
+     * @see #sendStickyOrderedBroadcast(Intent, BroadcastReceiver, Handler, int, String, Bundle)
      * @see android.content.BroadcastReceiver
      * @see #registerReceiver
      * @see android.app.Activity#RESULT_OK
@@ -715,8 +715,55 @@
      * be re-broadcast to future receivers.
      *
      * @see #sendBroadcast(Intent)
+     * @see #sendStickyOrderedBroadcast(Intent, BroadcastReceiver, Handler, int, String, Bundle)
      */
     public abstract void sendStickyBroadcast(Intent intent);
+    
+    /**
+     * Version of {@link #sendStickyBroadcast} that allows you to
+     * receive data back from the broadcast.  This is accomplished by
+     * supplying your own BroadcastReceiver when calling, which will be
+     * treated as a final receiver at the end of the broadcast -- its
+     * {@link BroadcastReceiver#onReceive} method will be called with
+     * the result values collected from the other receivers.  The broadcast will
+     * be serialized in the same way as calling
+     * {@link #sendOrderedBroadcast(Intent, String)}.
+     *
+     * <p>Like {@link #sendBroadcast(Intent)}, this method is
+     * asynchronous; it will return before
+     * resultReceiver.onReceive() is called.  Note that the sticky data
+     * stored is only the data you initially supply to the broadcast, not
+     * the result of any changes made by the receivers.
+     *
+     * <p>See {@link BroadcastReceiver} for more information on Intent broadcasts.
+     *
+     * @param intent The Intent to broadcast; all receivers matching this
+     *               Intent will receive the broadcast.
+     * @param resultReceiver Your own BroadcastReceiver to treat as the final
+     *                       receiver of the broadcast.
+     * @param scheduler A custom Handler with which to schedule the
+     *                  resultReceiver callback; if null it will be
+     *                  scheduled in the Context's main thread.
+     * @param initialCode An initial value for the result code.  Often
+     *                    Activity.RESULT_OK.
+     * @param initialData An initial value for the result data.  Often
+     *                    null.
+     * @param initialExtras An initial value for the result extras.  Often
+     *                      null.
+     *
+     * @see #sendBroadcast(Intent)
+     * @see #sendBroadcast(Intent, String)
+     * @see #sendOrderedBroadcast(Intent, String)
+     * @see #sendStickyBroadcast(Intent)
+     * @see android.content.BroadcastReceiver
+     * @see #registerReceiver
+     * @see android.app.Activity#RESULT_OK
+     */
+    public abstract void sendStickyOrderedBroadcast(Intent intent,
+            BroadcastReceiver resultReceiver,
+            Handler scheduler, int initialCode, String initialData,
+            Bundle initialExtras);
+
 
     /**
      * Remove the data previously sent with {@link #sendStickyBroadcast},
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index d580c47..1b34320c 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -288,6 +288,16 @@
     }
 
     @Override
+    public void sendStickyOrderedBroadcast(
+        Intent intent, BroadcastReceiver resultReceiver,
+        Handler scheduler, int initialCode, String initialData,
+        Bundle initialExtras) {
+        mBase.sendStickyOrderedBroadcast(intent,
+                resultReceiver, scheduler, initialCode,
+                initialData, initialExtras);
+    }
+
+    @Override
     public void removeStickyBroadcast(Intent intent) {
         mBase.removeStickyBroadcast(intent);
     }
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 1359761..5fb5768 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1352,14 +1352,20 @@
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_CONFIGURATION_CHANGED = "android.intent.action.CONFIGURATION_CHANGED";
     /**
-     * Broadcast Action:  The charging state, or charge level of the battery has
-     * changed.
+     * Broadcast Action:  This is a <em>sticky broadcast</em> containing the
+     * charging state, level, and other information about the battery.
+     * See {@link android.os.BatteryManager} for documentation on the
+     * contents of the Intent.
      *
      * <p class="note">
      * You can <em>not</em> receive this through components declared
      * in manifests, only by explicitly registering for it with
      * {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
-     * Context.registerReceiver()}.
+     * Context.registerReceiver()}.  See {@link #ACTION_BATTERY_LOW},
+     * {@link #ACTION_BATTERY_OKAY}, {@link #ACTION_POWER_CONNECTED},
+     * and {@link #ACTION_POWER_DISCONNECTED} for distinct battery-related
+     * broadcasts that are sent and can be received through manifest
+     * receivers.
      * 
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
@@ -1434,7 +1440,8 @@
      */
     public static final String ACTION_REQUEST_SHUTDOWN = "android.intent.action.ACTION_REQUEST_SHUTDOWN";
     /**
-     * Broadcast Action:  Indicates low memory condition on the device
+     * Broadcast Action:  A sticky broadcast that indicates low memory
+     * condition on the device
      * 
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
@@ -1711,6 +1718,18 @@
             "android.intent.action.REBOOT";
 
     /**
+     * Broadcast Action:  A sticky broadcast indicating the phone was docked
+     * or undocked.  Includes the extra
+     * field {@link #EXTRA_DOCK_STATE}, containing the current dock state.
+     * This is intended for monitoring the current dock state.
+     * To launch an activity from a dock state change, use {@link #CATEGORY_CAR_DOCK}
+     * or {@link #CATEGORY_DESK_DOCK} instead.
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_DOCK_EVENT =
+            "android.intent.action.DOCK_EVENT";
+
+    /**
      * Broadcast Action: a remote intent is to be broadcasted.
      *
      * A remote intent is used for remote RPC between devices. The remote intent
@@ -1720,6 +1739,7 @@
      * does not trust intent broadcasts from arbitrary intent senders, it should require
      * the sender to hold certain permissions so only trusted sender's broadcast will be
      * let through.
+     * @hide
      */
     public static final String ACTION_REMOTE_INTENT =
             "android.intent.action.REMOTE_INTENT";
@@ -1865,7 +1885,7 @@
             "android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST";
     /**
      * An activity to run when device is inserted into a car dock.
-    * Used with {@link #ACTION_MAIN} to launch an activity.
+     * Used with {@link #ACTION_MAIN} to launch an activity.
      * To monitor dock state, use {@link #ACTION_DOCK_EVENT} instead.
      */
     @SdkConstant(SdkConstantType.INTENT_CATEGORY)
@@ -1878,16 +1898,6 @@
     @SdkConstant(SdkConstantType.INTENT_CATEGORY)
     public static final String CATEGORY_DESK_DOCK = "android.intent.category.DESK_DOCK";
 
-    /**
-     * Broadcast Action:  The phone was docked or undocked.  Includes the extra
-     * field {@link #EXTRA_DOCK_STATE}, containing the current dock state.
-     * This is intended for monitoring the current dock state.
-     * To launch an activity from a dock state change, use {@link #CATEGORY_CAR_DOCK}
-     * or {@link #CATEGORY_DESK_DOCK} instead.
-     */
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String ACTION_DOCK_EVENT = "android.intent.action.DOCK_EVENT";
-
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     // Standard extra data keys.
@@ -2046,6 +2056,12 @@
     public static final int EXTRA_DOCK_STATE_CAR = 2;
 
     /**
+     * Boolean that can be supplied as meta-data with a dock activity, to
+     * indicate that the dock should take over the home key when it is active.
+     */
+    public static final String METADATA_DOCK_HOME = "android.dock_home";
+    
+    /**
      * Used as a parcelable extra field in {@link #ACTION_APP_ERROR}, containing
      * the bug report.
      *
@@ -2308,6 +2324,18 @@
      */
     public static final int FLAG_ACTIVITY_REORDER_TO_FRONT = 0X00020000;
     /**
+     * If set in an Intent passed to {@link Context#startActivity Context.startActivity()},
+     * this flag will prevent the system from applying an activity transition
+     * animation to go to the next activity state.  This doesn't mean an
+     * animation will never run -- if another activity change happens that doesn't
+     * specify this flag before the activity started here is displayed, then
+     * that transition will be used.  This this flag can be put to good use
+     * when you are going to do a series of activity operations but the
+     * animation seen by the user shouldn't be driven by the first activity
+     * change but rather a later one.
+     */
+    public static final int FLAG_ACTIVITY_NO_ANIMATION = 0X00010000;
+    /**
      * If set, when sending a broadcast only registered receivers will be
      * called -- no BroadcastReceiver components will be launched.
      */
@@ -2521,6 +2549,7 @@
      *
      * @param uri The URI to turn into an Intent.
      * @param flags Additional processing flags.  Either 0 or
+     * {@link #URI_INTENT_SCHEME}.
      *
      * @return Intent The newly created Intent object.
      *
@@ -2654,24 +2683,24 @@
 
         int i = uri.lastIndexOf('#');
         if (i >= 0) {
-            Uri data = null;
             String action = null;
-            if (i > 0) {
-                data = Uri.parse(uri.substring(0, i));
-            }
+            final int intentFragmentStart = i;
+            boolean isIntentFragment = false;
 
             i++;
 
             if (uri.regionMatches(i, "action(", 0, 7)) {
+                isIntentFragment = true;
                 i += 7;
                 int j = uri.indexOf(')', i);
                 action = uri.substring(i, j);
                 i = j + 1;
             }
 
-            intent = new Intent(action, data);
+            intent = new Intent(action);
 
             if (uri.regionMatches(i, "categories(", 0, 11)) {
+                isIntentFragment = true;
                 i += 11;
                 int j = uri.indexOf(')', i);
                 while (i < j) {
@@ -2686,6 +2715,7 @@
             }
 
             if (uri.regionMatches(i, "type(", 0, 5)) {
+                isIntentFragment = true;
                 i += 5;
                 int j = uri.indexOf(')', i);
                 intent.mType = uri.substring(i, j);
@@ -2693,6 +2723,7 @@
             }
 
             if (uri.regionMatches(i, "launchFlags(", 0, 12)) {
+                isIntentFragment = true;
                 i += 12;
                 int j = uri.indexOf(')', i);
                 intent.mFlags = Integer.decode(uri.substring(i, j)).intValue();
@@ -2700,6 +2731,7 @@
             }
 
             if (uri.regionMatches(i, "component(", 0, 10)) {
+                isIntentFragment = true;
                 i += 10;
                 int j = uri.indexOf(')', i);
                 int sep = uri.indexOf('!', i);
@@ -2712,6 +2744,7 @@
             }
 
             if (uri.regionMatches(i, "extras(", 0, 7)) {
+                isIntentFragment = true;
                 i += 7;
 
                 final int closeParen = uri.indexOf(')', i);
@@ -2783,6 +2816,12 @@
                 }
             }
 
+            if (isIntentFragment) {
+                intent.mData = Uri.parse(uri.substring(0, intentFragmentStart));
+            } else {
+                intent.mData = Uri.parse(uri);
+            }
+            
             if (intent.mAction == null) {
                 // By default, if no action is specified, then use VIEW.
                 intent.mAction = ACTION_VIEW;
@@ -3572,7 +3611,7 @@
             }
         } else {
             ResolveInfo info = pm.resolveActivity(
-                this, PackageManager.MATCH_DEFAULT_ONLY);
+                this, PackageManager.MATCH_DEFAULT_ONLY | flags);
             if (info != null) {
                 ai = info.activityInfo;
             }
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index 7859d5a..80613d8 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -514,7 +514,7 @@
     public SyncStorageEngine getSyncStorageEngine() {
         return mSyncStorageEngine;
     }
-    
+
     private void ensureAlarmService() {
         if (mAlarmService == null) {
             mAlarmService = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
@@ -1125,7 +1125,7 @@
         tobj.set(time);
         return tobj.format("%Y-%m-%d %H:%M:%S");
     }
-    
+
     protected void dumpSyncState(PrintWriter pw, StringBuilder sb) {
         pw.print("sync enabled: "); pw.println(isSyncEnabled());
         pw.print("data connected: "); pw.println(mDataConnectionIsConnected);
@@ -1219,13 +1219,13 @@
                         = mSyncStorageEngine.getAuthority(status.authorityId);
                 if (authority != null) {
                     Account curAccount = authority.account;
-                    
+
                     if (processedAccounts.contains(curAccount)) {
                         continue;
                     }
-                    
+
                     processedAccounts.add(curAccount);
-                    
+
                     pw.print("  Account "); pw.print(authority.account.name);
                             pw.print(" "); pw.print(authority.account.type);
                             pw.println(":");
@@ -1271,7 +1271,7 @@
         pw.print(time/1000); pw.print('.'); pw.print((time/100)%10);
         pw.print('s');
     }
-    
+
     private void dumpDayStatistic(PrintWriter pw, SyncStorageEngine.DayStats ds) {
         pw.print("Success ("); pw.print(ds.successCount);
         if (ds.successCount > 0) {
@@ -1285,7 +1285,7 @@
         }
         pw.println(")");
     }
-    
+
     protected void dumpSyncHistory(PrintWriter pw, StringBuilder sb) {
         SyncStorageEngine.DayStats dses[] = mSyncStorageEngine.getDayStatistics();
         if (dses != null && dses[0] != null) {
@@ -1295,18 +1295,18 @@
             int today = dses[0].day;
             int i;
             SyncStorageEngine.DayStats ds;
-            
+
             // Print each day in the current week.
             for (i=1; i<=6 && i < dses.length; i++) {
                 ds = dses[i];
                 if (ds == null) break;
                 int delta = today-ds.day;
                 if (delta > 6) break;
-                
+
                 pw.print("  Day-"); pw.print(delta); pw.print(":  ");
                 dumpDayStatistic(pw, ds);
             }
-            
+
             // Aggregate all following days into weeks and print totals.
             int weekDay = today;
             while (i < dses.length) {
@@ -1321,7 +1321,7 @@
                     int delta = weekDay-ds.day;
                     if (delta > 6) break;
                     i++;
-                    
+
                     if (aggr == null) {
                         aggr = new SyncStorageEngine.DayStats(weekDay);
                     }
@@ -1336,7 +1336,7 @@
                 }
             }
         }
-        
+
         ArrayList<SyncStorageEngine.SyncHistoryItem> items
                 = mSyncStorageEngine.getSyncHistory();
         if (items != null && items.size() > 0) {
@@ -2132,7 +2132,8 @@
             final long now = System.currentTimeMillis();
 
             EventLog.writeEvent(2720, syncOperation.authority,
-                    SyncStorageEngine.EVENT_START, source);
+                                SyncStorageEngine.EVENT_START, source,
+                                syncOperation.account.name.hashCode());
 
             return mSyncStorageEngine.insertStartSyncEvent(
                     syncOperation.account, syncOperation.authority, now, source);
@@ -2141,7 +2142,8 @@
         public void stopSyncEvent(long rowId, SyncOperation syncOperation, String resultMessage,
                 int upstreamActivity, int downstreamActivity, long elapsedTime) {
             EventLog.writeEvent(2720, syncOperation.authority,
-                    SyncStorageEngine.EVENT_STOP, syncOperation.syncSource);
+                                SyncStorageEngine.EVENT_STOP, syncOperation.syncSource,
+                                syncOperation.account.name.hashCode());
 
             mSyncStorageEngine.stopSyncEvent(rowId, elapsedTime, resultMessage,
                     downstreamActivity, upstreamActivity);
@@ -2173,7 +2175,7 @@
                 syncOperation.pendingOperation = op;
                 add(syncOperation, op);
             }
-            
+
             if (DEBUG_CHECK_DATA_CONSISTENCY) debugCheckDataStructures(true /* check the DB */);
         }
 
diff --git a/core/java/android/content/SyncStatusInfo.java b/core/java/android/content/SyncStatusInfo.java
index 6687fcb..b8fda03 100644
--- a/core/java/android/content/SyncStatusInfo.java
+++ b/core/java/android/content/SyncStatusInfo.java
@@ -38,6 +38,7 @@
     public String lastFailureMesg;
     public long initialFailureTime;
     public boolean pending;
+    public boolean initialize;
     
     SyncStatusInfo(int authorityId) {
         this.authorityId = authorityId;
@@ -73,6 +74,7 @@
         parcel.writeString(lastFailureMesg);
         parcel.writeLong(initialFailureTime);
         parcel.writeInt(pending ? 1 : 0);
+        parcel.writeInt(initialize ? 1 : 0);
     }
 
     SyncStatusInfo(Parcel parcel) {
@@ -94,6 +96,7 @@
         lastFailureMesg = parcel.readString();
         initialFailureTime = parcel.readLong();
         pending = parcel.readInt() != 0;
+        initialize = parcel.readInt() != 0;
     }
     
     public static final Creator<SyncStatusInfo> CREATOR = new Creator<SyncStatusInfo>() {
diff --git a/core/java/android/content/SyncStorageEngine.java b/core/java/android/content/SyncStorageEngine.java
index f251984..fbdd5ae 100644
--- a/core/java/android/content/SyncStorageEngine.java
+++ b/core/java/android/content/SyncStorageEngine.java
@@ -346,16 +346,6 @@
                 }
             }
         }
-        // Inform the backup manager about a data change
-        IBackupManager ibm = IBackupManager.Stub.asInterface(
-                ServiceManager.getService(Context.BACKUP_SERVICE));
-        if (ibm != null) {
-            try {
-                ibm.dataChanged("com.android.providers.settings");
-            } catch (RemoteException e) {
-                // Try again later
-            }
-        }
     }
 
     public boolean getSyncAutomatically(Account account, String providerName) {
@@ -521,6 +511,9 @@
 
             SyncStatusInfo status = getOrCreateSyncStatusLocked(authority.ident);
             status.pending = true;
+            status.initialize = op.extras != null && 
+                 op.extras.containsKey(ContentResolver.SYNC_EXTRAS_INITIALIZE) &&
+                 op.extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE);
         }
 
         reportChange(ContentResolver.SYNC_OBSERVER_TYPE_PENDING);
diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java
index 50faf57..11c67cc 100644
--- a/core/java/android/content/res/CompatibilityInfo.java
+++ b/core/java/android/content/res/CompatibilityInfo.java
@@ -274,6 +274,25 @@
          * Apply translation to the canvas that is necessary to draw the content.
          */
         public void translateCanvas(Canvas canvas) {
+            if (applicationScale == 1.5f) {
+                /*  When we scale for compatibility, we can put our stretched
+                    bitmaps and ninepatches on exacty 1/2 pixel boundaries,
+                    which can give us inconsistent drawing due to imperfect
+                    float precision in the graphics engine's inverse matrix.
+                 
+                    As a work-around, we translate by a tiny amount to avoid
+                    landing on exact pixel centers and boundaries, giving us
+                    the slop we need to draw consistently.
+                 
+                    This constant is meant to resolve to 1/255 after it is
+                    scaled by 1.5 (applicationScale). Note, this is just a guess
+                    as to what is small enough not to create its own artifacts,
+                    and big enough to avoid the precision problems. Feel free
+                    to experiment with smaller values as you choose.
+                 */
+                final float tinyOffset = 2.0f / (3 * 255);
+                canvas.translate(tinyOffset, tinyOffset);
+            }
             canvas.scale(applicationScale, applicationScale);
         }
 
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 13effe0..5f1a3c5 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -137,7 +137,6 @@
      *
      * @throws IOException if the method fails.
      *
-     * FIXME: Unhide after approval
      * @hide
      */
     public native final void reconnect() throws IOException;
@@ -150,25 +149,20 @@
      * Camera object is locked. Locking it again from the same process will
      * have no effect. Attempting to lock it from another process if it has
      * not been unlocked will fail.
-     * Returns 0 if lock was successful.
      *
-     * FIXME: Unhide after approval
-     * @hide
+     * @throws RuntimeException if the method fails.
      */
-    public native final int lock();
+    public native final void lock();
 
     /**
      * Unlock the camera to allow another process to access it. To save
      * setup/teardown time, a client of Camera can pass an initialized Camera
      * object to another process. This method is used to unlock the Camera
      * object before handing off the Camera object to the other process.
-
-     * Returns 0 if unlock was successful.
      *
-     * FIXME: Unhide after approval
-     * @hide
+     * @throws RuntimeException if the method fails.
      */
-    public native final int unlock();
+    public native final void unlock();
 
     /**
      * Sets the SurfaceHolder to be used for a picture preview. If the surface
@@ -363,10 +357,12 @@
 
     /**
      * Starts auto-focus function and registers a callback function to run when
-     * camera is focused. Only valid after startPreview() has been called. If
-     * the camera does not support auto-focus, it is a no-op and {@link
-     * AutoFocusCallback#onAutoFocus(boolean, Camera)} callback will be called
-     * immediately.
+     * camera is focused. Only valid after startPreview() has been called.
+     * Applications should call {@link
+     * android.hardware.Camera.Parameters#getFocusMode()} to determine if this
+     * method should be called. If the camera does not support auto-focus, it is
+     * a no-op and {@link AutoFocusCallback#onAutoFocus(boolean, Camera)}
+     * callback will be called immediately.
      * <p>If your application should not be installed
      * on devices without auto-focus, you must declare that your application
      * uses auto-focus with the
@@ -604,6 +600,7 @@
         private static final String KEY_ANTIBANDING = "antibanding";
         private static final String KEY_SCENE_MODE = "scene-mode";
         private static final String KEY_FLASH_MODE = "flash-mode";
+        private static final String KEY_FOCUS_MODE = "focus-mode";
         // Parameter key suffix for supported values.
         private static final String SUPPORTED_VALUES_SUFFIX = "-values";
 
@@ -652,6 +649,10 @@
          * Flash will be fired in red-eye reduction mode.
          */
         public static final String FLASH_MODE_RED_EYE = "red-eye";
+        /**
+         * Constant emission of light. This can be used for video recording.
+         */
+        public static final String FLASH_MODE_VIDEO_LIGHT = "video-light";
 
         // Values for scene mode settings.
         public static final String SCENE_MODE_AUTO = "auto";
@@ -670,9 +671,29 @@
         public static final String SCENE_MODE_PARTY = "party";
         public static final String SCENE_MODE_CANDLELIGHT = "candlelight";
 
+        // Values for focus mode settings.
+        /**
+         * Auto-focus mode.
+         */
+        public static final String FOCUS_MODE_AUTO = "auto";
+        /**
+         * Focus is set at infinity. Applications should not call
+         * {@link #autoFocus(AutoFocusCallback)} in this mode.
+         */
+        public static final String FOCUS_MODE_INFINITY = "infinity";
+        public static final String FOCUS_MODE_MACRO = "macro";
+        /**
+         * Focus is fixed. The camera is always in this mode if the focus is not
+         * adjustable. If the camera has auto-focus, this mode can fix the
+         * focus, which is usually at hyperfocal distance. Applications should
+         * not call {@link #autoFocus(AutoFocusCallback)} in this mode.
+         */
+        public static final String FOCUS_MODE_FIXED = "fixed";
+
         // Formats for setPreviewFormat and setPictureFormat.
         private static final String PIXEL_FORMAT_YUV422SP = "yuv422sp";
         private static final String PIXEL_FORMAT_YUV420SP = "yuv420sp";
+        private static final String PIXEL_FORMAT_YUV422I = "yuv422i-yuyv";
         private static final String PIXEL_FORMAT_RGB565 = "rgb565";
         private static final String PIXEL_FORMAT_JPEG = "jpeg";
 
@@ -957,7 +978,13 @@
          */
         public List<Integer> getSupportedPreviewFormats() {
             String str = get(KEY_PREVIEW_FORMAT + SUPPORTED_VALUES_SUFFIX);
-            return splitInt(str);
+            ArrayList<Integer> formats = new ArrayList<Integer>();
+            for (String s : split(str)) {
+                int f = pixelFormatForCameraFormat(s);
+                if (f == PixelFormat.UNKNOWN) continue;
+                formats.add(f);
+            }
+            return formats;
         }
 
         /**
@@ -1036,6 +1063,7 @@
             switch(pixel_format) {
             case PixelFormat.YCbCr_422_SP: return PIXEL_FORMAT_YUV422SP;
             case PixelFormat.YCbCr_420_SP: return PIXEL_FORMAT_YUV420SP;
+            case PixelFormat.YCbCr_422_I:  return PIXEL_FORMAT_YUV422I;
             case PixelFormat.RGB_565:      return PIXEL_FORMAT_RGB565;
             case PixelFormat.JPEG:         return PIXEL_FORMAT_JPEG;
             default:                       return null;
@@ -1052,6 +1080,9 @@
             if (format.equals(PIXEL_FORMAT_YUV420SP))
                 return PixelFormat.YCbCr_420_SP;
 
+            if (format.equals(PIXEL_FORMAT_YUV422I))
+                return PixelFormat.YCbCr_422_I;
+
             if (format.equals(PIXEL_FORMAT_RGB565))
                 return PixelFormat.RGB_565;
 
@@ -1290,6 +1321,39 @@
             return split(str);
         }
 
+        /**
+         * Gets the current focus mode setting.
+         *
+         * @return one of FOCUS_MODE_XXX string constant. If the camera does not
+         *         support auto-focus, this should return {@link
+         *         #FOCUS_MODE_FIXED}. If the focus mode is not FOCUS_MODE_FIXED
+         *         or {@link #FOCUS_MODE_INFINITY}, applications should call
+         *         {@link #autoFocus(AutoFocusCallback)} to start the focus.
+         */
+        public String getFocusMode() {
+            return get(KEY_FOCUS_MODE);
+        }
+
+        /**
+         * Sets the focus mode.
+         *
+         * @param value FOCUS_MODE_XXX string constants.
+         */
+        public void setFocusMode(String value) {
+            set(KEY_FOCUS_MODE, value);
+        }
+
+        /**
+         * Gets the supported focus modes.
+         *
+         * @return a List of FOCUS_MODE_XXX string constants. null if focus mode
+         *         setting is not supported.
+         */
+        public List<String> getSupportedFocusModes() {
+            String str = get(KEY_FOCUS_MODE + SUPPORTED_VALUES_SUFFIX);
+            return split(str);
+        }
+
         // Splits a comma delimited string to an ArrayList of String.
         // Return null if the passing string is null or the size is 0.
         private ArrayList<String> split(String str) {
diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java
index 8f1a756..44b73c5 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -18,10 +18,73 @@
 
 /**
  * The BatteryManager class contains strings and constants used for values
- * in the ACTION_BATTERY_CHANGED Intent.
+ * in the {@link android.content.Intent#ACTION_BATTERY_CHANGED} Intent.
  */
 public class BatteryManager {
-
+    /**
+     * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
+     * integer containing the current status constant.
+     */
+    public static final String EXTRA_STATUS = "status";
+    
+    /**
+     * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
+     * integer containing the current health constant.
+     */
+    public static final String EXTRA_HEALTH = "health";
+    
+    /**
+     * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
+     * boolean indicating whether a battery is present.
+     */
+    public static final String EXTRA_PRESENT = "present";
+    
+    /**
+     * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
+     * integer field containing the current battery level, from 0 to
+     * {@link #EXTRA_SCALE}.
+     */
+    public static final String EXTRA_LEVEL = "level";
+    
+    /**
+     * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
+     * integer containing the maximum battery level.
+     */
+    public static final String EXTRA_SCALE = "scale";
+    
+    /**
+     * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
+     * integer containing the resource ID of a small status bar icon
+     * indicating the current battery state.
+     */
+    public static final String EXTRA_ICON_SMALL = "icon-small";
+    
+    /**
+     * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
+     * integer indicating whether the device is plugged in to a power
+     * source; 0 means it is on battery, other constants are different
+     * types of power sources.
+     */
+    public static final String EXTRA_PLUGGED = "plugged";
+    
+    /**
+     * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
+     * integer containing the current battery voltage level.
+     */
+    public static final String EXTRA_VOLTAGE = "voltage";
+    
+    /**
+     * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
+     * integer containing the current battery temperature.
+     */
+    public static final String EXTRA_TEMPERATURE = "temperature";
+    
+    /**
+     * Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
+     * String describing the technology of the current battery.
+     */
+    public static final String EXTRA_TECHNOLOGY = "technology";
+    
     // values for "status" field in the ACTION_BATTERY_CHANGED Intent
     public static final int BATTERY_STATUS_UNKNOWN = 1;
     public static final int BATTERY_STATUS_CHARGING = 2;
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index e203fd5..a49a27a0 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -314,6 +314,15 @@
              * @return foreground cpu time in microseconds
              */
             public abstract long getForegroundTime(int which);
+
+            /**
+             * Returns the approximate cpu time spent in microseconds, at a certain CPU speed.
+             * @param speedStep the index of the CPU speed. This is not the actual speed of the
+             * CPU.
+             * @param which one of STATS_TOTAL, STATS_LAST, STATS_CURRENT or STATS_UNPLUGGED
+             * @see BatteryStats#getCpuSpeedSteps()
+             */
+            public abstract long getTimeAtCpuSpeedStep(int speedStep, int which);
         }
 
         /**
@@ -573,6 +582,9 @@
     
     public abstract Map<String, ? extends Timer> getKernelWakelockStats();
 
+    /** Returns the number of different speeds that the CPU can run at */
+    public abstract int getCpuSpeedSteps();
+
     private final static void formatTimeRaw(StringBuilder out, long seconds) {
         long days = seconds / (60 * 60 * 24);
         if (days != 0) {
diff --git a/core/java/android/preference/VolumePreference.java b/core/java/android/preference/VolumePreference.java
index b337d28..a264594 100644
--- a/core/java/android/preference/VolumePreference.java
+++ b/core/java/android/preference/VolumePreference.java
@@ -121,6 +121,9 @@
        if (mSeekBarVolumizer != null) {
            Dialog dialog = getDialog();
            if (dialog != null && dialog.isShowing()) {
+               View view = dialog.getWindow().getDecorView()
+                       .findViewById(com.android.internal.R.id.seekbar);
+               if (view != null) view.setOnKeyListener(null);
                // Stopped while dialog was showing, revert changes
                mSeekBarVolumizer.revertVolume();
            }
diff --git a/core/java/android/provider/Calendar.java b/core/java/android/provider/Calendar.java
index 1de971b..f046cef 100644
--- a/core/java/android/provider/Calendar.java
+++ b/core/java/android/provider/Calendar.java
@@ -110,6 +110,7 @@
         public static final int EDITOR_ACCESS = 600;
         /** Full access to the calendar */
         public static final int OWNER_ACCESS = 700;
+        /** Domain admin */
         public static final int ROOT_ACCESS = 800;
 
         /**
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 93ee3ba..3df228d 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -410,7 +410,8 @@
             private AggregationSuggestions() {}
 
             /**
-             * The directory twig for this sub-table
+             * The directory twig for this sub-table. The URI can be followed by an optional
+             * type-to-filter, similar to {@link Contacts#CONTENT_FILTER_URI}.
              */
             public static final String CONTENT_DIRECTORY = "suggestions";
         }
@@ -677,12 +678,20 @@
     }
 
     /**
+     * Combines all columns returned by {@link Data} table queries.
+     */
+    private interface DataColumnsWithJoins extends BaseColumns, DataColumns, RawContactsColumns,
+            ContactsColumns, ContactOptionsColumns {
+
+    }
+
+    /**
      * Constants for the data table, which contains data points tied to a raw contact.
      * For example, a phone number or email address. Each row in this table contains a type
      * definition and some generic columns. Each data type can define the meaning for each of
      * the generic columns.
      */
-    public static final class Data implements BaseColumns, DataColumns {
+    public final static class Data implements DataColumnsWithJoins {
         /**
          * This utility class cannot be instantiated
          */
@@ -892,32 +901,9 @@
         public static final String PACKAGE_COMMON = "common";
 
         /**
-         * Columns common across the specific types.
-         */
-        private interface BaseCommonColumns {
-            /**
-             * The package name to use when creating {@link Resources} objects for
-             * this data row. This value is only designed for use when building user
-             * interfaces, and should not be used to infer the owner.
-             */
-            public static final String RES_PACKAGE = "res_package";
-
-            /**
-             * The MIME type of the item represented by this row.
-             */
-            public static final String MIMETYPE = "mimetype";
-
-            /**
-             * The {@link RawContacts#_ID} that this data belongs to.
-             */
-            public static final String RAW_CONTACT_ID = "raw_contact_id";
-        }
-
-        /**
          * The base types that all "Typed" data kinds support.
          */
         public interface BaseTypes {
-
             /**
              * A custom type. The custom label should be supplied by user.
              */
@@ -927,96 +913,96 @@
         /**
          * Columns common across the specific types.
          */
-        private interface CommonColumns extends BaseTypes{
-            /**
-             * The type of data, for example Home or Work.
-             * <P>Type: INTEGER</P>
-             */
-            public static final String TYPE = "data1";
-
+        private interface CommonColumns extends BaseTypes {
             /**
              * The data for the contact method.
              * <P>Type: TEXT</P>
              */
-            public static final String DATA = "data2";
+            public static final String DATA = DataColumns.DATA1;
+
+            /**
+             * The type of data, for example Home or Work.
+             * <P>Type: INTEGER</P>
+             */
+            public static final String TYPE = DataColumns.DATA2;
 
             /**
              * The user defined label for the the contact method.
              * <P>Type: TEXT</P>
              */
-            public static final String LABEL = "data3";
+            public static final String LABEL = DataColumns.DATA3;
         }
 
         /**
          * Parts of the name.
          */
-        public static final class StructuredName implements BaseCommonColumns {
+        public static final class StructuredName implements DataColumnsWithJoins {
             private StructuredName() {}
 
             /** MIME type used when storing this in data table. */
             public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/name";
 
             /**
-             * The given name for the contact.
-             * <P>Type: TEXT</P>
-             */
-            public static final String GIVEN_NAME = "data1";
-
-            /**
-             * The family name for the contact.
-             * <P>Type: TEXT</P>
-             */
-            public static final String FAMILY_NAME = "data2";
-
-            /**
-             * The contact's honorific prefix, e.g. "Sir"
-             * <P>Type: TEXT</P>
-             */
-            public static final String PREFIX = "data3";
-
-            /**
-             * The contact's middle name
-             * <P>Type: TEXT</P>
-             */
-            public static final String MIDDLE_NAME = "data4";
-
-            /**
-             * The contact's honorific suffix, e.g. "Jr"
-             */
-            public static final String SUFFIX = "data5";
-
-            /**
-             * The phonetic version of the given name for the contact.
-             * <P>Type: TEXT</P>
-             */
-            public static final String PHONETIC_GIVEN_NAME = "data6";
-
-            /**
-             * The phonetic version of the additional name for the contact.
-             * <P>Type: TEXT</P>
-             */
-            public static final String PHONETIC_MIDDLE_NAME = "data7";
-
-            /**
-             * The phonetic version of the family name for the contact.
-             * <P>Type: TEXT</P>
-             */
-            public static final String PHONETIC_FAMILY_NAME = "data8";
-
-            /**
              * The name that should be used to display the contact.
              * <i>Unstructured component of the name should be consistent with
              * its structured representation.</i>
              * <p>
              * Type: TEXT
              */
-            public static final String DISPLAY_NAME = "data9";
+            public static final String DISPLAY_NAME = DATA1;
+
+            /**
+             * The given name for the contact.
+             * <P>Type: TEXT</P>
+             */
+            public static final String GIVEN_NAME = DATA2;
+
+            /**
+             * The family name for the contact.
+             * <P>Type: TEXT</P>
+             */
+            public static final String FAMILY_NAME = DATA3;
+
+            /**
+             * The contact's honorific prefix, e.g. "Sir"
+             * <P>Type: TEXT</P>
+             */
+            public static final String PREFIX = DATA4;
+
+            /**
+             * The contact's middle name
+             * <P>Type: TEXT</P>
+             */
+            public static final String MIDDLE_NAME = DATA5;
+
+            /**
+             * The contact's honorific suffix, e.g. "Jr"
+             */
+            public static final String SUFFIX = DATA6;
+
+            /**
+             * The phonetic version of the given name for the contact.
+             * <P>Type: TEXT</P>
+             */
+            public static final String PHONETIC_GIVEN_NAME = DATA7;
+
+            /**
+             * The phonetic version of the additional name for the contact.
+             * <P>Type: TEXT</P>
+             */
+            public static final String PHONETIC_MIDDLE_NAME = DATA8;
+
+            /**
+             * The phonetic version of the family name for the contact.
+             * <P>Type: TEXT</P>
+             */
+            public static final String PHONETIC_FAMILY_NAME = DATA9;
         }
 
         /**
          * A nickname.
          */
-        public static final class Nickname implements CommonColumns, BaseCommonColumns {
+        public static final class Nickname implements DataColumnsWithJoins, CommonColumns {
             private Nickname() {}
 
             /** MIME type used when storing this in data table. */
@@ -1037,7 +1023,7 @@
         /**
          * Common data definition for telephone numbers.
          */
-        public static final class Phone implements BaseCommonColumns, CommonColumns {
+        public static final class Phone implements DataColumnsWithJoins, CommonColumns {
             private Phone() {}
 
             /** MIME type used when storing this in data table. */
@@ -1093,43 +1079,85 @@
              */
             public static final String NUMBER = DATA;
 
+            /**
+             * @deprecated use {@link #getTypeLabel(Resources, int, CharSequence)} instead.
+             */
+            @Deprecated
             public static final CharSequence getDisplayLabel(Context context, int type,
                     CharSequence label, CharSequence[] labelArray) {
-                CharSequence display = "";
-
-                if (type != Phone.TYPE_CUSTOM) {
-                    CharSequence[] labels = labelArray != null? labelArray
-                            : context.getResources().getTextArray(
-                                    com.android.internal.R.array.phoneTypes);
-                    try {
-                        display = labels[type - 1];
-                    } catch (ArrayIndexOutOfBoundsException e) {
-                        display = labels[Phone.TYPE_CUSTOM];
-                    }
-                } else {
-                    if (!TextUtils.isEmpty(label)) {
-                        display = label;
-                    }
-                }
-                return display;
+                return getTypeLabel(context.getResources(), type, label);
             }
 
+            /**
+             * @deprecated use {@link #getTypeLabel(Resources, int, CharSequence)} instead.
+             */
+            @Deprecated
             public static final CharSequence getDisplayLabel(Context context, int type,
                     CharSequence label) {
-                return getDisplayLabel(context, type, label, null);
+                return getTypeLabel(context.getResources(), type, label);
+            }
+
+            /**
+             * Return the string resource that best describes the given
+             * {@link CommonColumns#TYPE}. Will always return a valid resource.
+             */
+            public static final int getTypeLabelResource(int type) {
+                switch (type) {
+                    case TYPE_HOME: return com.android.internal.R.string.phoneTypeHome;
+                    case TYPE_MOBILE: return com.android.internal.R.string.phoneTypeMobile;
+                    case TYPE_WORK: return com.android.internal.R.string.phoneTypeWork;
+                    case TYPE_FAX_WORK: return com.android.internal.R.string.phoneTypeFaxWork;
+                    case TYPE_FAX_HOME: return com.android.internal.R.string.phoneTypeFaxHome;
+                    case TYPE_PAGER: return com.android.internal.R.string.phoneTypePager;
+                    case TYPE_OTHER: return com.android.internal.R.string.phoneTypeOther;
+                    case TYPE_CALLBACK: return com.android.internal.R.string.phoneTypeCallback;
+                    case TYPE_CAR: return com.android.internal.R.string.phoneTypeCar;
+                    case TYPE_COMPANY_MAIN: return com.android.internal.R.string.phoneTypeCompanyMain;
+                    case TYPE_ISDN: return com.android.internal.R.string.phoneTypeIsdn;
+                    case TYPE_MAIN: return com.android.internal.R.string.phoneTypeMain;
+                    case TYPE_OTHER_FAX: return com.android.internal.R.string.phoneTypeOtherFax;
+                    case TYPE_RADIO: return com.android.internal.R.string.phoneTypeRadio;
+                    case TYPE_TELEX: return com.android.internal.R.string.phoneTypeTelex;
+                    case TYPE_TTY_TDD: return com.android.internal.R.string.phoneTypeTtyTdd;
+                    case TYPE_WORK_MOBILE: return com.android.internal.R.string.phoneTypeWorkMobile;
+                    case TYPE_WORK_PAGER: return com.android.internal.R.string.phoneTypeWorkPager;
+                    case TYPE_ASSISTANT: return com.android.internal.R.string.phoneTypeAssistant;
+                    case TYPE_MMS: return com.android.internal.R.string.phoneTypeMms;
+                    default: return com.android.internal.R.string.phoneTypeCustom;
+                }
+            }
+
+            /**
+             * Return a {@link CharSequence} that best describes the given type,
+             * possibly substituting the given {@link CommonColumns#LABEL} value
+             * for {@link BaseTypes#TYPE_CUSTOM}.
+             */
+            public static final CharSequence getTypeLabel(Resources res, int type,
+                    CharSequence label) {
+                if ((type == TYPE_CUSTOM || type == TYPE_ASSISTANT) && !TextUtils.isEmpty(label)) {
+                    return label;
+                } else {
+                    final int labelRes = getTypeLabelResource(type);
+                    return res.getText(labelRes);
+                }
             }
         }
 
         /**
          * Common data definition for email addresses.
          */
-        public static final class Email implements BaseCommonColumns, CommonColumns {
+        public static final class Email implements DataColumnsWithJoins, CommonColumns {
             private Email() {}
 
             /** MIME type used when storing this in data table. */
             public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/email_v2";
 
             /**
+             * The MIME type of {@link #CONTENT_URI} providing a directory of email addresses.
+             */
+            public static final String CONTENT_TYPE = "vnd.android.cursor.dir/email_v2";
+
+            /**
              * The content:// style URI for all data records of the
              * {@link Email#CONTENT_ITEM_TYPE} MIME type, combined with the
              * associated raw contact and aggregate contact data.
@@ -1145,9 +1173,6 @@
             public static final Uri CONTENT_LOOKUP_URI = Uri.withAppendedPath(CONTENT_URI,
                     "lookup");
 
-            @Deprecated
-            public static final Uri CONTENT_FILTER_EMAIL_URI = CONTENT_LOOKUP_URI;
-
             /**
              * The content:// style URL for email lookup using a filter. The filter returns
              * records of MIME type {@link Email#CONTENT_ITEM_TYPE}. The filter is applied
@@ -1166,13 +1191,42 @@
              * The display name for the email address
              * <P>Type: TEXT</P>
              */
-            public static final String DISPLAY_NAME = "data4";
+            public static final String DISPLAY_NAME = DATA4;
+
+            /**
+             * Return the string resource that best describes the given
+             * {@link CommonColumns#TYPE}. Will always return a valid resource.
+             */
+            public static final int getTypeLabelResource(int type) {
+                switch (type) {
+                    case TYPE_HOME: return com.android.internal.R.string.emailTypeHome;
+                    case TYPE_WORK: return com.android.internal.R.string.emailTypeWork;
+                    case TYPE_OTHER: return com.android.internal.R.string.emailTypeOther;
+                    case TYPE_MOBILE: return com.android.internal.R.string.emailTypeMobile;
+                    default: return com.android.internal.R.string.emailTypeCustom;
+                }
+            }
+
+            /**
+             * Return a {@link CharSequence} that best describes the given type,
+             * possibly substituting the given {@link CommonColumns#LABEL} value
+             * for {@link BaseTypes#TYPE_CUSTOM}.
+             */
+            public static final CharSequence getTypeLabel(Resources res, int type,
+                    CharSequence label) {
+                if (type == TYPE_CUSTOM && !TextUtils.isEmpty(label)) {
+                    return label;
+                } else {
+                    final int labelRes = getTypeLabelResource(type);
+                    return res.getText(labelRes);
+                }
+            }
         }
 
         /**
          * Common data definition for postal addresses.
          */
-        public static final class StructuredPostal implements BaseCommonColumns, CommonColumns {
+        public static final class StructuredPostal implements DataColumnsWithJoins, CommonColumns {
             private StructuredPostal() {
             }
 
@@ -1211,7 +1265,7 @@
              * <p>
              * Type: TEXT
              */
-            public static final String STREET = "data6";
+            public static final String STREET = DATA4;
 
             /**
              * Covers actual P.O. boxes, drawers, locked bags, etc. This is
@@ -1219,7 +1273,7 @@
              * <p>
              * Type: TEXT
              */
-            public static final String POBOX = "data7";
+            public static final String POBOX = DATA5;
 
             /**
              * This is used to disambiguate a street address when a city
@@ -1229,7 +1283,7 @@
              * <p>
              * Type: TEXT
              */
-            public static final String NEIGHBORHOOD = "data8";
+            public static final String NEIGHBORHOOD = DATA6;
 
             /**
              * Can be city, village, town, borough, etc. This is the postal town
@@ -1237,7 +1291,7 @@
              * <p>
              * Type: TEXT
              */
-            public static final String CITY = "data9";
+            public static final String CITY = DATA7;
 
             /**
              * A state, province, county (in Ireland), Land (in Germany),
@@ -1245,7 +1299,7 @@
              * <p>
              * Type: TEXT
              */
-            public static final String REGION = "data11";
+            public static final String REGION = DATA8;
 
             /**
              * Postal code. Usually country-wide, but sometimes specific to the
@@ -1253,20 +1307,48 @@
              * <p>
              * Type: TEXT
              */
-            public static final String POSTCODE = "data12";
+            public static final String POSTCODE = DATA9;
 
             /**
              * The name or code of the country.
              * <p>
              * Type: TEXT
              */
-            public static final String COUNTRY = "data13";
+            public static final String COUNTRY = DATA10;
+
+            /**
+             * Return the string resource that best describes the given
+             * {@link CommonColumns#TYPE}. Will always return a valid resource.
+             */
+            public static final int getTypeLabelResource(int type) {
+                switch (type) {
+                    case TYPE_HOME: return com.android.internal.R.string.postalTypeHome;
+                    case TYPE_WORK: return com.android.internal.R.string.postalTypeWork;
+                    case TYPE_OTHER: return com.android.internal.R.string.postalTypeOther;
+                    default: return com.android.internal.R.string.postalTypeCustom;
+                }
+            }
+
+            /**
+             * Return a {@link CharSequence} that best describes the given type,
+             * possibly substituting the given {@link CommonColumns#LABEL} value
+             * for {@link BaseTypes#TYPE_CUSTOM}.
+             */
+            public static final CharSequence getTypeLabel(Resources res, int type,
+                    CharSequence label) {
+                if (type == TYPE_CUSTOM && !TextUtils.isEmpty(label)) {
+                    return label;
+                } else {
+                    final int labelRes = getTypeLabelResource(type);
+                    return res.getText(labelRes);
+                }
+            }
         }
 
         /**
          * Common data definition for IM addresses.
          */
-        public static final class Im implements BaseCommonColumns, CommonColumns {
+        public static final class Im implements DataColumnsWithJoins, CommonColumns {
             private Im() {}
 
             /** MIME type used when storing this in data table. */
@@ -1282,9 +1364,9 @@
              * column is {@link #PROTOCOL_CUSTOM}, the {@link #CUSTOM_PROTOCOL}
              * should contain the name of the custom protocol.
              */
-            public static final String PROTOCOL = "data5";
+            public static final String PROTOCOL = DATA5;
 
-            public static final String CUSTOM_PROTOCOL = "data6";
+            public static final String CUSTOM_PROTOCOL = DATA6;
 
             /*
              * The predefined IM protocol types.
@@ -1299,12 +1381,74 @@
             public static final int PROTOCOL_ICQ = 6;
             public static final int PROTOCOL_JABBER = 7;
             public static final int PROTOCOL_NETMEETING = 8;
+
+            /**
+             * Return the string resource that best describes the given
+             * {@link CommonColumns#TYPE}. Will always return a valid resource.
+             */
+            public static final int getTypeLabelResource(int type) {
+                switch (type) {
+                    case TYPE_HOME: return com.android.internal.R.string.imTypeHome;
+                    case TYPE_WORK: return com.android.internal.R.string.imTypeWork;
+                    case TYPE_OTHER: return com.android.internal.R.string.imTypeOther;
+                    default: return com.android.internal.R.string.imTypeCustom;
+                }
+            }
+
+            /**
+             * Return a {@link CharSequence} that best describes the given type,
+             * possibly substituting the given {@link CommonColumns#LABEL} value
+             * for {@link BaseTypes#TYPE_CUSTOM}.
+             */
+            public static final CharSequence getTypeLabel(Resources res, int type,
+                    CharSequence label) {
+                if (type == TYPE_CUSTOM && !TextUtils.isEmpty(label)) {
+                    return label;
+                } else {
+                    final int labelRes = getTypeLabelResource(type);
+                    return res.getText(labelRes);
+                }
+            }
+
+            /**
+             * Return the string resource that best describes the given
+             * {@link Im#PROTOCOL}. Will always return a valid resource.
+             */
+            public static final int getProtocolLabelResource(int type) {
+                switch (type) {
+                    case PROTOCOL_AIM: return com.android.internal.R.string.imProtocolAim;
+                    case PROTOCOL_MSN: return com.android.internal.R.string.imProtocolMsn;
+                    case PROTOCOL_YAHOO: return com.android.internal.R.string.imProtocolYahoo;
+                    case PROTOCOL_SKYPE: return com.android.internal.R.string.imProtocolSkype;
+                    case PROTOCOL_QQ: return com.android.internal.R.string.imProtocolQq;
+                    case PROTOCOL_GOOGLE_TALK: return com.android.internal.R.string.imProtocolGoogleTalk;
+                    case PROTOCOL_ICQ: return com.android.internal.R.string.imProtocolIcq;
+                    case PROTOCOL_JABBER: return com.android.internal.R.string.imProtocolJabber;
+                    case PROTOCOL_NETMEETING: return com.android.internal.R.string.imProtocolNetMeeting;
+                    default: return com.android.internal.R.string.imProtocolCustom;
+                }
+            }
+
+            /**
+             * Return a {@link CharSequence} that best describes the given
+             * protocol, possibly substituting the given
+             * {@link #CUSTOM_PROTOCOL} value for {@link #PROTOCOL_CUSTOM}.
+             */
+            public static final CharSequence getProtocolLabel(Resources res, int type,
+                    CharSequence label) {
+                if (type == PROTOCOL_CUSTOM && !TextUtils.isEmpty(label)) {
+                    return label;
+                } else {
+                    final int labelRes = getProtocolLabelResource(type);
+                    return res.getText(labelRes);
+                }
+            }
         }
 
         /**
          * Common data definition for organizations.
          */
-        public static final class Organization implements BaseCommonColumns, CommonColumns {
+        public static final class Organization implements DataColumnsWithJoins, CommonColumns {
             private Organization() {}
 
             /** MIME type used when storing this in data table. */
@@ -1323,37 +1467,64 @@
              * The position title at this company as the user entered it.
              * <P>Type: TEXT</P>
              */
-            public static final String TITLE = "data4";
+            public static final String TITLE = DATA4;
 
             /**
              * The department at this company as the user entered it.
              * <P>Type: TEXT</P>
              */
-            public static final String DEPARTMENT = "data5";
+            public static final String DEPARTMENT = DATA5;
 
             /**
              * The job description at this company as the user entered it.
              * <P>Type: TEXT</P>
              */
-            public static final String JOB_DESCRIPTION = "data6";
+            public static final String JOB_DESCRIPTION = DATA6;
 
             /**
              * The symbol of this company as the user entered it.
              * <P>Type: TEXT</P>
              */
-            public static final String SYMBOL = "data7";
+            public static final String SYMBOL = DATA7;
 
             /**
              * The phonetic name of this company as the user entered it.
              * <P>Type: TEXT</P>
              */
-            public static final String PHONETIC_NAME = "data8";
+            public static final String PHONETIC_NAME = DATA8;
+
+            /**
+             * Return the string resource that best describes the given
+             * {@link CommonColumns#TYPE}. Will always return a valid resource.
+             */
+            public static final int getTypeLabelResource(int type) {
+                switch (type) {
+                    case TYPE_WORK: return com.android.internal.R.string.orgTypeWork;
+                    case TYPE_OTHER: return com.android.internal.R.string.orgTypeOther;
+                    default: return com.android.internal.R.string.orgTypeCustom;
+                }
+            }
+
+            /**
+             * Return a {@link CharSequence} that best describes the given type,
+             * possibly substituting the given {@link CommonColumns#LABEL} value
+             * for {@link BaseTypes#TYPE_CUSTOM}.
+             */
+            public static final CharSequence getTypeLabel(Resources res, int type,
+                    CharSequence label) {
+                if (type == TYPE_CUSTOM && !TextUtils.isEmpty(label)) {
+                    return label;
+                } else {
+                    final int labelRes = getTypeLabelResource(type);
+                    return res.getText(labelRes);
+                }
+            }
         }
 
         /**
          * Common data definition for miscellaneous information.
          */
-        public static final class Miscellaneous implements BaseCommonColumns {
+        public static final class Miscellaneous implements DataColumnsWithJoins {
             private Miscellaneous() {}
 
             /** MIME type used when storing this in data table. */
@@ -1363,19 +1534,19 @@
              * The birthday as the user entered it.
              * <P>Type: TEXT</P>
              */
-            public static final String BIRTHDAY = "data1";
+            public static final String BIRTHDAY = DATA1;
 
             /**
              * The nickname as the user entered it.
              * <P>Type: TEXT</P>
              */
-            public static final String NICKNAME = "data2";
+            public static final String NICKNAME = DATA2;
         }
 
         /**
          * Common data definition for relations.
          */
-        public static final class Relation implements BaseCommonColumns, CommonColumns {
+        public static final class Relation implements DataColumnsWithJoins, CommonColumns {
             private Relation() {}
 
             /** MIME type used when storing this in data table. */
@@ -1406,7 +1577,7 @@
         /**
          * Common data definition for events.
          */
-        public static final class Event implements BaseCommonColumns, CommonColumns {
+        public static final class Event implements DataColumnsWithJoins, CommonColumns {
             private Event() {}
 
             /** MIME type used when storing this in data table. */
@@ -1425,7 +1596,7 @@
         /**
          * Photo of the contact.
          */
-        public static final class Photo implements BaseCommonColumns {
+        public static final class Photo implements DataColumnsWithJoins {
             private Photo() {}
 
             /** MIME type used when storing this in data table. */
@@ -1437,13 +1608,13 @@
              * <p>
              * Type: BLOB
              */
-            public static final String PHOTO = "data1";
+            public static final String PHOTO = DATA15;
         }
 
         /**
          * Notes about the contact.
          */
-        public static final class Note implements BaseCommonColumns {
+        public static final class Note implements DataColumnsWithJoins {
             private Note() {}
 
             /** MIME type used when storing this in data table. */
@@ -1453,13 +1624,13 @@
              * The note text.
              * <P>Type: TEXT</P>
              */
-            public static final String NOTE = "data1";
+            public static final String NOTE = DATA1;
         }
 
         /**
          * Group Membership.
          */
-        public static final class GroupMembership implements BaseCommonColumns {
+        public static final class GroupMembership implements DataColumnsWithJoins {
             private GroupMembership() {}
 
             /** MIME type used when storing this in data table. */
@@ -1471,7 +1642,7 @@
              * this or {@link #GROUP_SOURCE_ID} must be set when inserting a row.
              * <P>Type: INTEGER</P>
              */
-            public static final String GROUP_ROW_ID = "data1";
+            public static final String GROUP_ROW_ID = DATA1;
 
             /**
              * The sourceid of the group that this group membership refers to.  Exactly one of
@@ -1484,7 +1655,7 @@
         /**
          * Website related to the contact.
          */
-        public static final class Website implements BaseCommonColumns, CommonColumns {
+        public static final class Website implements DataColumnsWithJoins, CommonColumns {
             private Website() {}
 
             /** MIME type used when storing this in data table. */
@@ -1502,7 +1673,7 @@
              * The website URL string.
              * <P>Type: TEXT</P>
              */
-            public static final String URL = "data1";
+            public static final String URL = DATA;
         }
     }
 
@@ -1672,24 +1843,12 @@
          */
         public static final int TYPE_KEEP_TOGETHER = 1;
 
-        @Deprecated
-        public static final int TYPE_KEEP_IN = 1;
-
         /**
          * Makes sure that the specified raw contacts are NOT included in the same
          * aggregate contact.
          */
         public static final int TYPE_KEEP_SEPARATE = 2;
 
-        @Deprecated
-        public static final int TYPE_KEEP_OUT = 2;
-
-        @Deprecated
-        public static final String CONTACT_ID = "contact_id";
-
-        @Deprecated
-        public static final String RAW_CONTACT_ID = "raw_contact_id";
-
         /**
          * A reference to the {@link RawContacts#_ID} of the raw contact that the rule applies to.
          */
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 1d41df2..6cf8db6 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2406,7 +2406,6 @@
             WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY,
             WIFI_NUM_ALLOWED_CHANNELS,
             WIFI_NUM_OPEN_NETWORKS_KEPT,
-            BACKGROUND_DATA,
         };
 
         /**
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index ba53307..f3bc3a6 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -247,7 +247,6 @@
                 addDevice(address, properties);
             }
         }
-        mBluetoothService.getBondState().setBondState(address, BluetoothDevice.BOND_BONDING);
         return;
     }
 
@@ -266,8 +265,8 @@
         }
         String name = propValues[0];
         if (name.equals("Name")) {
-            Intent intent = new Intent(BluetoothDevice.ACTION_NAME_CHANGED);
-            intent.putExtra(BluetoothDevice.EXTRA_NAME, propValues[1]);
+            Intent intent = new Intent(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
+            intent.putExtra(BluetoothAdapter.EXTRA_LOCAL_NAME, propValues[1]);
             mContext.sendBroadcast(intent, BLUETOOTH_PERM);
             mBluetoothService.setProperty(name, propValues[1]);
         } else if (name.equals("Pairable") || name.equals("Discoverable")) {
@@ -330,6 +329,9 @@
             Log.e(TAG, "onDevicePropertyChanged: Address of the remote device in null");
             return;
         }
+        if (DBG) {
+            log("Device property changed:" + address + "property:" + name);
+        }
         BluetoothDevice device = mAdapter.getRemoteDevice(address);
         if (name.equals("Name")) {
             Intent intent = new Intent(BluetoothDevice.ACTION_NAME_CHANGED);
@@ -366,6 +368,11 @@
                 uuid = str.toString();
             }
             mBluetoothService.setRemoteDeviceProperty(address, name, uuid);
+
+            // UUIDs have changed, query remote service channel and update cache.
+            mBluetoothService.updateDeviceServiceChannelCache(address);
+
+            mBluetoothService.sendUuidIntent(address);
         } else if (name.equals("Paired")) {
             if (propValues[1].equals("true")) {
                 mBluetoothService.getBondState().setBondState(address, BluetoothDevice.BOND_BONDED);
@@ -396,6 +403,9 @@
             mBluetoothService.cancelPairingUserInput(address);
             return null;
         }
+        // Set state to BONDING, for incoming connections it will be set here.
+        // For outgoing connections, it gets set when call createBond.
+        mBluetoothService.getBondState().setBondState(address, BluetoothDevice.BOND_BONDING);
         return address;
     }
 
@@ -453,8 +463,9 @@
         String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
         if (address == null) return;
 
-        if (mBluetoothService.getBondState().getBondState(address) ==
-                BluetoothDevice.BOND_BONDING) {
+        String pendingOutgoingAddress =
+                mBluetoothService.getBondState().getPendingOutgoingBonding();
+        if (address.equals(pendingOutgoingAddress)) {
             // we initiated the bonding
             BluetoothClass btClass = new BluetoothClass(mBluetoothService.getRemoteClass(address));
 
@@ -528,6 +539,24 @@
         return;
     }
 
+    private void onDiscoverServicesResult(String deviceObjectPath, boolean result) {
+        String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
+        // We don't parse the xml here, instead just query Bluez for the properties.
+        if (result) {
+            mBluetoothService.updateRemoteDevicePropertiesCache(address);
+        }
+        mBluetoothService.sendUuidIntent(address);
+    }
+
+    private void onCreateDeviceResult(String address, boolean result) {
+        if (DBG) {
+            log("Result of onCreateDeviceResult:" + result);
+        }
+        if (!result) {
+            mBluetoothService.sendUuidIntent(address);
+        }
+    }
+
     private void onRestartRequired() {
         if (mBluetoothService.isEnabled()) {
             Log.e(TAG, "*** A serious error occured (did bluetoothd crash?) - " +
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index c0e4f34..e5b20bd 100644
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -28,6 +28,7 @@
 import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothUuid;
 import android.bluetooth.IBluetooth;
 import android.bluetooth.ParcelUuid;
 import android.content.BroadcastReceiver;
@@ -76,10 +77,18 @@
 
     private static final int MESSAGE_REGISTER_SDP_RECORDS = 1;
     private static final int MESSAGE_FINISH_DISABLE = 2;
+    private static final int MESSAGE_UUID_INTENT = 3;
+
+    // The timeout used to sent the UUIDs Intent
+    // This timeout should be greater than the page timeout
+    private static final int UUID_INTENT_DELAY = 6000;
 
     private final Map<String, String> mAdapterProperties;
     private final HashMap <String, Map<String, String>> mDeviceProperties;
 
+    private final HashMap <String, Map<ParcelUuid, Integer>> mDeviceServiceChannelCache;
+    private final ArrayList <String> mUuidIntentTracker;
+
     static {
         classInitNative();
     }
@@ -104,6 +113,9 @@
         mIsDiscovering = false;
         mAdapterProperties = new HashMap<String, String>();
         mDeviceProperties = new HashMap<String, Map<String,String>>();
+
+        mDeviceServiceChannelCache = new HashMap<String, Map<ParcelUuid, Integer>>();
+        mUuidIntentTracker = new ArrayList<String>();
         registerForAirplaneMode();
     }
 
@@ -291,6 +303,11 @@
             case MESSAGE_FINISH_DISABLE:
                 finishDisable(msg.arg1 != 0);
                 break;
+            case MESSAGE_UUID_INTENT:
+                String address = (String)msg.obj;
+                if (address != null)
+                    sendUuidIntent(address);
+                break;
             }
         }
     };
@@ -414,6 +431,18 @@
                 new ArrayList<String>(Arrays.asList(
                         "Motorola IHF1000", "i.TechBlueBAND", "X5 Stereo v1.3"));
 
+        // If this is an outgoing connection, store the address.
+        // There can be only 1 pending outgoing connection at a time,
+        private String mPendingOutgoingBonding;
+
+        private synchronized void setPendingOutgoingBonding(String address) {
+            mPendingOutgoingBonding = address;
+        }
+
+        public synchronized String getPendingOutgoingBonding() {
+            return mPendingOutgoingBonding;
+        }
+
         public synchronized void loadBondState() {
             if (mBluetoothState != BluetoothAdapter.STATE_TURNING_ON) {
                 return;
@@ -444,6 +473,15 @@
             if (oldState == state) {
                 return;
             }
+
+            // Check if this was an pending outgoing bonding.
+            // If yes, reset the state.
+            if (oldState == BluetoothDevice.BOND_BONDING) {
+                if (address.equals(mPendingOutgoingBonding)) {
+                    mPendingOutgoingBonding = null;
+                }
+            }
+
             if (DBG) log(address + " bond state " + oldState + " -> " + state + " (" +
                          reason + ")");
             Intent intent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
@@ -766,8 +804,7 @@
         }
         address = address.toUpperCase();
 
-        String[] bonding = mBondState.listInState(BluetoothDevice.BOND_BONDING);
-        if (bonding.length > 0 && !bonding[0].equals(address)) {
+        if (mBondState.getPendingOutgoingBonding() != null) {
             log("Ignoring createBond(): another device is bonding");
             // a different device is currently bonding, fail
             return false;
@@ -785,7 +822,9 @@
             return false;
         }
 
+        mBondState.setPendingOutgoingBonding(address);
         mBondState.setBondState(address, BluetoothDevice.BOND_BONDING);
+
         return true;
     }
 
@@ -845,16 +884,22 @@
             // Query for remote device properties, again.
             // We will need to reload the cache when we switch Bluetooth on / off
             // or if we crash.
-            String[] propValues = getRemoteDeviceProperties(address);
-            if (propValues != null) {
-                addRemoteDeviceProperties(address, propValues);
+            if (updateRemoteDevicePropertiesCache(address))
                 return getRemoteDeviceProperty(address, property);
-            }
         }
         Log.e(TAG, "getRemoteDeviceProperty: " + property + "not present:" + address);
         return null;
     }
 
+    /* package */ synchronized boolean updateRemoteDevicePropertiesCache(String address) {
+        String[] propValues = getRemoteDeviceProperties(address);
+        if (propValues != null) {
+            addRemoteDeviceProperties(address, propValues);
+            return true;
+        }
+        return false;
+    }
+
     /* package */ synchronized void addRemoteDeviceProperties(String address, String[] properties) {
         /*
          * We get a DeviceFound signal every time RSSI changes or name changes.
@@ -889,6 +934,10 @@
             propertyValues.put(name, newValue);
         }
         mDeviceProperties.put(address, propertyValues);
+
+        // We have added a new remote device or updated its properties.
+        // Also update the serviceChannel cache.
+        updateDeviceServiceChannelCache(address);
     }
 
     /* package */ void removeRemoteDeviceProperties(String address) {
@@ -976,6 +1025,10 @@
         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
             return null;
         }
+        return getUuidFromCache(address);
+    }
+
+    private ParcelUuid[] getUuidFromCache(String address) {
         String value = getRemoteDeviceProperty(address, "UUIDs");
         if (value == null) return null;
 
@@ -990,6 +1043,36 @@
         return uuids;
     }
 
+    public synchronized boolean fetchRemoteUuidsWithSdp(String address) {
+        mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
+            return false;
+        }
+
+        if (mUuidIntentTracker.contains(address)) {
+            // An SDP query for this address is already in progress
+            return true;
+        }
+
+        boolean ret;
+        if (getBondState(address) == BluetoothDevice.BOND_BONDED) {
+            String path = getObjectPathFromAddress(address);
+            if (path == null) return false;
+
+            // Use an empty string for the UUID pattern
+            ret = discoverServicesNative(path, "");
+        } else {
+            ret = createDeviceNative(address);
+        }
+
+        mUuidIntentTracker.add(address);
+
+        Message message = mHandler.obtainMessage(MESSAGE_UUID_INTENT);
+        message.obj = address;
+        mHandler.sendMessageDelayed(message, UUID_INTENT_DELAY);
+        return ret;
+    }
+
     /**
      * Gets the rfcomm channel associated with the UUID.
      *
@@ -997,14 +1080,23 @@
      * @param uuid ParcelUuid of the service attribute
      *
      * @return rfcomm channel associated with the service attribute
+     *         -1 on error
      */
     public int getRemoteServiceChannel(String address, ParcelUuid uuid) {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
             return BluetoothDevice.ERROR;
         }
-        return getDeviceServiceChannelNative(getObjectPathFromAddress(address), uuid.toString(),
-                0x0004);
+        // Check if we are recovering from a crash.
+        if (mDeviceProperties.isEmpty()) {
+            if (!updateRemoteDevicePropertiesCache(address))
+                return -1;
+        }
+
+        Map<ParcelUuid, Integer> value = mDeviceServiceChannelCache.get(address);
+        if (value != null && value.containsKey(uuid))
+            return value.get(uuid);
+        return -1;
     }
 
     public synchronized boolean setPin(String address, byte[] pin) {
@@ -1083,6 +1175,27 @@
         return cancelPairingUserInputNative(address, data.intValue());
     }
 
+    public void updateDeviceServiceChannelCache(String address) {
+        ParcelUuid[] deviceUuids = getRemoteUuids(address);
+        // We are storing the rfcomm channel numbers only for the uuids
+        // we are interested in.
+        int channel;
+        ParcelUuid[] interestedUuids = {BluetoothUuid.Handsfree,
+                                        BluetoothUuid.HSP,
+                                        BluetoothUuid.ObexObjectPush};
+
+        Map <ParcelUuid, Integer> value = new HashMap<ParcelUuid, Integer>();
+        for (ParcelUuid uuid: interestedUuids) {
+            if (BluetoothUuid.isUuidPresent(deviceUuids, uuid)) {
+                channel =
+                   getDeviceServiceChannelNative(getObjectPathFromAddress(address), uuid.toString(),
+                                                 0x0004);
+                value.put(uuid, channel);
+            }
+        }
+        mDeviceServiceChannelCache.put(address, value);
+    }
+
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -1121,6 +1234,18 @@
                 Settings.System.AIRPLANE_MODE_ON, 0) == 1;
     }
 
+    /* Broadcast the Uuid intent */
+    /*package*/ synchronized void sendUuidIntent(String address) {
+        ParcelUuid[] uuid = getUuidFromCache(address);
+        Intent intent = new Intent(BluetoothDevice.ACTION_UUID);
+        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
+        intent.putExtra(BluetoothDevice.EXTRA_UUID, uuid);
+        mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
+
+        if (mUuidIntentTracker.contains(address))
+            mUuidIntentTracker.remove(address);
+    }
+
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("\nmIsAirplaneSensitive = " + mIsAirplaneSensitive + "\n");
@@ -1284,4 +1409,7 @@
     private native boolean setPairingConfirmationNative(String address, boolean confirm,
             int nativeData);
     private native boolean setDevicePropertyBooleanNative(String objectPath, String key, int value);
+    private native boolean createDeviceNative(String address);
+    private native boolean discoverServicesNative(String objectPath, String pattern);
+
 }
diff --git a/core/java/android/text/format/Formatter.java b/core/java/android/text/format/Formatter.java
index 367b26c..baaa3ce 100644
--- a/core/java/android/text/format/Formatter.java
+++ b/core/java/android/text/format/Formatter.java
@@ -32,6 +32,18 @@
      * @return formated string with the number
      */
     public static String formatFileSize(Context context, long number) {
+        return formatFileSize(context, number, false);
+    }
+    
+    /**
+     * Like {@link #formatFileSize}, but trying to generate shorter numbers
+     * (showing fewer digits of precisin).
+     */
+    public static String formatShortFileSize(Context context, long number) {
+        return formatFileSize(context, number, true);
+    }
+    
+    private static String formatFileSize(Context context, long number, boolean shorter) {
         if (context == null) {
             return "";
         }
@@ -58,13 +70,24 @@
             suffix = com.android.internal.R.string.petabyteShort;
             result = result / 1024;
         }
-        if (result < 100) {
-            String value = String.format("%.2f", result);
-            return context.getResources().
-                getString(com.android.internal.R.string.fileSizeSuffix,
-                          value, context.getString(suffix));
+        String value;
+        if (result < 1) {
+            value = String.format("%.2f", result);
+        } else if (result < 10) {
+            if (shorter) {
+                value = String.format("%.1f", result);
+            } else {
+                value = String.format("%.2f", result);
+            }
+        } else if (result < 100) {
+            if (shorter) {
+                value = String.format("%.0f", result);
+            } else {
+                value = String.format("%.2f", result);
+            }
+        } else {
+            value = String.format("%.0f", result);
         }
-        String value = String.format("%.0f", result);
         return context.getResources().
             getString(com.android.internal.R.string.fileSizeSuffix,
                       value, context.getString(suffix));
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index f67c4aa..396e380 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -488,7 +488,10 @@
          * is locked. This will let application windows take precedence over
          * key guard or any other lock screens. Can be used with
          * {@link #FLAG_KEEP_SCREEN_ON} to turn screen on and display windows
-         * directly before showing the key guard window
+         * directly before showing the key guard window.  Can be used with
+         * {@link #FLAG_DISMISS_KEYGUARD} to automatically fully dismisss
+         * non-secure keyguards.  This flag only applies to the top-most
+         * full-screen window.
          */
         public static final int FLAG_SHOW_WHEN_LOCKED = 0x00080000;
 
@@ -506,6 +509,19 @@
          * up the device) to turn the screen on. */
         public static final int FLAG_TURN_SCREEN_ON = 0x00200000;
         
+        /** Window flag: when set the window will cause the keyguard to
+         * be dismissed, only if it is not a secure lock keyguard.  Because such
+         * a keyguard is not needed for security, it will never re-appear if
+         * the user navigates to another window (in contrast to
+         * {@link #FLAG_SHOW_WHEN_LOCKED}, which will only temporarily
+         * hide both secure and non-secure keyguards but ensure they reappear
+         * when the user moves to another UI that doesn't hide them).
+         * If the keyguard is currently active and is secure (requires an
+         * unlock pattern) than the user will still need to confirm it before
+         * seeing this window, unless {@link #FLAG_SHOW_WHEN_LOCKED} has
+         * also been set. */
+        public static final int FLAG_DISMISS_KEYGUARD = 0x00400000;
+        
         /** Window flag: special flag to limit the size of the window to be
          * original size ([320x480] x density). Used to create window for applications
          * running under compatibility mode.
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 45ff27e..1923743 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -314,7 +314,9 @@
         public boolean showLw(boolean doAnimation);
     }
 
-    /** No transition happening. */
+    /** Not set up for a transition. */
+    public final int TRANSIT_UNSET = 0;
+    /** No animation for transition. */
     public final int TRANSIT_NONE = 0;
     /** Window has been added to the screen. */
     public final int TRANSIT_ENTER = 1;
@@ -600,11 +602,18 @@
      * returned, all windows given to layoutWindow() <em>must</em> have had a
      * frame assigned.
      *  
-     * @return Return true if layout state may have changed (so that another 
-     *         layout will be performed).
+     * @return Return any bit set of {@link #FINISH_LAYOUT_REDO_LAYOUT}
+     * and {@link #FINISH_LAYOUT_REDO_CONFIG}.
      */
-    public boolean finishLayoutLw();
+    public int finishLayoutLw();
 
+    /** Layout state may have changed (so another layout will be performed) */
+    static final int FINISH_LAYOUT_REDO_LAYOUT = 0x0001;
+    /** Configuration state may have changed */
+    static final int FINISH_LAYOUT_REDO_CONFIG = 0x0002;
+    /** Wallpaper may need to move */
+    static final int FINISH_LAYOUT_REDO_WALLPAPER = 0x0004;
+    
     /**
      * Called when animation of the windows is about to start.
      * 
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index dbddb2e..e233a02 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -605,8 +605,8 @@
     }
 
     // Called by JNI when an apple-touch-icon attribute was found.
-    private void didReceiveTouchIconUrl(String url) {
-        mCallbackProxy.onReceivedTouchIconUrl(url);
+    private void didReceiveTouchIconUrl(String url, boolean precomposed) {
+        mCallbackProxy.onReceivedTouchIconUrl(url, precomposed);
     }
 
     /**
@@ -707,6 +707,10 @@
         return value.string.toString();
     }
 
+    private float density() {
+        return mContext.getResources().getDisplayMetrics().density;
+    }
+
     //==========================================================================
     // native functions
     //==========================================================================
diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
index b051675..1ec769b 100644
--- a/core/java/android/webkit/CallbackProxy.java
+++ b/core/java/android/webkit/CallbackProxy.java
@@ -249,7 +249,7 @@
             case RECEIVED_TOUCH_ICON_URL:
                 if (mWebChromeClient != null) {
                     mWebChromeClient.onReceivedTouchIconUrl(mWebView,
-                            (String) msg.obj);
+                            (String) msg.obj, msg.arg1 == 1);
                 }
                 break;
 
@@ -1065,19 +1065,22 @@
         sendMessage(obtainMessage(RECEIVED_ICON, icon));
     }
 
-    /* package */ void onReceivedTouchIconUrl(String url) {
+    /* package */ void onReceivedTouchIconUrl(String url, boolean precomposed) {
         // We should have a current item but we do not want to crash so check
         // for null.
         WebHistoryItem i = mBackForwardList.getCurrentItem();
         if (i != null) {
-            i.setTouchIconUrl(url);
+            if (precomposed || i.getTouchIconUrl() != null) {
+                i.setTouchIconUrl(url);
+            }
         }
         // Do an unsynchronized quick check to avoid posting if no callback has
         // been set.
         if (mWebChromeClient == null) {
             return;
         }
-        sendMessage(obtainMessage(RECEIVED_TOUCH_ICON_URL, url));
+        sendMessage(obtainMessage(RECEIVED_TOUCH_ICON_URL,
+                precomposed ? 1 : 0, 0, url));
     }
 
     public void onReceivedTitle(String title) {
diff --git a/core/java/android/webkit/GeolocationPermissions.java b/core/java/android/webkit/GeolocationPermissions.java
index e985ccc..c0cac01 100755
--- a/core/java/android/webkit/GeolocationPermissions.java
+++ b/core/java/android/webkit/GeolocationPermissions.java
@@ -19,10 +19,9 @@
 import android.os.Handler;
 import android.os.Message;
 import android.util.Log;
-import java.util.concurrent.locks.Condition;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
+import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Map;
 import java.util.Set;
 
 
@@ -47,15 +46,13 @@
     private static GeolocationPermissions sInstance;
 
     private Handler mHandler;
+    private Handler mUIHandler;
 
     // Members used to transfer the origins and permissions between threads.
     private Set<String> mOrigins;
     private boolean mAllowed;
     private Set<String> mOriginsToClear;
     private Set<String> mOriginsToAllow;
-    private static Lock mLock = new ReentrantLock();
-    private static boolean mUpdated;
-    private static Condition mUpdatedCondition = mLock.newCondition();
 
     // Message ids
     static final int GET_ORIGINS = 0;
@@ -64,6 +61,15 @@
     static final int ALLOW = 3;
     static final int CLEAR_ALL = 4;
 
+    // Message ids on the UI thread
+    static final int RETURN_ORIGINS = 0;
+    static final int RETURN_ALLOWED = 1;
+
+    private static final String ORIGINS = "origins";
+    private static final String ORIGIN = "origin";
+    private static final String CALLBACK = "callback";
+    private static final String ALLOWED = "allowed";
+
     /**
      * Gets the singleton instance of the class.
      */
@@ -75,22 +81,62 @@
     }
 
     /**
+     * Creates the UI message handler. Must be called on the UI thread.
+     */
+    public void createUIHandler() {
+        if (mUIHandler == null) {
+            mUIHandler = new Handler() {
+                @Override
+                public void handleMessage(Message msg) {
+                    // Runs on the UI thread.
+                    switch (msg.what) {
+                        case RETURN_ORIGINS: {
+                            Map values = (Map) msg.obj;
+                            Set origins = (Set) values.get(ORIGINS);
+                            ValueCallback<Set> callback = (ValueCallback<Set>) values.get(CALLBACK);
+                            callback.onReceiveValue(origins);
+                        } break;
+                        case RETURN_ALLOWED: {
+                            Map values = (Map) msg.obj;
+                            Boolean allowed = (Boolean) values.get(ALLOWED);
+                            ValueCallback<Boolean> callback = (ValueCallback<Boolean>) values.get(CALLBACK);
+                            callback.onReceiveValue(allowed);
+                        } break;
+                    }
+                }
+            };
+        }
+    }
+
+    /**
      * Creates the message handler. Must be called on the WebKit thread.
      */
     public void createHandler() {
-        mLock.lock();
         if (mHandler == null) {
             mHandler = new Handler() {
                 @Override
                 public void handleMessage(Message msg) {
                     // Runs on the WebKit thread.
                     switch (msg.what) {
-                        case GET_ORIGINS:
+                        case GET_ORIGINS: {
                             getOriginsImpl();
-                            break;
-                        case GET_ALLOWED:
-                            getAllowedImpl((String) msg.obj);
-                            break;
+                            ValueCallback callback = (ValueCallback) msg.obj;
+                            Set origins = new HashSet(mOrigins);
+                            Map values = new HashMap<String, Object>();
+                            values.put(CALLBACK, callback);
+                            values.put(ORIGINS, origins);
+                            postUIMessage(Message.obtain(null, RETURN_ORIGINS, values));
+                            } break;
+                        case GET_ALLOWED: {
+                            Map values = (Map) msg.obj;
+                            String origin = (String) values.get(ORIGIN);
+                            ValueCallback callback = (ValueCallback) values.get(CALLBACK);
+                            getAllowedImpl(origin);
+                            Map retValues = new HashMap<String, Object>();
+                            retValues.put(CALLBACK, callback);
+                            retValues.put(ALLOWED, new Boolean(mAllowed));
+                            postUIMessage(Message.obtain(null, RETURN_ALLOWED, retValues));
+                            } break;
                         case CLEAR:
                             nativeClear((String) msg.obj);
                             break;
@@ -115,7 +161,6 @@
                 }
             }
         }
-        mLock.unlock();
     }
 
     /**
@@ -127,29 +172,31 @@
     }
 
     /**
+     * Utility function to send a message to the handler on the UI thread
+     */
+    private void postUIMessage(Message msg) {
+        if (mUIHandler != null) {
+            mUIHandler.sendMessage(msg);
+        }
+    }
+
+    /**
      * Gets the set of origins for which Geolocation permissions are stored.
      * Note that we represent the origins as strings. These are created using
      * WebCore::SecurityOrigin::toString(). As long as all 'HTML 5 modules'
      * (Database, Geolocation etc) do so, it's safe to match up origins for the
      * purposes of displaying UI.
      */
-    public Set getOrigins() {
-        // Called on the UI thread.
-        Set origins = null;
-        mLock.lock();
-        try {
-            mUpdated = false;
-            postMessage(Message.obtain(null, GET_ORIGINS));
-            while (!mUpdated) {
-                mUpdatedCondition.await();
+    public void getOrigins(ValueCallback<Set> callback) {
+        if (callback != null) {
+            if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
+                getOriginsImpl();
+                Set origins = new HashSet(mOrigins);
+                callback.onReceiveValue(origins);
+            } else {
+                postMessage(Message.obtain(null, GET_ORIGINS, callback));
             }
-            origins = mOrigins;
-        } catch (InterruptedException e) {
-            Log.e(TAG, "Exception while waiting for update", e);
-        } finally {
-            mLock.unlock();
         }
-        return origins;
     }
 
     /**
@@ -157,33 +204,29 @@
      */
     private void getOriginsImpl() {
         // Called on the WebKit thread.
-        mLock.lock();
         mOrigins = nativeGetOrigins();
-        mUpdated = true;
-        mUpdatedCondition.signal();
-        mLock.unlock();
     }
 
     /**
      * Gets the permission state for the specified origin.
      */
-    public boolean getAllowed(String origin) {
-        // Called on the UI thread.
-        boolean allowed = false;
-        mLock.lock();
-        try {
-            mUpdated = false;
-            postMessage(Message.obtain(null, GET_ALLOWED, origin));
-            while (!mUpdated) {
-                mUpdatedCondition.await();
-            }
-            allowed = mAllowed;
-        } catch (InterruptedException e) {
-            Log.e(TAG, "Exception while waiting for update", e);
-        } finally {
-            mLock.unlock();
+    public void getAllowed(String origin, ValueCallback<Boolean> callback) {
+        if (callback == null) {
+            return;
         }
-        return allowed;
+        if (origin == null) {
+            callback.onReceiveValue(null);
+            return;
+        }
+        if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
+            getAllowedImpl(origin);
+            callback.onReceiveValue(new Boolean(mAllowed));
+        } else {
+            Map values = new HashMap<String, Object>();
+            values.put(ORIGIN, origin);
+            values.put(CALLBACK, callback);
+            postMessage(Message.obtain(null, GET_ALLOWED, values));
+        }
     }
 
     /**
@@ -191,11 +234,7 @@
      */
     private void getAllowedImpl(String origin) {
         // Called on the WebKit thread.
-        mLock.lock();
         mAllowed = nativeGetAllowed(origin);
-        mUpdated = true;
-        mUpdatedCondition.signal();
-        mLock.unlock();
     }
 
     /**
@@ -205,7 +244,6 @@
      */
     public void clear(String origin) {
         // Called on the UI thread.
-        mLock.lock();
         if (mHandler == null) {
             if (mOriginsToClear == null) {
                 mOriginsToClear = new HashSet<String>();
@@ -217,7 +255,6 @@
         } else {
             postMessage(Message.obtain(null, CLEAR, origin));
         }
-        mLock.unlock();
     }
 
     /**
@@ -227,7 +264,6 @@
      */
     public void allow(String origin) {
         // Called on the UI thread.
-        mLock.lock();
         if (mHandler == null) {
             if (mOriginsToAllow == null) {
                 mOriginsToAllow = new HashSet<String>();
@@ -239,7 +275,6 @@
         } else {
             postMessage(Message.obtain(null, ALLOW, origin));
         }
-        mLock.unlock();
     }
 
     /**
diff --git a/core/java/android/webkit/GoogleLocationSettingManager.java b/core/java/android/webkit/GoogleLocationSettingManager.java
index fe7fce6..1b6e77c 100644
--- a/core/java/android/webkit/GoogleLocationSettingManager.java
+++ b/core/java/android/webkit/GoogleLocationSettingManager.java
@@ -35,8 +35,6 @@
  * @hide pending API council review
  */
 class GoogleLocationSettingManager {
-    // The application context.
-    private Context mContext;
     // The observer used to listen to the system setting.
     private GoogleLocationSettingObserver mSettingObserver;
 
@@ -48,6 +46,8 @@
     // by the browser.
     private final static String LAST_READ_USE_LOCATION_FOR_SERVICES =
             "lastReadUseLocationForServices";
+    // The Browser package name.
+    private static final String BROWSER_PACKAGE_NAME = "com.android.browser";
     // The Google origins we consider.
     private static HashSet<String> sGoogleOrigins;
     static {
@@ -57,38 +57,72 @@
         sGoogleOrigins.add("http://www.google.co.uk");
     }
 
-    GoogleLocationSettingManager(Context context) {
-        mContext = context;
+    private static GoogleLocationSettingManager sGoogleLocationSettingManager = null;
+    private static int sRefCount = 0;
+
+    static GoogleLocationSettingManager getInstance() {
+        if (sGoogleLocationSettingManager == null) {
+            sGoogleLocationSettingManager = new GoogleLocationSettingManager();
+        }
+        return sGoogleLocationSettingManager;
     }
 
+    private GoogleLocationSettingManager() {}
+
     /**
      * Starts the manager. Checks whether the setting has changed and
      * installs an observer to listen for future changes.
      */
-    public void start() {
-        maybeApplySetting();
-
+    public void start(Context context) {
+        // Are we running in the browser?
+        if (context == null || !BROWSER_PACKAGE_NAME.equals(context.getPackageName())) {
+            return;
+        }
+        // Increase the refCount
+        sRefCount++;
+        // Are we already registered?
+        if (mSettingObserver != null) {
+            return;
+        }
+        // Read and apply the settings if needed.
+        maybeApplySetting(context);
+        // Register to receive notifications when the system settings change.
         mSettingObserver = new GoogleLocationSettingObserver();
-        mSettingObserver.observe();
+        mSettingObserver.observe(context);
     }
 
     /**
+     * Stops the manager.
+     */
+    public void stop() {
+        // Are we already registered?
+        if (mSettingObserver == null) {
+            return;
+        }
+        if (--sRefCount == 0) {
+            mSettingObserver.doNotObserve();
+            mSettingObserver = null;
+        }
+    }
+    /**
      * Checks to see if the system setting has changed and if so,
      * updates the Geolocation permissions accordingly.
+     * @param the Application context
      */
-    private void maybeApplySetting() {
-        int setting = getSystemSetting();
-        if (settingChanged(setting)) {
+    private void maybeApplySetting(Context context) {
+        int setting = getSystemSetting(context);
+        if (settingChanged(setting, context)) {
             applySetting(setting);
         }
     }
 
     /**
      * Gets the current system setting for 'Use location for Google services'.
+     * @param the Application context
      * @return The system setting.
      */
-    private int getSystemSetting() {
-        return Settings.Secure.getInt(mContext.getContentResolver(),
+    private int getSystemSetting(Context context) {
+        return Settings.Secure.getInt(context.getContentResolver(),
                                       Settings.Secure.USE_LOCATION_FOR_SERVICES,
                                       sSystemSettingFalse);
     }
@@ -97,12 +131,13 @@
      * Determines whether the supplied setting has changed from the last
      * value read by the browser.
      * @param setting The setting.
+     * @param the Application context
      * @return Whether the setting has changed from the last value read
      *     by the browser.
      */
-    private boolean settingChanged(int setting) {
+    private boolean settingChanged(int setting, Context context) {
         SharedPreferences preferences =
-                PreferenceManager.getDefaultSharedPreferences(mContext);
+                PreferenceManager.getDefaultSharedPreferences(context);
         // Default to false. If the system setting is false the first time it is ever read by the
         // browser, there's nothing to do.
         int lastReadSetting = sSystemSettingFalse;
@@ -137,20 +172,35 @@
      * This class implements an observer to listen for changes to the
      * system setting.
      */
-    class GoogleLocationSettingObserver extends ContentObserver {
+    private class GoogleLocationSettingObserver extends ContentObserver {
+        private Context mContext;
+
         GoogleLocationSettingObserver() {
             super(new Handler());
         }
 
-        void observe() {
-            ContentResolver resolver = mContext.getContentResolver();
+        void observe(Context context) {
+            if (mContext != null) {
+                return;
+            }
+            ContentResolver resolver = context.getContentResolver();
             resolver.registerContentObserver(Settings.Secure.getUriFor(
                 Settings.Secure.USE_LOCATION_FOR_SERVICES), false, this);
+            mContext = context;
+        }
+
+        void doNotObserve() {
+            if (mContext == null) {
+                return;
+            }
+            ContentResolver resolver = mContext.getContentResolver();
+            resolver.unregisterContentObserver(this);
+            mContext = null;
         }
 
         @Override
         public void onChange(boolean selfChange) {
-            maybeApplySetting();
+            maybeApplySetting(mContext);
         }
     }
 }
diff --git a/core/java/android/webkit/PluginManager.java b/core/java/android/webkit/PluginManager.java
index 32eea5f..766bd75 100644
--- a/core/java/android/webkit/PluginManager.java
+++ b/core/java/android/webkit/PluginManager.java
@@ -63,8 +63,11 @@
 
     private final Context mContext;
 
+    private ArrayList<PackageInfo> mPackageInfoCache;
+
     private PluginManager(Context context) {
         mContext = context;
+        mPackageInfoCache = new ArrayList<PackageInfo>();
     }
 
     public static synchronized PluginManager getInstance(Context context) {
@@ -92,65 +95,94 @@
     }
 
     String[] getPluginDirectories() {
+
         ArrayList<String> directories = new ArrayList<String>();
         PackageManager pm = mContext.getPackageManager();
         List<ResolveInfo> plugins = pm.queryIntentServices(new Intent(
                 PLUGIN_ACTION), PackageManager.GET_SERVICES);
-        for (ResolveInfo info : plugins) {
-            ServiceInfo serviceInfo = info.serviceInfo;
-            if (serviceInfo == null) {
-                Log.w(LOGTAG, "Ignore bad plugin");
-                continue;
-            }
-            PackageInfo pkgInfo;
-            try {
-                pkgInfo = pm.getPackageInfo(serviceInfo.packageName,
-                        PackageManager.GET_PERMISSIONS
-                                | PackageManager.GET_SIGNATURES);
-            } catch (NameNotFoundException e) {
-                Log.w(LOGTAG, "Cant find plugin: " + serviceInfo.packageName);
-                continue;
-            }
-            if (pkgInfo == null) {
-                continue;
-            }
-            String directory = pkgInfo.applicationInfo.dataDir + "/lib";
-            if (directories.contains(directory)) {
-                continue;
-            }
-            String permissions[] = pkgInfo.requestedPermissions;
-            if (permissions == null) {
-                continue;
-            }
-            boolean permissionOk = false;
-            for (String permit : permissions) {
-                if (PLUGIN_PERMISSION.equals(permit)) {
-                    permissionOk = true;
+
+        synchronized(mPackageInfoCache) {
+
+            // clear the list of existing packageInfo objects
+            mPackageInfoCache.clear();
+
+            for (ResolveInfo info : plugins) {
+                ServiceInfo serviceInfo = info.serviceInfo;
+                if (serviceInfo == null) {
+                    Log.w(LOGTAG, "Ignore bad plugin");
+                    continue;
+                }
+                PackageInfo pkgInfo;
+                try {
+                    pkgInfo = pm.getPackageInfo(serviceInfo.packageName,
+                                    PackageManager.GET_PERMISSIONS
+                                    | PackageManager.GET_SIGNATURES);
+                } catch (NameNotFoundException e) {
+                    Log.w(LOGTAG, "Cant find plugin: " + serviceInfo.packageName);
+                    continue;
+                }
+                if (pkgInfo == null) {
+                    continue;
+                }
+                String directory = pkgInfo.applicationInfo.dataDir + "/lib";
+                if (directories.contains(directory)) {
+                    continue;
+                }
+                String permissions[] = pkgInfo.requestedPermissions;
+                if (permissions == null) {
+                    continue;
+                }
+                boolean permissionOk = false;
+                for (String permit : permissions) {
+                    if (PLUGIN_PERMISSION.equals(permit)) {
+                        permissionOk = true;
+                        break;
+                    }
+                }
+                if (!permissionOk) {
+                    continue;
+                }
+                Signature signatures[] = pkgInfo.signatures;
+                if (signatures == null) {
+                    continue;
+                }
+                boolean signatureMatch = false;
+                for (Signature signature : signatures) {
+                    // TODO: check signature against Google provided one
+                    signatureMatch = true;
                     break;
                 }
+                if (!signatureMatch) {
+                    continue;
+                }
+                mPackageInfoCache.add(pkgInfo);
+                directories.add(directory);
             }
-            if (!permissionOk) {
-                continue;
-            }
-            Signature signatures[] = pkgInfo.signatures;
-            if (signatures == null) {
-                continue;
-            }
-            boolean signatureMatch = false;
-            for (Signature signature : signatures) {
-                // TODO: check signature against Google provided one
-                signatureMatch = true;
-                break;
-            }
-            if (!signatureMatch) {
-                continue;
-            }
-            directories.add(directory);
         }
 
         return directories.toArray(new String[directories.size()]);
     }
 
+    String getPluginsAPKName(String pluginLib) {
+
+        // basic error checking on input params
+        if (pluginLib == null || pluginLib.length() == 0) {
+            return null;
+        }
+
+        // must be synchronized to ensure the consistency of the cache
+        synchronized(mPackageInfoCache) {
+            for (PackageInfo pkgInfo : mPackageInfoCache) {
+                if (pluginLib.startsWith(pkgInfo.applicationInfo.dataDir)) {
+                    return pkgInfo.packageName;
+                }
+            }
+        }
+
+        // if no apk was found then return null
+        return null;
+    }
+
     String getPluginSharedDataDirectory() {
         return mContext.getDir("plugins", 0).getPath();
     }
diff --git a/core/java/android/webkit/ValueCallback.java b/core/java/android/webkit/ValueCallback.java
new file mode 100644
index 0000000..d8c5cdc
--- /dev/null
+++ b/core/java/android/webkit/ValueCallback.java
@@ -0,0 +1,29 @@
+/*
+ * 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;
+
+/**
+ * A callback interface used to returns values asynchronously
+ *
+ * @hide pending council approval
+ */
+public interface ValueCallback<T>  {
+  /**
+   * Invoked when we have the result
+   */
+  public void onReceiveValue(T value);
+};
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 0e08514..1ae1d85 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -48,9 +48,11 @@
      * Notify the host application of the url for an apple-touch-icon.
      * @param view The WebView that initiated the callback.
      * @param url The icon url.
+     * @param precomposed True if the url is for a precomposed touch icon.
      * @hide pending council approval
      */
-    public void onReceivedTouchIconUrl(WebView view, String url) {}
+    public void onReceivedTouchIconUrl(WebView view, String url,
+            boolean precomposed) {}
 
     /**
      * A callback interface used by the host application to notify
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 196bbd7..0cfcb95 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -17,6 +17,7 @@
 package android.webkit;
 
 import android.content.Context;
+import android.content.SharedPreferences;
 import android.content.pm.PackageManager;
 import android.os.Build;
 import android.os.Handler;
@@ -189,9 +190,11 @@
     private boolean         mAllowFileAccess = true;
     private boolean         mLoadWithOverviewMode = false;
 
-    // Manages interaction of the system setting 'Location & security - Share
-    // with Google' and the browser.
-    static GoogleLocationSettingManager sGoogleLocationSettingManager;
+    // private WebSettings, not accessible by the host activity
+    static private int      mDoubleTapToastCount = 3;
+
+    private static final String PREF_FILE = "WebViewSettings";
+    private static final String DOUBLE_TAP_TOAST_COUNT = "double_tap_toast_count";
 
     // Class to handle messages before WebCore is ready.
     private class EventHandler {
@@ -199,6 +202,8 @@
         static final int SYNC = 0;
         // Message id for setting priority
         static final int PRIORITY = 1;
+        // Message id for writing double-tap toast count
+        static final int SET_DOUBLE_TAP_TOAST_COUNT = 2;
         // Actual WebCore thread handler
         private Handler mHandler;
 
@@ -224,6 +229,16 @@
                             setRenderPriority();
                             break;
                         }
+
+                        case SET_DOUBLE_TAP_TOAST_COUNT: {
+                            SharedPreferences.Editor editor = mContext
+                                    .getSharedPreferences(PREF_FILE,
+                                            Context.MODE_PRIVATE).edit();
+                            editor.putInt(DOUBLE_TAP_TOAST_COUNT,
+                                    mDoubleTapToastCount);
+                            editor.commit();
+                            break;
+                        }
                     }
                 }
             };
@@ -1311,6 +1326,19 @@
         }
      }
 
+    int getDoubleTapToastCount() {
+        return mDoubleTapToastCount;
+    }
+
+    void setDoubleTapToastCount(int count) {
+        if (mDoubleTapToastCount != count) {
+            mDoubleTapToastCount = count;
+            // write the settings in the non-UI thread
+            mEventHandler.sendMessage(Message.obtain(null,
+                    EventHandler.SET_DOUBLE_TAP_TOAST_COUNT));
+        }
+    }
+
     /**
      * Transfer messages from the queue to the new WebCoreThread. Called from
      * WebCore thread.
@@ -1321,13 +1349,28 @@
         if (DebugFlags.WEB_SETTINGS) {
             junit.framework.Assert.assertTrue(frame.mNativeFrame != 0);
         }
-        sGoogleLocationSettingManager = new GoogleLocationSettingManager(mContext);
-        sGoogleLocationSettingManager.start();
+
+        GoogleLocationSettingManager.getInstance().start(mContext);
+
+        SharedPreferences sp = mContext.getSharedPreferences(PREF_FILE,
+                Context.MODE_PRIVATE);
+        if (mDoubleTapToastCount > 0) {
+            mDoubleTapToastCount = sp.getInt(DOUBLE_TAP_TOAST_COUNT,
+                    mDoubleTapToastCount);
+        }
         nativeSync(frame.mNativeFrame);
         mSyncPending = false;
         mEventHandler.createHandler();
     }
 
+    /**
+     * Let the Settings object know that our owner is being destroyed.
+     */
+    /*package*/
+    synchronized void onDestroyed() {
+        GoogleLocationSettingManager.getInstance().stop();
+    }
+
     private int pin(int size) {
         // FIXME: 72 is just an arbitrary max text size value.
         if (size < 1) {
diff --git a/core/java/android/webkit/WebStorage.java b/core/java/android/webkit/WebStorage.java
index ae560fb..0022248 100644
--- a/core/java/android/webkit/WebStorage.java
+++ b/core/java/android/webkit/WebStorage.java
@@ -20,9 +20,8 @@
 import android.os.Message;
 import android.util.Log;
 
-import java.util.concurrent.locks.Condition;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
+import java.util.Collection;
+import java.util.Map;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -51,28 +50,41 @@
     // Global instance of a WebStorage
     private static WebStorage sWebStorage;
 
-    // We keep the origins, quotas and usages as member values
-    // that we protect via a lock and update in syncValues().
-    // This is needed to transfer this data across threads.
-    private static Lock mLock = new ReentrantLock();
-    private static Condition mUpdateCondition = mLock.newCondition();
-    private static boolean mUpdateAvailable;
-
     // Message ids
     static final int UPDATE = 0;
     static final int SET_QUOTA_ORIGIN = 1;
     static final int DELETE_ORIGIN = 2;
     static final int DELETE_ALL = 3;
+    static final int GET_ORIGINS = 4;
+    static final int GET_USAGE_ORIGIN = 5;
+    static final int GET_QUOTA_ORIGIN = 6;
 
-    private Set <String> mOrigins;
-    private HashMap <String, Long> mQuotas = new HashMap<String, Long>();
-    private HashMap <String, Long> mUsages = new HashMap<String, Long>();
+    // Message ids on the UI thread
+    static final int RETURN_ORIGINS = 0;
+    static final int RETURN_USAGE_ORIGIN = 1;
+    static final int RETURN_QUOTA_ORIGIN = 2;
+
+    private static final String ORIGINS = "origins";
+    private static final String ORIGIN = "origin";
+    private static final String CALLBACK = "callback";
+    private static final String USAGE = "usage";
+    private static final String QUOTA = "quota";
+
+    private Map <String, Origin> mOrigins;
 
     private Handler mHandler = null;
+    private Handler mUIHandler = null;
 
-    private static class Origin {
+    static class Origin {
         String mOrigin = null;
         long mQuota = 0;
+        long mUsage = 0;
+
+        public Origin(String origin, long quota, long usage) {
+            mOrigin = origin;
+            mQuota = quota;
+            mUsage = usage;
+        }
 
         public Origin(String origin, long quota) {
             mOrigin = origin;
@@ -90,11 +102,49 @@
         public long getQuota() {
             return mQuota;
         }
+
+        public long getUsage() {
+            return mUsage;
+        }
     }
 
     /**
      * @hide
-     * Message handler
+     * Message handler, UI side
+     */
+    public void createUIHandler() {
+        if (mUIHandler == null) {
+            mUIHandler = new Handler() {
+                @Override
+                public void handleMessage(Message msg) {
+                    switch (msg.what) {
+                        case RETURN_ORIGINS: {
+                            Map values = (Map) msg.obj;
+                            Map origins = (Map) values.get(ORIGINS);
+                            ValueCallback<Map> callback = (ValueCallback<Map>) values.get(CALLBACK);
+                            callback.onReceiveValue(origins);
+                            } break;
+
+                        case RETURN_USAGE_ORIGIN: {
+                            Map values = (Map) msg.obj;
+                            ValueCallback<Long> callback = (ValueCallback<Long>) values.get(CALLBACK);
+                            callback.onReceiveValue((Long)values.get(USAGE));
+                            } break;
+
+                        case RETURN_QUOTA_ORIGIN: {
+                            Map values = (Map) msg.obj;
+                            ValueCallback<Long> callback = (ValueCallback<Long>) values.get(CALLBACK);
+                            callback.onReceiveValue((Long)values.get(QUOTA));
+                            } break;
+                    }
+                }
+            };
+        }
+    }
+
+    /**
+     * @hide
+     * Message handler, webcore side
      */
     public void createHandler() {
         if (mHandler == null) {
@@ -117,6 +167,46 @@
                             nativeDeleteAllData();
                             break;
 
+                        case GET_ORIGINS: {
+                            syncValues();
+                            ValueCallback callback = (ValueCallback) msg.obj;
+                            Map origins = new HashMap(mOrigins);
+                            Map values = new HashMap<String, Object>();
+                            values.put(CALLBACK, callback);
+                            values.put(ORIGINS, origins);
+                            postUIMessage(Message.obtain(null, RETURN_ORIGINS, values));
+                            } break;
+
+                        case GET_USAGE_ORIGIN: {
+                            syncValues();
+                            Map values = (Map) msg.obj;
+                            String origin = (String) values.get(ORIGIN);
+                            ValueCallback callback = (ValueCallback) values.get(CALLBACK);
+                            Origin website = mOrigins.get(origin);
+                            Map retValues = new HashMap<String, Object>();
+                            retValues.put(CALLBACK, callback);
+                            if (website != null) {
+                                long usage = website.getUsage();
+                                retValues.put(USAGE, new Long(usage));
+                            }
+                            postUIMessage(Message.obtain(null, RETURN_USAGE_ORIGIN, retValues));
+                            } break;
+
+                        case GET_QUOTA_ORIGIN: {
+                            syncValues();
+                            Map values = (Map) msg.obj;
+                            String origin = (String) values.get(ORIGIN);
+                            ValueCallback callback = (ValueCallback) values.get(CALLBACK);
+                            Origin website = mOrigins.get(origin);
+                            Map retValues = new HashMap<String, Object>();
+                            retValues.put(CALLBACK, callback);
+                            if (website != null) {
+                                long quota = website.getQuota();
+                                retValues.put(QUOTA, new Long(quota));
+                            }
+                            postUIMessage(Message.obtain(null, RETURN_QUOTA_ORIGIN, retValues));
+                            } break;
+
                         case UPDATE:
                             syncValues();
                             break;
@@ -126,82 +216,91 @@
         }
     }
 
+    /*
+     * When calling getOrigins(), getUsageForOrigin() and getQuotaForOrigin(),
+     * we need to get the values from webcore, but we cannot block while doing so
+     * as we used to do, as this could result in a full deadlock (other webcore
+     * messages received while we are still blocked here, see http://b/2127737).
+     *
+     * We have to do everything asynchronously, by providing a callback function.
+     * We post a message on the webcore thread (mHandler) that will get the result
+     * from webcore, and we post it back on the UI thread (using mUIHandler).
+     * We can then use the callback function to return the value.
+     */
+
     /**
      * @hide
      * Returns a list of origins having a database
      */
-    public Set getOrigins() {
-        Set ret = null;
-        mLock.lock();
-        try {
-            mUpdateAvailable = false;
-            update();
-            while (!mUpdateAvailable) {
-                mUpdateCondition.await();
+    public void getOrigins(ValueCallback<Map> callback) {
+        if (callback != null) {
+            if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
+                syncValues();
+                callback.onReceiveValue(mOrigins);
+            } else {
+                postMessage(Message.obtain(null, GET_ORIGINS, callback));
             }
-            ret = mOrigins;
-        } catch (InterruptedException e) {
-            Log.e(TAG, "Exception while waiting on the updated origins", e);
-        } finally {
-            mLock.unlock();
         }
-        return ret;
+    }
+
+    /**
+     * Returns a list of origins having a database
+     * should only be called from WebViewCore.
+     */
+    Collection<Origin> getOriginsSync() {
+        if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
+            update();
+            return mOrigins.values();
+        }
+        return null;
     }
 
     /**
      * @hide
      * Returns the use for a given origin
      */
-    public long getUsageForOrigin(String origin) {
-        long ret = 0;
+    public void getUsageForOrigin(String origin, ValueCallback<Long> callback) {
+        if (callback == null) {
+            return;
+        }
         if (origin == null) {
-          return ret;
+            callback.onReceiveValue(null);
+            return;
         }
-        mLock.lock();
-        try {
-            mUpdateAvailable = false;
-            update();
-            while (!mUpdateAvailable) {
-                mUpdateCondition.await();
-            }
-            Long usage = mUsages.get(origin);
-            if (usage != null) {
-                ret = usage.longValue();
-            }
-        } catch (InterruptedException e) {
-            Log.e(TAG, "Exception while waiting on the updated origins", e);
-        } finally {
-            mLock.unlock();
+        if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
+            syncValues();
+            Origin website = mOrigins.get(origin);
+            callback.onReceiveValue(new Long(website.getUsage()));
+        } else {
+            HashMap values = new HashMap<String, Object>();
+            values.put(ORIGIN, origin);
+            values.put(CALLBACK, callback);
+            postMessage(Message.obtain(null, GET_USAGE_ORIGIN, values));
         }
-        return ret;
     }
 
     /**
      * @hide
      * Returns the quota for a given origin
      */
-    public long getQuotaForOrigin(String origin) {
-        long ret = 0;
+    public void getQuotaForOrigin(String origin, ValueCallback<Long> callback) {
+        if (callback == null) {
+            return;
+        }
         if (origin == null) {
-          return ret;
+            callback.onReceiveValue(null);
+            return;
         }
-        mLock.lock();
-        try {
-            mUpdateAvailable = false;
-            update();
-            while (!mUpdateAvailable) {
-                mUpdateCondition.await();
-            }
-            Long quota = mQuotas.get(origin);
-            if (quota != null) {
-                ret = quota.longValue();
-            }
-        } catch (InterruptedException e) {
-            Log.e(TAG, "Exception while waiting on the updated origins", e);
-        } finally {
-            mLock.unlock();
+        if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
+            syncValues();
+            Origin website = mOrigins.get(origin);
+            callback.onReceiveValue(new Long(website.getUsage()));
+        } else {
+            HashMap values = new HashMap<String, Object>();
+            values.put(ORIGIN, origin);
+            values.put(CALLBACK, callback);
+            postMessage(Message.obtain(null, GET_QUOTA_ORIGIN, values));
         }
-        return ret;
     }
 
     /**
@@ -256,6 +355,15 @@
     }
 
     /**
+     * Utility function to send a message to the handler on the UI thread
+     */
+    private void postUIMessage(Message msg) {
+        if (mUIHandler != null) {
+            mUIHandler.sendMessage(msg);
+        }
+    }
+
+    /**
      * @hide
      * Get the global instance of WebStorage.
      * @return A single instance of WebStorage.
@@ -284,21 +392,14 @@
      * set the local values with the current ones
      */
     private void syncValues() {
-        mLock.lock();
-        Set tmp = nativeGetOrigins();
-        mOrigins = new HashSet<String>();
-        mQuotas.clear();
-        mUsages.clear();
-        Iterator<String> iter = tmp.iterator();
-        while (iter.hasNext()) {
-            String origin = iter.next();
-            mOrigins.add(origin);
-            mQuotas.put(origin, new Long(nativeGetQuotaForOrigin(origin)));
-            mUsages.put(origin, new Long(nativeGetUsageForOrigin(origin)));
+        Set<String> tmp = nativeGetOrigins();
+        mOrigins = new HashMap<String, Origin>();
+        for (String origin : tmp) {
+            Origin website = new Origin(origin,
+                                 nativeGetUsageForOrigin(origin),
+                                 nativeGetQuotaForOrigin(origin));
+            mOrigins.put(origin, website);
         }
-        mUpdateAvailable = true;
-        mUpdateCondition.signal();
-        mLock.unlock();
     }
 
     // Native functions
diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java
index 39a2470..1a65ce8 100644
--- a/core/java/android/webkit/WebTextView.java
+++ b/core/java/android/webkit/WebTextView.java
@@ -448,8 +448,13 @@
             int initialScrollX = Touch.getInitialScrollX(this, buffer);
             int initialScrollY = Touch.getInitialScrollY(this, buffer);
             super.onTouchEvent(event);
-            if (Math.abs(mScrollX - initialScrollX) > slop
-                    || Math.abs(mScrollY - initialScrollY) > slop) {
+            int dx = Math.abs(mScrollX - initialScrollX);
+            int dy = Math.abs(mScrollY - initialScrollY);
+            // Use a smaller slop when checking to see if we've moved far enough
+            // to scroll the text, because experimentally, slop has shown to be
+            // to big for the case of a small textfield.
+            int smallerSlop = slop/2;
+            if (dx > smallerSlop || dy > smallerSlop) {
                 if (mWebView != null) {
                     mWebView.scrollFocusedTextInput(mScrollX, mScrollY);
                 }
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 7e8ba8f..51c5e1f 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -420,6 +420,7 @@
     private static final int STD_SPEED = 480;  // pixels per second
     // time for the longest scroll animation
     private static final int MAX_DURATION = 750;   // milliseconds
+    private static final int SLIDE_TITLE_DURATION = 500;   // milliseconds
     private Scroller mScroller;
 
     private boolean mWrapContent;
@@ -1781,12 +1782,22 @@
     }
 
     /**
+     * Given a distance in view space, convert it to content space. Note: this
+     * does not reflect translation, just scaling, so this should not be called
+     * with coordinates, but should be called for dimensions like width or
+     * height.
+     */
+    private int viewToContentDimension(int d) {
+        return Math.round(d * mInvActualScale);
+    }
+
+    /**
      * Given an x coordinate in view space, convert it to content space.  Also
      * may be used for absolute heights (such as for the WebTextView's
      * textSize, which is unaffected by the height of the title bar).
      */
     /*package*/ int viewToContentX(int x) {
-        return Math.round(x * mInvActualScale);
+        return viewToContentDimension(x);
     }
 
     /**
@@ -1795,7 +1806,7 @@
      * embedded into the WebView.
      */
     /*package*/ int viewToContentY(int y) {
-        return viewToContentX(y - getTitleHeight());
+        return viewToContentDimension(y - getTitleHeight());
     }
 
     /**
@@ -1810,7 +1821,7 @@
 
     /**
      * Given an x coordinate in content space, convert it to view
-     * space.  Also used for absolute heights.
+     * space.
      */
     /*package*/ int contentToViewX(int x) {
         return contentToViewDimension(x);
@@ -2000,7 +2011,7 @@
         getGlobalVisibleRect(r, p);
         r.offset(-p.x, -p.y);
         if (mFindIsUp) {
-            r.bottom -= FIND_HEIGHT;
+            r.bottom -= mFindHeight;
         }
     }
 
@@ -2072,9 +2083,6 @@
         }
     }
 
-    // Make sure this stays in sync with the actual height of the FindDialog.
-    private static final int FIND_HEIGHT = 79;
-
     @Override
     protected int computeVerticalScrollRange() {
         if (mDrawHistory) {
@@ -2305,7 +2313,11 @@
      *              that were found.
      */
     public int findAll(String find) {
-        mFindIsUp = true;
+        if (mFindIsUp == false) {
+            recordNewContentSize(mContentWidth, mContentHeight + mFindHeight,
+                    false);
+            mFindIsUp = true;
+        }
         int result = nativeFindAll(find.toLowerCase(), find.toUpperCase());
         invalidate();
         return result;
@@ -2314,6 +2326,7 @@
     // Used to know whether the find dialog is open.  Affects whether
     // or not we draw the highlights for matches.
     private boolean mFindIsUp;
+    private int mFindHeight;
 
     /**
      * Return the first substring consisting of the address of a physical
@@ -2369,7 +2382,11 @@
      * Clear the highlighting surrounding text matches created by findAll.
      */
     public void clearMatches() {
-        mFindIsUp = false;
+        if (mFindIsUp) {
+            recordNewContentSize(mContentWidth, mContentHeight - mFindHeight,
+                    false);
+            mFindIsUp = false;
+        }
         nativeSetFindIsDown();
         // Now that the dialog has been removed, ensure that we scroll to a
         // location that is not beyond the end of the page.
@@ -2378,6 +2395,16 @@
     }
 
     /**
+     * @hide
+     */
+    public void setFindDialogHeight(int height) {
+        if (DebugFlags.WEB_VIEW) {
+            Log.v(LOGTAG, "setFindDialogHeight height=" + height);
+        }
+        mFindHeight = height;
+    }
+
+    /**
      * Query the document to see if it contains any image references. The
      * message object will be dispatched with arg1 being set to 1 if images
      * were found and 0 if the document does not reference any images.
@@ -2419,7 +2446,6 @@
     private boolean pinScrollBy(int dx, int dy, boolean animate, int animationDuration) {
         return pinScrollTo(mScrollX + dx, mScrollY + dy, animate, animationDuration);
     }
-
     // helper to pin the scrollTo parameters (already in view coordinates)
     // returns true if the scroll was changed
     private boolean pinScrollTo(int x, int y, boolean animate, int animationDuration) {
@@ -2431,15 +2457,6 @@
         if ((dx | dy) == 0) {
             return false;
         }
-        // By this point we have added in the title bar's height.  If the site
-        // is trying to scroll to the top of the page, scroll it to the top
-        // of the WebView including showing the title bar.
-        // mobile sites prefer to scroll to (0, 1), thus the + 1 below
-        if (getVisibleTitleHeight() > 0 && x == 0
-                && y <= getTitleHeight() + 1) {
-            y = 0;
-            animate = false;
-        }
         if (animate) {
             //        Log.d(LOGTAG, "startScroll: " + dx + " " + dy);
             mScroller.startScroll(mScrollX, mScrollY, dx, dy,
@@ -2498,10 +2515,31 @@
             // saved scroll position, it is ok to skip this.
             return false;
         }
-        int vx = contentToViewX(cx);
-        int vy = contentToViewY(cy);
+        int vx;
+        int vy;
+        if ((cx | cy) == 0) {
+            // If the page is being scrolled to (0,0), do not add in the title
+            // bar's height, and simply scroll to (0,0). (The only other work
+            // in contentToView_ is to multiply, so this would not change 0.)
+            vx = 0;
+            vy = 0;
+        } else {
+            vx = contentToViewX(cx);
+            vy = contentToViewY(cy);
+        }
 //        Log.d(LOGTAG, "content scrollTo [" + cx + " " + cy + "] view=[" +
 //                      vx + " " + vy + "]");
+        // Some mobile sites attempt to scroll the title bar off the page by
+        // scrolling to (0,1).  If we are at the top left corner of the
+        // page, assume this is an attempt to scroll off the title bar, and
+        // animate the title bar off screen slowly enough that the user can see
+        // it.
+        if (cx == 0 && cy == 1 && mScrollX == 0 && mScrollY == 0) {
+            pinScrollTo(vx, vy, true, SLIDE_TITLE_DURATION);
+            // Since we are animating, we have not yet reached the desired
+            // scroll position.  Do not return true to request another attempt
+            return false;
+        }
         pinScrollTo(vx, vy, false, 0);
         // If the request was to scroll to a negative coordinate, treat it as if
         // it was a request to scroll to 0
@@ -3732,6 +3770,13 @@
                             && !mZoomButtonsController.isVisible()
                             && mMinZoomScale < mMaxZoomScale) {
                         mZoomButtonsController.setVisible(true);
+                        int count = settings.getDoubleTapToastCount();
+                        if (mInZoomOverview && count > 0) {
+                            settings.setDoubleTapToastCount(--count);
+                            Toast.makeText(mContext,
+                                    com.android.internal.R.string.double_tap_toast,
+                                    Toast.LENGTH_LONG).show();
+                        }
                     }
                 }
 
@@ -4410,7 +4455,10 @@
             return;
         }
         mWebViewCore.sendMessage(EventHub.SCROLL_TEXT_INPUT, viewToContentX(x),
-                viewToContentY(y));
+                // Since this position is relative to the top of the text input
+                // field, we do not need to take the title bar's height into
+                // consideration.
+                viewToContentDimension(y));
     }
 
     /**
@@ -4504,7 +4552,8 @@
         mZoomCenterY = mLastTouchY;
         mInZoomOverview = !mInZoomOverview;
         // remove the zoom control after double tap
-        if (getSettings().getBuiltInZoomControls()) {
+        WebSettings settings = getSettings();
+        if (settings.getBuiltInZoomControls()) {
             if (mZoomButtonsController.isVisible()) {
                 mZoomButtonsController.setVisible(false);
             }
@@ -4516,7 +4565,10 @@
                 mZoomControls.hide();
             }
         }
+        settings.setDoubleTapToastCount(0);
         if (mInZoomOverview) {
+            // Force the titlebar fully reveal in overview mode
+            if (mScrollY < getTitleHeight()) mScrollY = 0;
             zoomWithPreview((float) getViewWidth() / mZoomOverviewWidth);
         } else {
             // mLastTouchX and mLastTouchY are the point in the current viewport
@@ -4816,7 +4868,7 @@
                                             / draw.mMinPrefWidth;
                                     mMinZoomScaleFixed = false;
                                 } else {
-                                    mMinZoomScale = mDefaultScale;
+                                    mMinZoomScale = restoreState.mDefaultScale;
                                     mMinZoomScaleFixed = true;
                                 }
                             } else {
@@ -4833,22 +4885,13 @@
                             mMaxZoomScale = restoreState.mMaxScale;
                         }
                         setNewZoomScale(mLastScale, false);
-                        if (getTitleHeight() != 0 && restoreState.mScrollX == 0
-                                && restoreState.mScrollY == 0) {
-                            // If there is a title bar, and the page is being
-                            // restored to (0,0), do not scroll the title bar
-                            // off the page.
-                            abortAnimation();
-                            scrollTo(0,0);
-                        } else {
-                            setContentScrollTo(restoreState.mScrollX,
-                                    restoreState.mScrollY);
-                        }
+                        setContentScrollTo(restoreState.mScrollX,
+                                restoreState.mScrollY);
                         if (useWideViewport
                                 && settings.getLoadWithOverviewMode()) {
                             if (restoreState.mViewScale == 0
                                     || (restoreState.mMobileSite
-                                            && mMinZoomScale < mDefaultScale)) {
+                                    && mMinZoomScale < restoreState.mDefaultScale)) {
                                 mInZoomOverview = true;
                             }
                         }
@@ -4865,7 +4908,8 @@
                     final boolean updateLayout = viewSize.x == mLastWidthSent
                             && viewSize.y == mLastHeightSent;
                     recordNewContentSize(draw.mWidthHeight.x,
-                            draw.mWidthHeight.y, updateLayout);
+                            draw.mWidthHeight.y
+                            + (mFindIsUp ? mFindHeight : 0), updateLayout);
                     if (DebugFlags.WEB_VIEW) {
                         Rect b = draw.mInvalRegion.getBounds();
                         Log.v(LOGTAG, "NEW_PICTURE_MSG_ID {" +
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index d4142bb..ce45373 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -17,6 +17,7 @@
 package android.webkit;
 
 import android.content.Context;
+import android.content.Intent;
 import android.graphics.Canvas;
 import android.graphics.DrawFilter;
 import android.graphics.Paint;
@@ -37,6 +38,7 @@
 import android.view.View;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Map;
 import java.util.Set;
 
@@ -100,6 +102,15 @@
 
     private boolean mViewportUserScalable = true;
 
+    /*
+     * range is from 70 to 400.
+     * 0 is a special value means device-dpi. The default scale factor will be
+     * always 100.
+     * -1 means undefined. The default scale factor will be
+     * WebView.DEFAULT_SCALE_PERCENT.
+     */
+    private int mViewportDensityDpi = -1;
+
     private int mRestoredScale = 0;
     private int mRestoredScreenWidthScale = 0;
     private int mRestoredX = 0;
@@ -153,8 +164,10 @@
         // The WebIconDatabase needs to be initialized within the UI thread so
         // just request the instance here.
         WebIconDatabase.getInstance();
-        // Create the WebStorage singleton
-        WebStorage.getInstance();
+        // Create the WebStorage singleton and the UI handler
+        WebStorage.getInstance().createUIHandler();
+        // Create the UI handler for GeolocationPermissions
+        GeolocationPermissions.getInstance().createUIHandler();
         // Send a message to initialize the WebViewCore.
         Message init = sWebCoreHandler.obtainMessage(
                 WebCoreThread.INITIALIZE, this);
@@ -841,6 +854,7 @@
                             synchronized (WebViewCore.this) {
                                 mBrowserFrame.destroy();
                                 mBrowserFrame = null;
+                                mSettings.onDestroyed();
                                 mNativeClass = 0;
                             }
                             break;
@@ -1510,13 +1524,14 @@
     // callbacks. Computes the sum of database quota for all origins.
     private long getUsedQuota() {
         WebStorage webStorage = WebStorage.getInstance();
-        Set<String> origins = webStorage.getOrigins();
+        Collection<WebStorage.Origin> origins = webStorage.getOriginsSync();
+
         if (origins == null) {
             return 0;
         }
         long usedQuota = 0;
-        for (String origin : origins) {
-            usedQuota += webStorage.getQuotaForOrigin(origin);
+        for (WebStorage.Origin website : origins) {
+            usedQuota += website.getQuota();
         }
         return usedQuota;
     }
@@ -1539,6 +1554,7 @@
         float mMaxScale;
         float mViewScale;
         float mTextWrapScale;
+        float mDefaultScale;
         int mScrollX;
         int mScrollY;
         boolean mMobileSite;
@@ -1842,47 +1858,48 @@
         // set the viewport settings from WebKit
         setViewportSettingsFromNative();
 
-        // adjust the default scale to match the density
-        if (WebView.DEFAULT_SCALE_PERCENT != 100) {
-            float adjust = (float) WebView.DEFAULT_SCALE_PERCENT / 100.0f;
-            if (mViewportInitialScale > 0) {
-                mViewportInitialScale *= adjust;
+        // adjust the default scale to match the densityDpi
+        float adjust = 1.0f;
+        if (mViewportDensityDpi == -1) {
+            if (WebView.DEFAULT_SCALE_PERCENT != 100) {
+                adjust = WebView.DEFAULT_SCALE_PERCENT / 100.0f;
             }
-            if (mViewportMinimumScale > 0) {
-                mViewportMinimumScale *= adjust;
-            }
-            if (mViewportMaximumScale > 0) {
-                mViewportMaximumScale *= adjust;
-            }
+        } else if (mViewportDensityDpi > 0) {
+            adjust = (float) mContext.getResources().getDisplayMetrics().densityDpi
+                    / mViewportDensityDpi;
+        }
+        int defaultScale = (int) (adjust * 100);
+
+        if (mViewportInitialScale > 0) {
+            mViewportInitialScale *= adjust;
+        }
+        if (mViewportMinimumScale > 0) {
+            mViewportMinimumScale *= adjust;
+        }
+        if (mViewportMaximumScale > 0) {
+            mViewportMaximumScale *= adjust;
         }
 
         // infer the values if they are not defined.
         if (mViewportWidth == 0) {
             if (mViewportInitialScale == 0) {
-                mViewportInitialScale = WebView.DEFAULT_SCALE_PERCENT;
+                mViewportInitialScale = defaultScale;
             }
         }
         if (mViewportUserScalable == false) {
-            mViewportInitialScale = WebView.DEFAULT_SCALE_PERCENT;
-            mViewportMinimumScale = WebView.DEFAULT_SCALE_PERCENT;
-            mViewportMaximumScale = WebView.DEFAULT_SCALE_PERCENT;
+            mViewportInitialScale = defaultScale;
+            mViewportMinimumScale = defaultScale;
+            mViewportMaximumScale = defaultScale;
         }
-        if (mViewportMinimumScale > mViewportInitialScale) {
-            if (mViewportInitialScale == 0) {
-                mViewportInitialScale = mViewportMinimumScale;
-            } else {
-                mViewportMinimumScale = mViewportInitialScale;
-            }
+        if (mViewportMinimumScale > mViewportInitialScale
+                && mViewportInitialScale != 0) {
+            mViewportMinimumScale = mViewportInitialScale;
         }
-        if (mViewportMaximumScale > 0) {
-            if (mViewportMaximumScale < mViewportInitialScale) {
-                mViewportMaximumScale = mViewportInitialScale;
-            } else if (mViewportInitialScale == 0) {
-                mViewportInitialScale = mViewportMaximumScale;
-            }
+        if (mViewportMaximumScale > 0
+                && mViewportMaximumScale < mViewportInitialScale) {
+            mViewportMaximumScale = mViewportInitialScale;
         }
-        if (mViewportWidth < 0
-                && mViewportInitialScale == WebView.DEFAULT_SCALE_PERCENT) {
+        if (mViewportWidth < 0 && mViewportInitialScale == defaultScale) {
             mViewportWidth = 0;
         }
 
@@ -1899,7 +1916,7 @@
             // 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;
+            viewportWidth = (int) (webViewWidth / adjust);
             if (viewportWidth == 0) {
                 Log.w(LOGTAG, "Can't get the viewWidth after the first layout");
             }
@@ -1909,6 +1926,7 @@
         mRestoreState = new RestoreState();
         mRestoreState.mMinScale = mViewportMinimumScale / 100.0f;
         mRestoreState.mMaxScale = mViewportMaximumScale / 100.0f;
+        mRestoreState.mDefaultScale = adjust;
         mRestoreState.mScrollX = mRestoredX;
         mRestoreState.mScrollY = mRestoredY;
         mRestoreState.mMobileSite = (0 == mViewportWidth);
@@ -1930,8 +1948,7 @@
                 mRestoreState.mViewScale = mRestoreState.mTextWrapScale =
                         (float) webViewWidth / mViewportWidth;
             } else {
-                mRestoreState.mTextWrapScale =
-                        WebView.DEFAULT_SCALE_PERCENT / 100.0f;
+                mRestoreState.mTextWrapScale = adjust;
                 // 0 will trigger WebView to turn on zoom overview mode
                 mRestoreState.mViewScale = 0;
             }
@@ -2075,22 +2092,49 @@
         }
     }
 
-    // PluginWidget functions for creating SurfaceViews for the Surface drawing
-    // model.
-    private ViewManager.ChildView createSurface(String packageName, String className,
+    // called by JNI. PluginWidget function to launch an activity and overlays
+    // the activity with the View provided by the plugin class.
+    private void startFullScreenPluginActivity(String libName, String clsName, int npp) {
+        if (mWebView == null) {
+            return;
+        }
+
+        String pkgName = PluginManager.getInstance(null).getPluginsAPKName(libName);
+        if (pkgName == null) {
+            Log.w(LOGTAG, "Unable to resolve " + libName + " to a plugin APK");
+            return;
+        }
+
+        Intent intent = new Intent("android.intent.webkit.PLUGIN");
+        intent.putExtra(PluginActivity.INTENT_EXTRA_PACKAGE_NAME, pkgName);
+        intent.putExtra(PluginActivity.INTENT_EXTRA_CLASS_NAME, clsName);
+        intent.putExtra(PluginActivity.INTENT_EXTRA_NPP_INSTANCE, npp);
+        mWebView.getContext().startActivity(intent);
+    }
+
+    // called by JNI.  PluginWidget functions for creating an embedded View for
+    // the surface drawing model.
+    private ViewManager.ChildView createSurface(String libName, String clsName,
             int npp, int x, int y, int width, int height) {
         if (mWebView == null) {
             return null;
         }
-        PluginStub stub = PluginUtil.getPluginStub(mWebView.getContext(), packageName, className);
-        if (stub == null) {
-            Log.e(LOGTAG, "Unable to find plugin class (" + className + 
-                    ") in the apk (" + packageName + ")");
+
+        String pkgName = PluginManager.getInstance(null).getPluginsAPKName(libName);
+        if (pkgName == null) {
+            Log.w(LOGTAG, "Unable to resolve " + libName + " to a plugin APK");
             return null;
         }
-        
+
+        PluginStub stub =PluginUtil.getPluginStub(mWebView.getContext(),pkgName, clsName);
+        if (stub == null) {
+            Log.e(LOGTAG, "Unable to find plugin class (" + clsName +
+                    ") in the apk (" + pkgName + ")");
+            return null;
+        }
+
         View pluginView = stub.getEmbeddedView(npp, mWebView.getContext());
-        
+
         ViewManager.ChildView view = mWebView.mViewManager.createView();
         view.mView = pluginView;
         view.attachView(x, y, width, height);
diff --git a/core/java/android/widget/FasttrackBadgeWidget.java b/core/java/android/widget/FasttrackBadgeWidget.java
index 9d2307f..8c8e054 100644
--- a/core/java/android/widget/FasttrackBadgeWidget.java
+++ b/core/java/android/widget/FasttrackBadgeWidget.java
@@ -22,6 +22,7 @@
 import android.content.Intent;
 import android.content.res.TypedArray;
 import android.database.Cursor;
+import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.FastTrack;
@@ -46,6 +47,7 @@
     private String mContactPhone;
     private int mMode;
     private QueryHandler mQueryHandler;
+    private Drawable mBadgeBackground;
 
     protected String[] mExcludeMimes = null;
 
@@ -91,6 +93,8 @@
         a.recycle();
 
         init();
+
+        mBadgeBackground = getBackground();
     }
 
     private void init() {
@@ -108,6 +112,17 @@
      */
     public void assignContactUri(Uri contactUri) {
         mContactUri = contactUri;
+        mContactEmail = null;
+        mContactPhone = null;
+        onContactUriChanged();
+    }
+
+    private void onContactUriChanged() {
+        if (mContactUri == null && mContactEmail == null && mContactPhone == null) {
+            setBackgroundDrawable(null);
+        } else {
+            setBackgroundDrawable(mBadgeBackground);
+        }
     }
 
     /**
@@ -127,6 +142,7 @@
                     EMAIL_LOOKUP_PROJECTION, null, null, null);
         } else {
             mContactUri = null;
+            onContactUriChanged();
         }
     }
 
@@ -147,6 +163,7 @@
                     PHONE_LOOKUP_PROJECTION, null, null, null);
         } else {
             mContactUri = null;
+            onContactUriChanged();
         }
     }
 
@@ -237,6 +254,7 @@
             }
 
             mContactUri = lookupUri;
+            onContactUriChanged();
 
             if (trigger && lookupUri != null) {
                 // Found contact, so trigger track
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index 703cd8e2..31c7814 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -743,7 +743,7 @@
 
         final int maxJump = getMaxScrollAmount();
 
-        if (nextFocused != null && isWithinDeltaOfScreen(nextFocused, maxJump)) {
+        if (nextFocused != null && isWithinDeltaOfScreen(nextFocused, maxJump, getHeight())) {
             nextFocused.getDrawingRect(mTempRect);
             offsetDescendantRectToMyCoords(nextFocused, mTempRect);
             int scrollDelta = computeScrollDeltaToGetChildRectOnScreen(mTempRect);
@@ -792,19 +792,19 @@
      *  screen.
      */
     private boolean isOffScreen(View descendant) {
-        return !isWithinDeltaOfScreen(descendant, 0);
+        return !isWithinDeltaOfScreen(descendant, 0, getHeight());
     }
 
     /**
      * @return whether the descendant of this scroll view is within delta
      *  pixels of being on the screen.
      */
-    private boolean isWithinDeltaOfScreen(View descendant, int delta) {
+    private boolean isWithinDeltaOfScreen(View descendant, int delta, int height) {
         descendant.getDrawingRect(mTempRect);
         offsetDescendantRectToMyCoords(descendant, mTempRect);
 
         return (mTempRect.bottom + delta) >= getScrollY()
-                && (mTempRect.top - delta) <= (getScrollY() + getHeight());
+                && (mTempRect.top - delta) <= (getScrollY() + height);
     }
 
     /**
@@ -1124,9 +1124,10 @@
         if (null == currentFocused || this == currentFocused)
             return;
 
-        final int maxJump = mBottom - mTop;
-
-        if (isWithinDeltaOfScreen(currentFocused, maxJump)) {
+        // If the currently-focused view was visible on the screen when the
+        // screen was at the old height, then scroll the screen to make that
+        // view visible with the new screen height.
+        if (isWithinDeltaOfScreen(currentFocused, 0, oldh)) {
             currentFocused.getDrawingRect(mTempRect);
             offsetDescendantRectToMyCoords(currentFocused, mTempRect);
             int scrollDelta = computeScrollDeltaToGetChildRectOnScreen(mTempRect);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 2e3364b..3c61c1c 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -2874,26 +2874,23 @@
      * @attr ref android.R.styleable#TextView_inputType
      */
     public void setInputType(int type) {
+        final boolean wasPassword = isPasswordInputType(mInputType);
+        final boolean wasVisiblePassword = isVisiblePasswordInputType(mInputType);
         setInputType(type, false);
-        final int variation = type&(EditorInfo.TYPE_MASK_CLASS
-                |EditorInfo.TYPE_MASK_VARIATION);
-        final boolean isPassword = variation
-                == (EditorInfo.TYPE_CLASS_TEXT
-                        |EditorInfo.TYPE_TEXT_VARIATION_PASSWORD);
+        final boolean isPassword = isPasswordInputType(type);
+        final boolean isVisiblePassword = isVisiblePasswordInputType(type);
         boolean forceUpdate = false;
         if (isPassword) {
             setTransformationMethod(PasswordTransformationMethod.getInstance());
             setTypefaceByIndex(MONOSPACE, 0);
-        } else if (mTransformation == PasswordTransformationMethod.getInstance()) {
-            // We need to clean up if we were previously in password mode.
-            if (variation != (EditorInfo.TYPE_CLASS_TEXT
-                        |EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD)) {
-                setTypefaceByIndex(-1, -1);
-            }
-            forceUpdate = true;
-        } else if (variation == (EditorInfo.TYPE_CLASS_TEXT
-                        |EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD)) {
+        } else if (isVisiblePassword) {
             setTypefaceByIndex(MONOSPACE, 0);
+        } else if (wasPassword || wasVisiblePassword) {
+            // not in password mode, clean up typeface and transformation
+            setTypefaceByIndex(-1, -1);
+            if (mTransformation == PasswordTransformationMethod.getInstance()) {
+                forceUpdate = true;
+            }
         }
         
         boolean multiLine = (type&(EditorInfo.TYPE_MASK_CLASS
@@ -2913,6 +2910,22 @@
         if (imm != null) imm.restartInput(this);
     }
 
+    private boolean isPasswordInputType(int inputType) {
+        final int variation = inputType & (EditorInfo.TYPE_MASK_CLASS
+                | EditorInfo.TYPE_MASK_VARIATION);
+        return variation
+                == (EditorInfo.TYPE_CLASS_TEXT
+                        | EditorInfo.TYPE_TEXT_VARIATION_PASSWORD);
+    }
+
+    private boolean isVisiblePasswordInputType(int inputType) {
+        final int variation = inputType & (EditorInfo.TYPE_MASK_CLASS
+                | EditorInfo.TYPE_MASK_VARIATION);
+        return variation
+                == (EditorInfo.TYPE_CLASS_TEXT
+                        | EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD);
+    }
+
     /**
      * Directly change the content type integer of the text view, without
      * modifying any other state.
diff --git a/core/java/com/android/internal/backup/BackupConstants.java b/core/java/com/android/internal/backup/BackupConstants.java
new file mode 100644
index 0000000..3ee11bd
--- /dev/null
+++ b/core/java/com/android/internal/backup/BackupConstants.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.backup;
+
+/**
+ * Constants used internally between the backup manager and its transports
+ */
+public class BackupConstants {
+    public static final int TRANSPORT_OK = 0;
+    public static final int TRANSPORT_ERROR = 1;
+    public static final int TRANSPORT_NOT_INITIALIZED = 2;
+}
diff --git a/core/java/com/android/internal/backup/IBackupTransport.aidl b/core/java/com/android/internal/backup/IBackupTransport.aidl
index af06965..a830ebd 100644
--- a/core/java/com/android/internal/backup/IBackupTransport.aidl
+++ b/core/java/com/android/internal/backup/IBackupTransport.aidl
@@ -22,24 +22,6 @@
 
 /** {@hide} */
 interface IBackupTransport {
-/* STOPSHIP - don't ship with this comment in place
-    Things the transport interface has to do:
-    1. set up the connection to the destination
-        - set up encryption
-        - for Google cloud, log in using the user's gaia credential or whatever
-        - for adb, just set up the all-in-one destination file
-    2. send each app's backup transaction
-        - parse the data file for key/value pointers etc
-        - send key/blobsize set to the Google cloud, get back quota ok/rejected response
-        - sd/adb doesn't preflight; no per-app quota
-        - app's entire change is essentially atomic
-        - cloud transaction encrypts then sends each key/value pair separately; we already
-          parsed the data when preflighting so we don't have to again here
-        - sd target streams raw data into encryption envelope then to sd?
-    3. shut down connection to destination
-        - cloud: tear down connection etc
-        - adb: close the file
-*/
     /**
      * Ask the transport where, on local device storage, to keep backup state blobs.
      * This is per-transport so that mock transports used for testing can coexist with
@@ -68,6 +50,17 @@
     long requestBackupTime();
 
     /**
+     * Initialize the server side storage for this device, erasing all stored data.
+     * The transport may send the request immediately, or may buffer it.  After
+     * this is called, {@link #finishBackup} must be called to ensure the request
+     * is sent and received successfully.
+     *
+     * @return One of {@link BackupConstants#TRANSPORT_OK} (OK so far) or
+     *   {@link BackupConstants#TRANSPORT_ERROR} (on network error or other failure).
+     */
+    int initializeDevice();
+
+    /**
      * Send one application's data to the backup destination.  The transport may send
      * the data immediately, or may buffer it.  After this is called, {@link #finishBackup}
      * must be called to ensure the data is sent and recorded successfully.
@@ -77,10 +70,16 @@
      * @param data The data stream that resulted from invoking the application's
      *   BackupService.doBackup() method.  This may be a pipe rather than a file on
      *   persistent media, so it may not be seekable.
-     * @return false if errors occurred (the backup should be aborted and rescheduled),
-     *   true if everything is OK so far (but {@link #finishBackup} must be called).
+     * @param wipeAllFirst When true, <i>all</i> backed-up data for the current device/account
+     *   will be erased prior to the storage of the data provided here.  The purpose of this
+     *   is to provide a guarantee that no stale data exists in the restore set when the
+     *   device begins providing backups.
+     * @return one of {@link BackupConstants#TRANSPORT_OK} (OK so far),
+     *  {@link BackupConstants#TRANSPORT_ERROR} (on network error or other failure), or
+     *  {@link BackupConstants#TRANSPORT_NOT_INITIALIZED} (if the backend dataset has
+     *  become lost due to inactive expiry or some other reason and needs re-initializing)
      */
-    boolean performBackup(in PackageInfo packageInfo, in ParcelFileDescriptor inFd);
+    int performBackup(in PackageInfo packageInfo, in ParcelFileDescriptor inFd);
 
     /**
      * Erase the give application's data from the backup destination.  This clears
@@ -88,10 +87,9 @@
      * the app had never yet been backed up.  After this is called, {@link finishBackup}
      * must be called to ensure that the operation is recorded successfully.
      *
-     * @return false if errors occurred (the backup should be aborted and rescheduled),
-     *   true if everything is OK so far (but {@link #finishBackup} must be called).
+     * @return the same error codes as {@link #performBackup}.
      */
-    boolean clearBackupData(in PackageInfo packageInfo);
+    int clearBackupData(in PackageInfo packageInfo);
 
     /**
      * Finish sending application data to the backup destination.  This must be
@@ -99,10 +97,9 @@
      * all data is sent.  Only when this method returns true can a backup be assumed
      * to have succeeded.
      *
-     * @return false if errors occurred (the backup should be aborted and rescheduled),
-     *   true if everything is OK.
+     * @return the same error codes as {@link #performBackup}.
      */
-    boolean finishBackup();
+    int finishBackup();
 
     /**
      * Get the set of backups currently available over this transport.
@@ -120,10 +117,11 @@
      * @param token A backup token as returned by {@link #getAvailableRestoreSets}.
      * @param packages List of applications to restore (if data is available).
      *   Application data will be restored in the order given.
-     * @return false if errors occurred (the restore should be aborted and rescheduled),
-     *   true if everything is OK so far (go ahead and call {@link #nextRestorePackage}).
+     * @return One of {@link BackupConstants#TRANSPORT_OK} (OK so far, call
+     *   {@link #nextRestorePackage}) or {@link BackupConstants#TRANSPORT_ERROR}
+     *   (an error occurred, the restore should be aborted and rescheduled).
      */
-    boolean startRestore(long token, in PackageInfo[] packages);
+    int startRestore(long token, in PackageInfo[] packages);
 
     /**
      * Get the package name of the next application with data in the backup store.
@@ -136,10 +134,9 @@
     /**
      * Get the data for the application returned by {@link #nextRestorePackage}.
      * @param data An open, writable file into which the backup data should be stored.
-     * @return false if errors occurred (the restore should be aborted and rescheduled),
-     *   true if everything is OK so far (go ahead and call {@link #nextRestorePackage}).
+     * @return the same error codes as {@link #nextRestorePackage}.
      */
-    boolean getRestoreData(in ParcelFileDescriptor outFd);
+    int getRestoreData(in ParcelFileDescriptor outFd);
 
     /**
      * End a restore session (aborting any in-process data transfer as necessary),
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java
index 2facce2..4fc3edc 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/core/java/com/android/internal/backup/LocalTransport.java
@@ -47,17 +47,22 @@
     }
 
 
-    public String transportDirName() throws RemoteException {
+    public String transportDirName() {
         return TRANSPORT_DIR_NAME;
     }
 
-    public long requestBackupTime() throws RemoteException {
+    public long requestBackupTime() {
         // any time is a good time for local backup
         return 0;
     }
 
-    public boolean performBackup(PackageInfo packageInfo, ParcelFileDescriptor data)
-            throws RemoteException {
+    public int initializeDevice() {
+        if (DEBUG) Log.v(TAG, "wiping all data");
+        deleteContents(mDataDir);
+        return BackupConstants.TRANSPORT_OK;
+    }
+
+    public int performBackup(PackageInfo packageInfo, ParcelFileDescriptor data) {
         if (DEBUG) Log.v(TAG, "performBackup() pkg=" + packageInfo.packageName);
 
         File packageDir = new File(mDataDir, packageInfo.packageName);
@@ -95,7 +100,7 @@
                         entity.write(buf, 0, dataSize);
                     } catch (IOException e) {
                         Log.e(TAG, "Unable to update key file " + entityFile.getAbsolutePath());
-                        return false;
+                        return BackupConstants.TRANSPORT_ERROR;
                     } finally {
                         entity.close();
                     }
@@ -103,15 +108,30 @@
                     entityFile.delete();
                 }
             }
-            return true;
+            return BackupConstants.TRANSPORT_OK;
         } catch (IOException e) {
             // oops, something went wrong.  abort the operation and return error.
             Log.v(TAG, "Exception reading backup input:", e);
-            return false;
+            return BackupConstants.TRANSPORT_ERROR;
         }
     }
 
-    public boolean clearBackupData(PackageInfo packageInfo) {
+    // Deletes the contents but not the given directory
+    private void deleteContents(File dirname) {
+        File[] contents = dirname.listFiles();
+        if (contents != null) {
+            for (File f : contents) {
+                if (f.isDirectory()) {
+                    // delete the directory's contents then fall through
+                    // and delete the directory itself.
+                    deleteContents(f);
+                }
+                f.delete();
+            }
+        }
+    }
+
+    public int clearBackupData(PackageInfo packageInfo) {
         if (DEBUG) Log.v(TAG, "clearBackupData() pkg=" + packageInfo.packageName);
 
         File packageDir = new File(mDataDir, packageInfo.packageName);
@@ -119,12 +139,12 @@
             f.delete();
         }
         packageDir.delete();
-        return true;
+        return BackupConstants.TRANSPORT_OK;
     }
 
-    public boolean finishBackup() throws RemoteException {
+    public int finishBackup() {
         if (DEBUG) Log.v(TAG, "finishBackup()");
-        return true;
+        return BackupConstants.TRANSPORT_OK;
     }
 
     // Restore handling
@@ -135,11 +155,11 @@
         return array;
     }
 
-    public boolean startRestore(long token, PackageInfo[] packages) {
+    public int startRestore(long token, PackageInfo[] packages) {
         if (DEBUG) Log.v(TAG, "start restore " + token);
         mRestorePackages = packages;
         mRestorePackage = -1;
-        return true;
+        return BackupConstants.TRANSPORT_OK;
     }
 
     public String nextRestorePackage() {
@@ -156,7 +176,7 @@
         return "";
     }
 
-    public boolean getRestoreData(ParcelFileDescriptor outFd) {
+    public int getRestoreData(ParcelFileDescriptor outFd) {
         if (mRestorePackages == null) throw new IllegalStateException("startRestore not called");
         if (mRestorePackage < 0) throw new IllegalStateException("nextRestorePackage not called");
         File packageDir = new File(mDataDir, mRestorePackages[mRestorePackage].packageName);
@@ -164,9 +184,9 @@
         // The restore set is the concatenation of the individual record blobs,
         // each of which is a file in the package's directory
         File[] blobs = packageDir.listFiles();
-        if (blobs == null) {
+        if (blobs == null) {  // nextRestorePackage() ensures the dir exists, so this is an error
             Log.e(TAG, "Error listing directory: " + packageDir);
-            return false;  // nextRestorePackage() ensures the dir exists, so this is an error
+            return BackupConstants.TRANSPORT_ERROR;
         }
 
         // We expect at least some data if the directory exists in the first place
@@ -187,10 +207,10 @@
                     in.close();
                 }
             }
-            return true;
+            return BackupConstants.TRANSPORT_OK;
         } catch (IOException e) {
             Log.e(TAG, "Unable to read backup records", e);
-            return false;
+            return BackupConstants.TRANSPORT_ERROR;
         }
     }
 
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 2da72df..35c66ba 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -56,7 +56,9 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS' 
 
     // Current on-disk Parcel version
-    private static final int VERSION = 39;
+    private static final int VERSION = 40;
+
+    private static int sNumSpeedSteps;
 
     private final File mFile;
     private final File mBackupFile;
@@ -213,7 +215,7 @@
     /**
      * State for keeping track of counting information.
      */
-    public static final class Counter extends BatteryStats.Counter implements Unpluggable {
+    public static class Counter extends BatteryStats.Counter implements Unpluggable {
         int mCount;
         int mLoadedCount;
         int mLastCount;
@@ -302,7 +304,22 @@
             mUnpluggedCount = mPluggedCount = mCount;
         }
     }
-    
+
+    public static class SamplingCounter extends Counter {
+
+        SamplingCounter(ArrayList<Unpluggable> unpluggables, Parcel in) {
+            super(unpluggables, in);
+        }
+
+        SamplingCounter(ArrayList<Unpluggable> unpluggables) {
+            super(unpluggables);
+        }
+
+        public void addCountLocked(long count) {
+            mCount += count;
+        }
+    }
+
     /**
      * State for keeping track of timing information.
      */
@@ -1940,10 +1957,16 @@
              */
             long mUnpluggedForegroundTime;
 
+            SamplingCounter[] mSpeedBins;
+
             Proc() {
                 mUnpluggables.add(this);
+                mSpeedBins = new SamplingCounter[getCpuSpeedSteps()];
+                for (int i = 0; i < mSpeedBins.length; i++) {
+                    mSpeedBins[i] = new SamplingCounter(mUnpluggables);
+                }
             }
-            
+
             public void unplug(long batteryUptime, long batteryRealtime) {
                 mUnpluggedUserTime = mUserTime;
                 mUnpluggedSystemTime = mSystemTime;
@@ -1974,6 +1997,11 @@
                 out.writeLong(mUnpluggedSystemTime);
                 out.writeLong(mUnpluggedForegroundTime);
                 out.writeInt(mUnpluggedStarts);
+
+                out.writeInt(mSpeedBins.length);
+                for (int i = 0; i < mSpeedBins.length; i++) {
+                    mSpeedBins[i].writeToParcel(out);
+                }
             }
 
             void readFromParcelLocked(Parcel in) {
@@ -1993,6 +2021,12 @@
                 mUnpluggedSystemTime = in.readLong();
                 mUnpluggedForegroundTime = in.readLong();
                 mUnpluggedStarts = in.readInt();
+
+                int bins = in.readInt();
+                mSpeedBins = new SamplingCounter[bins];
+                for (int i = 0; i < bins; i++) {
+                    mSpeedBins[i] = new SamplingCounter(mUnpluggables, in);
+                }
             }
 
             public BatteryStatsImpl getBatteryStats() {
@@ -2075,6 +2109,22 @@
                 }
                 return val;
             }
+
+            /* Called by ActivityManagerService when CPU times are updated. */
+            public void addSpeedStepTimes(long[] values) {
+                for (int i = 0; i < mSpeedBins.length && i < values.length; i++) {
+                    mSpeedBins[i].addCountLocked(values[i]);
+                }
+            }
+
+            @Override
+            public long getTimeAtCpuSpeedStep(int speedStep, int which) {
+                if (speedStep < mSpeedBins.length) {
+                    return mSpeedBins[speedStep].getCountLocked(which);
+                } else {
+                    return 0;
+                }
+            }
         }
 
         /**
@@ -2625,6 +2675,10 @@
         readFromParcel(p);
     }
 
+    public void setNumSpeedSteps(int steps) {
+        if (sNumSpeedSteps == 0) sNumSpeedSteps = steps;
+    }
+
     @Override
     public int getStartCount() {
         return mStartCount;
@@ -2853,6 +2907,11 @@
             return mDischargeCurrentLevel;
     }
 
+    @Override
+    public int getCpuSpeedSteps() {
+        return sNumSpeedSteps;
+    }
+
     /**
      * Retrieve the statistics object for a particular uid, creating if needed.
      */
@@ -3063,7 +3122,9 @@
                 getKernelWakelockTimerLocked(kwltName).readSummaryFromParcelLocked(in);
             }
         }
-        
+
+        sNumSpeedSteps = in.readInt();
+
         final int NU = in.readInt();
         for (int iu = 0; iu < NU; iu++) {
             int uid = in.readInt();
@@ -3206,6 +3267,7 @@
             }
         }
         
+        out.writeInt(sNumSpeedSteps);
         final int NU = mUidStats.size();
         out.writeInt(NU);
         for (int iu = 0; iu < NU; iu++) {
@@ -3404,6 +3466,8 @@
         mFullTimers.clear();
         mWindowTimers.clear();
 
+        sNumSpeedSteps = in.readInt();
+
         int numUids = in.readInt();
         mUidStats.clear();
         for (int i = 0; i < numUids; i++) {
@@ -3484,7 +3548,9 @@
                 out.writeInt(0);
             }
         }
-        
+
+        out.writeInt(sNumSpeedSteps);
+
         int size = mUidStats.size();
         out.writeInt(size);
         for (int i = 0; i < size; i++) {
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index 94f703ad..4b4b717 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -47,14 +47,9 @@
     public static final String POWER_CPU_IDLE = "cpu.idle";
 
     /**
-     * Power consumption when CPU is running at normal speed.
+     * Power consumption when CPU is in power collapse mode.
      */
-    public static final String POWER_CPU_NORMAL = "cpu.normal";
-
-    /**
-     * Power consumption when CPU is running at full speed.
-     */
-    public static final String POWER_CPU_FULL = "cpu.full";
+    public static final String POWER_CPU_ACTIVE = "cpu.active";
 
     /**
      * Power consumption when WiFi driver is scanning for networks.
@@ -124,6 +119,8 @@
      */
     public static final String POWER_VIDEO = "dsp.video";
 
+    public static final String POWER_CPU_SPEEDS = "cpu.speeds";
+
     static final HashMap<String, Object> sPowerMap = new HashMap<String, Object>();
 
     private static final String TAG_DEVICE = "device";
@@ -214,10 +211,10 @@
     }
     
     /**
-     * Returns the average current in mA consumed by the subsystem for the given level. 
+     * Returns the average current in mA consumed by the subsystem for the given level.
      * @param type the subsystem type
      * @param level the level of power at which the subsystem is running. For instance, the
-     *  signal strength of the cell network between 0 and 4 (if there are 4 bars max.).
+     *  signal strength of the cell network between 0 and 4 (if there are 4 bars max.)
      *  If there is no data for multiple levels, the level is ignored.
      * @return the average current in milliAmps.
      */
@@ -240,4 +237,12 @@
             return 0;
         }
     }
+
+    public int getNumSpeedSteps() {
+        Object value = sPowerMap.get(POWER_CPU_SPEEDS);
+        if (value != null && value instanceof Double[]) {
+            return ((Double[])value).length;
+        }
+        return 1; // Only one speed
+    }
 }
diff --git a/core/java/com/android/internal/widget/ContactHeaderWidget.java b/core/java/com/android/internal/widget/ContactHeaderWidget.java
index 4ec597c..35d637d 100644
--- a/core/java/com/android/internal/widget/ContactHeaderWidget.java
+++ b/core/java/com/android/internal/widget/ContactHeaderWidget.java
@@ -63,6 +63,7 @@
     private static final String TAG = "ContactHeaderWidget";
 
     private TextView mDisplayNameView;
+    private View mAggregateBadge;
     private TextView mPhoneticNameView;
     private CheckBox mStarredView;
     private FasttrackBadgeWidget mPhotoView;
@@ -159,6 +160,8 @@
 
         mDisplayNameView = (TextView) findViewById(R.id.name);
         mDisplayNameView.setOnLongClickListener(this);
+        mAggregateBadge = findViewById(R.id.aggregate_badge);
+        mAggregateBadge.setVisibility(View.GONE);
 
         mPhoneticNameView = (TextView) findViewById(R.id.phonetic_name);
 
@@ -248,7 +251,9 @@
                                     PHONE_LOOKUP_CONTACT_LOOKUP_KEY_COLUMN_INDEX);
                             bindFromContactUri(Contacts.getLookupUri(contactId, lookupKey));
                         } else {
-                            setDisplayName((String) cookie, null);
+                            String phoneNumber = (String) cookie;
+                            setDisplayName(phoneNumber, null);
+                            mPhotoView.assignContactFromPhone(phoneNumber, true);
                         }
                         break;
                     }
@@ -259,7 +264,9 @@
                                     EMAIL_LOOKUP_CONTACT_LOOKUP_KEY_COLUMN_INDEX);
                             bindFromContactUri(Contacts.getLookupUri(contactId, lookupKey));
                         } else {
-                            setDisplayName((String) cookie, null);
+                            String emailAddress = (String) cookie;
+                            setDisplayName(emailAddress, null);
+                            mPhotoView.assignContactFromEmail(emailAddress, true);
                         }
                         break;
                     }
@@ -280,6 +287,13 @@
     }
 
     /**
+     * Turn on/off showing of the aggregate bage element.
+     */
+    public void showAggregateBadge(boolean showBagde) {
+        mAggregateBadge.setVisibility(showBagde ? View.VISIBLE : View.GONE);
+    }
+
+    /**
      * Turn on/off showing of the star element.
      */
     public void showStar(boolean showStar) {
@@ -306,6 +320,7 @@
      */
     public void setContactUri(Uri uri) {
         mContactUri = uri;
+        mPhotoView.assignContactUri(uri);
     }
 
     /**
@@ -398,7 +413,7 @@
      */
     public void bindFromPhoneNumber(String number) {
         mQueryHandler.startQuery(TOKEN_PHONE_LOOKUP, number,
-                Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, number),
+                Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number)),
                 PHONE_LOOKUP_PROJECTION, null, null, null);
     }
 
diff --git a/core/java/com/android/internal/widget/RotarySelector.java b/core/java/com/android/internal/widget/RotarySelector.java
index 712f1bf..426cef5 100644
--- a/core/java/com/android/internal/widget/RotarySelector.java
+++ b/core/java/com/android/internal/widget/RotarySelector.java
@@ -25,7 +25,9 @@
 import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.animation.AccelerateInterpolator;
+import android.view.VelocityTracker;
+import android.view.ViewConfiguration;
+import android.view.animation.DecelerateInterpolator;
 import static android.view.animation.AnimationUtils.currentAnimationTimeMillis;
 import com.android.internal.R;
 
@@ -59,21 +61,18 @@
     private int mLeftHandleX;
     private int mRightHandleX;
 
-    // current offset of user's dragging
-    private int mTouchDragOffset = 0;
+    // current offset of rotary widget along the x axis
+    private int mRotaryOffsetX = 0;
 
     // state of the animation used to bring the handle back to its start position when
     // the user lets go before triggering an action
     private boolean mAnimating = false;
-    private long mAnimationEndTime;
-    private int mAnimatingDelta;
-    private AccelerateInterpolator mInterpolator;
+    private long mAnimationStartTime;
+    private long mAnimationDuration;
+    private int mAnimatingDeltaXStart;   // the animation will interpolate from this delta to zero
+    private int mAnimatingDeltaXEnd;
 
-    /**
-     * True after triggering an action if the user of {@link OnDialTriggerListener} wants to
-     * freeze the UI (until they transition to another screen).
-     */
-    private boolean mFrozen = false;
+    private DecelerateInterpolator mInterpolator;
 
     /**
      * If the user is currently dragging something.
@@ -91,8 +90,8 @@
 
     // Vibration (haptic feedback)
     private Vibrator mVibrator;
-    private static final long VIBRATE_SHORT = 60;  // msec
-    private static final long VIBRATE_LONG = 100;  // msec
+    private static final long VIBRATE_SHORT = 30;  // msec
+    private static final long VIBRATE_LONG = 60;  // msec
 
     /**
      * The drawable for the arrows need to be scrunched this many dips towards the rotary bg below
@@ -108,17 +107,37 @@
     /**
      * How far from the edge of the screen the user must drag to trigger the event.
      */
-    private static final int EDGE_TRIGGER_DIP = 65;
+    private static final int EDGE_TRIGGER_DIP = 100;
 
     /**
      * Dimensions of arc in background drawable.
      */
     static final int OUTER_ROTARY_RADIUS_DIP = 390;
     static final int ROTARY_STROKE_WIDTH_DIP = 83;
-    private static final int ANIMATION_DURATION_MILLIS = 300;
+    static final int SNAP_BACK_ANIMATION_DURATION_MILLIS = 300;
+    static final int SPIN_ANIMATION_DURATION_MILLIS = 800;
 
-    private static final boolean DRAW_CENTER_DIMPLE = false;
+    private static final boolean DRAW_CENTER_DIMPLE = true;
     private int mEdgeTriggerThresh;
+    private int mDimpleWidth;
+    private int mBackgroundWidth;
+    private int mBackgroundHeight;
+    private final int mOuterRadius;
+    private final int mInnerRadius;
+    private int mDimpleSpacing;
+
+    private VelocityTracker mVelocityTracker;
+    private int mMinimumVelocity;
+    private int mMaximumVelocity;
+
+    /**
+     * The number of dimples we are flinging when we do the "spin" animation.  Used to know when to
+     * wrap the icons back around so they "rotate back" onto the screen.
+     * @see #updateAnimation()
+     */
+    private int mDimplesOfFling = 0;
+
+
 
     public RotarySelector(Context context) {
         this(context, null);
@@ -152,9 +171,31 @@
         mArrowLongLeft.setBounds(0, 0, arrowW, arrowH);
         mArrowLongRight.setBounds(0, 0, arrowW, arrowH);
 
-        mInterpolator = new AccelerateInterpolator();
+        mInterpolator = new DecelerateInterpolator(1f);
 
         mEdgeTriggerThresh = (int) (mDensity * EDGE_TRIGGER_DIP);
+
+        mDimpleWidth = mDimple.getIntrinsicWidth();
+
+        mBackgroundWidth = mBackground.getIntrinsicWidth();
+        mBackgroundHeight = mBackground.getIntrinsicHeight();
+        mOuterRadius = (int) (mDensity * OUTER_ROTARY_RADIUS_DIP);
+        mInnerRadius = (int) ((OUTER_ROTARY_RADIUS_DIP - ROTARY_STROKE_WIDTH_DIP) * mDensity);
+
+        final ViewConfiguration configuration = ViewConfiguration.get(mContext);
+        mMinimumVelocity = configuration.getScaledMinimumFlingVelocity() * 2;
+        mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
+    }
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+
+        mLeftHandleX = (int) (EDGE_PADDING_DIP * mDensity) + mDimpleWidth / 2;
+        mRightHandleX =
+                getWidth() - (int) (EDGE_PADDING_DIP * mDensity) - mDimpleWidth / 2;
+
+        mDimpleSpacing = (getWidth() / 2) - mLeftHandleX;
     }
 
     /**
@@ -214,7 +255,7 @@
         final int width = MeasureSpec.getSize(widthMeasureSpec);  // screen width
 
         final int arrowH = mArrowShortLeftAndRight.getIntrinsicHeight();
-        final int backgroundH = mBackground.getIntrinsicHeight();
+        final int backgroundH = mBackgroundHeight;
 
         // by making the height less than arrow + bg, arrow and bg will be scrunched together,
         // overlaying somewhat (though on transparent portions of the drawable).
@@ -224,44 +265,26 @@
         setMeasuredDimension(width, backgroundH + arrowH - arrowScrunch);
     }
 
-    @Override
-    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-        super.onSizeChanged(w, h, oldw, oldh);
-
-        mLeftHandleX = (int) (EDGE_PADDING_DIP * mDensity) + mDimple.getIntrinsicWidth() / 2;
-        mRightHandleX =
-                getWidth() - (int) (EDGE_PADDING_DIP * mDensity) - mDimple.getIntrinsicWidth() / 2;
-    }
-
 //    private Paint mPaint = new Paint();
 
     @Override
     protected void onDraw(Canvas canvas) {
         super.onDraw(canvas);
         if (DBG) {
-            log(String.format("onDraw: mAnimating=%s, mTouchDragOffset=%d, mGrabbedState=%d," +
-                    "mFrozen=%s",
-                    mAnimating, mTouchDragOffset, mGrabbedState, mFrozen));
+            log(String.format("onDraw: mAnimating=%s, mRotaryOffsetX=%d, mGrabbedState=%d",
+                    mAnimating, mRotaryOffsetX, mGrabbedState));
         }
 
         final int height = getHeight();
 
         // update animating state before we draw anything
-        if (mAnimating && !mFrozen) {
-            long millisLeft = mAnimationEndTime - currentAnimationTimeMillis();
-            if (DBG) log("millisleft for animating: " + millisLeft);
-            if (millisLeft <= 0) {
-                reset();
-            } else {
-                float interpolation = mInterpolator.getInterpolation(
-                        (float) millisLeft / ANIMATION_DURATION_MILLIS);
-                mTouchDragOffset = (int) (mAnimatingDelta * interpolation);
-            }
+        if (mAnimating) {
+            updateAnimation();
         }
 
         // Background:
-        final int backgroundW = mBackground.getIntrinsicWidth();
-        final int backgroundH = mBackground.getIntrinsicHeight();
+        final int backgroundW = mBackgroundWidth;
+        final int backgroundH = mBackgroundHeight;
         final int backgroundY = height - backgroundH;
         if (DBG) log("- Background INTRINSIC: " + backgroundW + " x " + backgroundH);
         mBackground.setBounds(0, backgroundY,
@@ -293,16 +316,13 @@
 //        float or = OUTER_ROTARY_RADIUS_DIP * mDensity;
 //        canvas.drawCircle(getWidth() / 2, or + mBackground.getBounds().top, or, mPaint);
 
-        final int outerRadius = (int) (mDensity * OUTER_ROTARY_RADIUS_DIP);
-        final int innerRadius =
-                (int) ((OUTER_ROTARY_RADIUS_DIP - ROTARY_STROKE_WIDTH_DIP) * mDensity);
         final int bgTop = mBackground.getBounds().top;
         {
-            final int xOffset = mLeftHandleX + mTouchDragOffset;
+            final int xOffset = mLeftHandleX + mRotaryOffsetX;
             final int drawableY = getYOnArc(
                     mBackground,
-                    innerRadius,
-                    outerRadius,
+                    mInnerRadius,
+                    mOuterRadius,
                     xOffset);
 
             drawCentered(mDimple, canvas, xOffset, drawableY + bgTop);
@@ -312,22 +332,22 @@
         }
 
         if (DRAW_CENTER_DIMPLE) {
-            final int xOffset = getWidth() / 2 + mTouchDragOffset;
+            final int xOffset = getWidth() / 2 + mRotaryOffsetX;
             final int drawableY = getYOnArc(
                     mBackground,
-                    innerRadius,
-                    outerRadius,
+                    mInnerRadius,
+                    mOuterRadius,
                     xOffset);
 
             drawCentered(mDimple, canvas, xOffset, drawableY + bgTop);
         }
 
         {
-            final int xOffset = mRightHandleX + mTouchDragOffset;
+            final int xOffset = mRightHandleX + mRotaryOffsetX;
             final int drawableY = getYOnArc(
                     mBackground,
-                    innerRadius,
-                    outerRadius,
+                    mInnerRadius,
+                    mOuterRadius,
                     xOffset);
 
             drawCentered(mDimple, canvas, xOffset, drawableY + bgTop);
@@ -336,7 +356,33 @@
             }
         }
 
-        if (mAnimating) invalidate();
+        // draw extra left hand dimples
+        int dimpleLeft = mRotaryOffsetX + mLeftHandleX - mDimpleSpacing;
+        final int halfdimple = mDimpleWidth / 2;
+        while (dimpleLeft > -halfdimple) {
+            final int drawableY = getYOnArc(
+                    mBackground,
+                    mInnerRadius,
+                    mOuterRadius,
+                    dimpleLeft);
+
+            drawCentered(mDimple, canvas, dimpleLeft, drawableY + bgTop);
+            dimpleLeft -= mDimpleSpacing;
+        }
+
+        // draw extra right hand dimples
+        int dimpleRight = mRotaryOffsetX + mRightHandleX + mDimpleSpacing;
+        final int rightThresh = mRight + halfdimple;
+        while (dimpleRight < rightThresh) {
+            final int drawableY = getYOnArc(
+                    mBackground,
+                    mInnerRadius,
+                    mOuterRadius,
+                    dimpleRight);
+
+            drawCentered(mDimple, canvas, dimpleRight, drawableY + bgTop);
+            dimpleRight += mDimpleSpacing;
+        }
     }
 
     /**
@@ -383,12 +429,17 @@
      */
     @Override
     public boolean onTouchEvent(MotionEvent event) {
-        if (mAnimating || mFrozen) {
+        if (mAnimating) {
             return true;
         }
+        if (mVelocityTracker == null) {
+            mVelocityTracker = VelocityTracker.obtain();
+        }
+        mVelocityTracker.addMovement(event);
+
 
         final int eventX = (int) event.getX();
-        final int hitWindow = mDimple.getIntrinsicWidth();
+        final int hitWindow = mDimpleWidth;
 
         final int action = event.getAction();
         switch (action) {
@@ -400,12 +451,12 @@
                     invalidate();
                 }
                 if (eventX < mLeftHandleX + hitWindow) {
-                    mTouchDragOffset = eventX - mLeftHandleX;
+                    mRotaryOffsetX = eventX - mLeftHandleX;
                     mGrabbedState = LEFT_HANDLE_GRABBED;
                     invalidate();
                     vibrate(VIBRATE_SHORT);
                 } else if (eventX > mRightHandleX - hitWindow) {
-                    mTouchDragOffset = eventX - mRightHandleX;
+                    mRotaryOffsetX = eventX - mRightHandleX;
                     mGrabbedState = RIGHT_HANDLE_GRABBED;
                     invalidate();
                     vibrate(VIBRATE_SHORT);
@@ -415,18 +466,38 @@
             case MotionEvent.ACTION_MOVE:
                 if (DBG) log("touch-move");
                 if (mGrabbedState == LEFT_HANDLE_GRABBED) {
-                    mTouchDragOffset = eventX - mLeftHandleX;
+                    mRotaryOffsetX = eventX - mLeftHandleX;
                     invalidate();
                     if (eventX >= getRight() - mEdgeTriggerThresh && !mTriggered) {
                         mTriggered = true;
-                        mFrozen = dispatchTriggerEvent(OnDialTriggerListener.LEFT_HANDLE);
+                        dispatchTriggerEvent(OnDialTriggerListener.LEFT_HANDLE);
+                        final VelocityTracker velocityTracker = mVelocityTracker;
+                        velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
+                        final int velocity = Math.max(mMinimumVelocity, (int) velocityTracker.getXVelocity());
+                        mDimplesOfFling = Math.max(
+                                8,
+                                Math.abs(velocity / mDimpleSpacing));
+                        startAnimationWithVelocity(
+                                eventX - mLeftHandleX,
+                                mDimplesOfFling * mDimpleSpacing,
+                                velocity);
                     }
                 } else if (mGrabbedState == RIGHT_HANDLE_GRABBED) {
-                    mTouchDragOffset = eventX - mRightHandleX;
+                    mRotaryOffsetX = eventX - mRightHandleX;
                     invalidate();
                     if (eventX <= mEdgeTriggerThresh && !mTriggered) {
                         mTriggered = true;
-                        mFrozen = dispatchTriggerEvent(OnDialTriggerListener.RIGHT_HANDLE);
+                        dispatchTriggerEvent(OnDialTriggerListener.RIGHT_HANDLE);
+                        final VelocityTracker velocityTracker = mVelocityTracker;
+                        velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
+                        final int velocity = Math.min(-mMinimumVelocity, (int) velocityTracker.getXVelocity());
+                        mDimplesOfFling = Math.max(
+                                8,
+                                Math.abs(velocity / mDimpleSpacing));
+                        startAnimationWithVelocity(
+                                eventX - mRightHandleX,
+                                -(mDimplesOfFling * mDimpleSpacing),
+                                velocity);
                     }
                 }
                 break;
@@ -435,32 +506,85 @@
                 // handle animating back to start if they didn't trigger
                 if (mGrabbedState == LEFT_HANDLE_GRABBED
                         && Math.abs(eventX - mLeftHandleX) > 5) {
-                    mAnimating = true;
-                    mAnimationEndTime = currentAnimationTimeMillis() + ANIMATION_DURATION_MILLIS;
-                    mAnimatingDelta = eventX - mLeftHandleX;
+                    // set up "snap back" animation
+                    startAnimation(eventX - mLeftHandleX, 0, SNAP_BACK_ANIMATION_DURATION_MILLIS);
                 } else if (mGrabbedState == RIGHT_HANDLE_GRABBED
                         && Math.abs(eventX - mRightHandleX) > 5) {
-                    mAnimating = true;
-                    mAnimationEndTime = currentAnimationTimeMillis() + ANIMATION_DURATION_MILLIS;
-                    mAnimatingDelta = eventX - mRightHandleX;
+                    // set up "snap back" animation
+                    startAnimation(eventX - mRightHandleX, 0, SNAP_BACK_ANIMATION_DURATION_MILLIS);
                 }
-
-                mTouchDragOffset = 0;
+                mRotaryOffsetX = 0;
                 mGrabbedState = NOTHING_GRABBED;
                 invalidate();
+                if (mVelocityTracker != null) {
+                    mVelocityTracker.recycle(); // wishin' we had generational GC
+                    mVelocityTracker = null;
+                }
                 break;
             case MotionEvent.ACTION_CANCEL:
                 if (DBG) log("touch-cancel");
                 reset();
                 invalidate();
+                if (mVelocityTracker != null) {
+                    mVelocityTracker.recycle();
+                    mVelocityTracker = null;
+                }
                 break;
         }
         return true;
     }
 
+    private void startAnimation(int startX, int endX, int duration) {
+        mAnimating = true;
+        mAnimationStartTime = currentAnimationTimeMillis();
+        mAnimationDuration = duration;
+        mAnimatingDeltaXStart = startX;
+        mAnimatingDeltaXEnd = endX;
+        mGrabbedState = NOTHING_GRABBED;
+        mDimplesOfFling = 0;
+        invalidate();
+    }
+
+    private void startAnimationWithVelocity(int startX, int endX, int pixelsPerSecond) {
+        mAnimating = true;
+        mAnimationStartTime = currentAnimationTimeMillis();
+        mAnimationDuration = 1000 * (endX - startX) / pixelsPerSecond;
+        mAnimatingDeltaXStart = startX;
+        mAnimatingDeltaXEnd = endX;
+        mGrabbedState = NOTHING_GRABBED;
+        invalidate();
+    }
+
+    private void updateAnimation() {
+        final long millisSoFar = currentAnimationTimeMillis() - mAnimationStartTime;
+        final long millisLeft = mAnimationDuration - millisSoFar;
+        final int totalDeltaX = mAnimatingDeltaXStart - mAnimatingDeltaXEnd;
+        if (DBG) log("millisleft for animating: " + millisLeft);
+        if (millisLeft <= 0) {
+            reset();
+            return;
+        }
+        // from 0 to 1 as animation progresses
+        float interpolation =
+                mInterpolator.getInterpolation((float) millisSoFar / mAnimationDuration);
+        final int dx = (int) (totalDeltaX * (1 - interpolation));
+        mRotaryOffsetX = mAnimatingDeltaXEnd + dx;
+        if (mDimplesOfFling > 0) {
+            if (mRotaryOffsetX < 4 * mDimpleSpacing) {
+                // wrap around on fling left
+                mRotaryOffsetX += (4 + mDimplesOfFling - 4) * mDimpleSpacing;
+            } else if (mRotaryOffsetX > 4 * mDimpleSpacing) {
+                // wrap around on fling right
+                mRotaryOffsetX -= (4 + mDimplesOfFling - 4) * mDimpleSpacing;
+            }
+        }
+        invalidate();
+    }
+
     private void reset() {
         mAnimating = false;
-        mTouchDragOffset = 0;
+        mRotaryOffsetX = 0;
+        mDimplesOfFling = 0;
         mGrabbedState = NOTHING_GRABBED;
         mTriggered = false;
     }
@@ -470,7 +594,8 @@
      */
     private synchronized void vibrate(long duration) {
         if (mVibrator == null) {
-            mVibrator = (android.os.Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
+            mVibrator = (android.os.Vibrator)
+                    getContext().getSystemService(Context.VIBRATOR_SERVICE);
         }
         mVibrator.vibrate(duration);
     }
@@ -504,12 +629,11 @@
     /**
      * Dispatches a trigger event to our listener.
      */
-    private boolean dispatchTriggerEvent(int whichHandle) {
+    private void dispatchTriggerEvent(int whichHandle) {
         vibrate(VIBRATE_LONG);
         if (mOnDialTriggerListener != null) {
-            return mOnDialTriggerListener.onDialTrigger(this, whichHandle);
+            mOnDialTriggerListener.onDialTrigger(this, whichHandle);
         }
-        return false;
     }
 
     /**
@@ -530,22 +654,13 @@
         public static final int RIGHT_HANDLE = 2;
 
         /**
-         * @hide
-         * The center handle is currently unused.
-         */
-        public static final int CENTER_HANDLE = 3;
-
-        /**
          * Called when the dial is triggered.
          *
          * @param v The view that was triggered
          * @param whichHandle  Which "dial handle" the user grabbed,
-         *        either {@link #LEFT_HANDLE}, {@link #RIGHT_HANDLE}, or
-         *        {@link #CENTER_HANDLE}.
-         * @return Whether the widget should freeze (e.g when the action goes to another screen,
-         *         you want the UI to stay put until the transition occurs).
+         *        either {@link #LEFT_HANDLE}, {@link #RIGHT_HANDLE}.
          */
-        boolean onDialTrigger(View v, int whichHandle);
+        void onDialTrigger(View v, int whichHandle);
     }
 
 
diff --git a/core/java/com/google/android/mms/pdu/GenericPdu.java b/core/java/com/google/android/mms/pdu/GenericPdu.java
index 46c6e00..705de6a 100644
--- a/core/java/com/google/android/mms/pdu/GenericPdu.java
+++ b/core/java/com/google/android/mms/pdu/GenericPdu.java
@@ -89,4 +89,25 @@
     public void setMmsVersion(int value) throws InvalidHeaderValueException {
         mPduHeaders.setOctet(value, PduHeaders.MMS_VERSION);
     }
+
+    /**
+     * Get From value.
+     * From-value = Value-length
+     *      (Address-present-token Encoded-string-value | Insert-address-token)
+     *
+     * @return the value
+     */
+    public EncodedStringValue getFrom() {
+       return mPduHeaders.getEncodedStringValue(PduHeaders.FROM);
+    }
+
+    /**
+     * Set From value.
+     *
+     * @param value the value
+     * @throws NullPointerException if the value is null.
+     */
+    public void setFrom(EncodedStringValue value) {
+        mPduHeaders.setEncodedStringValue(value, PduHeaders.FROM);
+    }
 }
diff --git a/core/java/com/google/android/mms/pdu/PduComposer.java b/core/java/com/google/android/mms/pdu/PduComposer.java
index 094e992..8b31936 100644
--- a/core/java/com/google/android/mms/pdu/PduComposer.java
+++ b/core/java/com/google/android/mms/pdu/PduComposer.java
@@ -450,6 +450,29 @@
         appendQuotedString(str.getBytes());
     }
 
+    private EncodedStringValue appendAddressType(EncodedStringValue address) {
+        EncodedStringValue temp = null;
+
+        try {
+            int addressType = checkAddressType(address.getString());
+            temp = EncodedStringValue.copy(address);
+            if (PDU_PHONE_NUMBER_ADDRESS_TYPE == addressType) {
+                // Phone number.
+                temp.appendTextString(STRING_PHONE_NUMBER_ADDRESS_TYPE.getBytes());
+            } else if (PDU_IPV4_ADDRESS_TYPE == addressType) {
+                // Ipv4 address.
+                temp.appendTextString(STRING_IPV4_ADDRESS_TYPE.getBytes());
+            } else if (PDU_IPV6_ADDRESS_TYPE == addressType) {
+                // Ipv6 address.
+                temp.appendTextString(STRING_IPV6_ADDRESS_TYPE.getBytes());
+            }
+        } catch (NullPointerException e) {
+            return null;
+        }
+
+        return temp;
+    }
+
     /**
      * Append header to mMessage.
      */
@@ -489,21 +512,8 @@
 
                 EncodedStringValue temp;
                 for (int i = 0; i < addr.length; i++) {
-                    try {
-                        int addressType = checkAddressType(addr[i].getString());
-                        temp = EncodedStringValue.copy(addr[i]);
-                        if (PDU_PHONE_NUMBER_ADDRESS_TYPE == addressType) {
-                            // Phone number.
-                            temp.appendTextString(
-                                    STRING_PHONE_NUMBER_ADDRESS_TYPE.getBytes());
-                        } else if (PDU_IPV4_ADDRESS_TYPE == addressType) {
-                            // Ipv4 address.
-                            temp.appendTextString(STRING_IPV4_ADDRESS_TYPE.getBytes());
-                        } else if (PDU_IPV6_ADDRESS_TYPE == addressType) {
-                            // Ipv6 address.
-                            temp.appendTextString(STRING_IPV6_ADDRESS_TYPE.getBytes());
-                        }
-                    } catch (NullPointerException e) {
+                    temp = appendAddressType(addr[i]);
+                    if (temp == null) {
                         return PDU_COMPOSE_CONTENT_ERROR;
                     }
 
@@ -530,7 +540,13 @@
 
                     // Address-present-token = <Octet 128>
                     append(PduHeaders.FROM_ADDRESS_PRESENT_TOKEN);
-                    appendEncodedString(from);
+
+                    temp = appendAddressType(from);
+                    if (temp == null) {
+                        return PDU_COMPOSE_CONTENT_ERROR;
+                    }
+
+                    appendEncodedString(temp);
 
                     int flen = fstart.getLength();
                     mStack.pop();
diff --git a/core/java/com/google/android/mms/pdu/ReadRecInd.java b/core/java/com/google/android/mms/pdu/ReadRecInd.java
index 0a4dbf0..880e3ac 100644
--- a/core/java/com/google/android/mms/pdu/ReadRecInd.java
+++ b/core/java/com/google/android/mms/pdu/ReadRecInd.java
@@ -73,27 +73,6 @@
     }
 
     /**
-     * Get From value.
-     * From-value = Value-length
-     *      (Address-present-token Encoded-string-value | Insert-address-token)
-     *
-     * @return the value
-     */
-    public EncodedStringValue getFrom() {
-       return mPduHeaders.getEncodedStringValue(PduHeaders.FROM);
-    }
-
-    /**
-     * Set From value.
-     *
-     * @param value the value
-     * @throws NullPointerException if the value is null.
-     */
-    public void setFrom(EncodedStringValue value) {
-        mPduHeaders.setEncodedStringValue(value, PduHeaders.FROM);
-    }
-
-    /**
      * Get Message-ID value.
      *
      * @return the value
diff --git a/core/java/com/google/android/mms/pdu/SendReq.java b/core/java/com/google/android/mms/pdu/SendReq.java
index 9ea6e47..597cd00 100644
--- a/core/java/com/google/android/mms/pdu/SendReq.java
+++ b/core/java/com/google/android/mms/pdu/SendReq.java
@@ -226,27 +226,6 @@
     }
 
     /**
-     * Get From value.
-     * From-value = Value-length
-     *      (Address-present-token Encoded-string-value | Insert-address-token)
-     *
-     * @return the value
-     */
-    public EncodedStringValue getFrom() {
-       return mPduHeaders.getEncodedStringValue(PduHeaders.FROM);
-    }
-
-    /**
-     * Set From value.
-     *
-     * @param value the value
-     * @throws NullPointerException if the value is null.
-     */
-    public void setFrom(EncodedStringValue value) {
-        mPduHeaders.setEncodedStringValue(value, PduHeaders.FROM);
-    }
-
-    /**
      * Get X-Mms-Message-Class value.
      * Message-class-value = Class-identifier | Token-text
      * Class-identifier = Personal | Advertisement | Informational | Auto
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index ce2b10c..6b92994 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -55,7 +55,7 @@
 
     jobject     mCameraJObjectWeak;     // weak reference to java object
     jclass      mCameraJClass;          // strong reference to java class
-    sp<Camera>  mCamera;                // strong reference to native object 
+    sp<Camera>  mCamera;                // strong reference to native object
     Mutex       mLock;
 };
 
@@ -391,20 +391,26 @@
     }
 }
 
-static jint android_hardware_Camera_lock(JNIEnv *env, jobject thiz)
+static void android_hardware_Camera_lock(JNIEnv *env, jobject thiz)
 {
     LOGV("lock");
     sp<Camera> camera = get_native_camera(env, thiz, NULL);
-    if (camera == 0) return INVALID_OPERATION;
-    return (jint) camera->lock();
+    if (camera == 0) return;
+
+    if (camera->lock() != NO_ERROR) {
+        jniThrowException(env, "java/lang/RuntimeException", "lock failed");
+    }
 }
 
-static jint android_hardware_Camera_unlock(JNIEnv *env, jobject thiz)
+static void android_hardware_Camera_unlock(JNIEnv *env, jobject thiz)
 {
     LOGV("unlock");
     sp<Camera> camera = get_native_camera(env, thiz, NULL);
-    if (camera == 0) return INVALID_OPERATION;
-    return (jint) camera->unlock();
+    if (camera == 0) return;
+
+    if (camera->unlock() != NO_ERROR) {
+        jniThrowException(env, "java/lang/RuntimeException", "unlock failed");
+    }
 }
 
 //-------------------------------------------------
@@ -450,10 +456,10 @@
     "()V",
     (void*)android_hardware_Camera_reconnect },
   { "lock",
-    "()I",
+    "()V",
     (void*)android_hardware_Camera_lock },
   { "unlock",
-    "()I",
+    "()V",
     (void*)android_hardware_Camera_unlock },
 };
 
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
index e703ed8..e37e832 100644
--- a/core/jni/android_server_BluetoothEventLoop.cpp
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -48,6 +48,8 @@
 static jmethodID method_onDeviceDisconnectRequested;
 
 static jmethodID method_onCreatePairedDeviceResult;
+static jmethodID method_onCreateDeviceResult;
+static jmethodID method_onDiscoverServicesResult;
 static jmethodID method_onGetDeviceServiceChannelResult;
 
 static jmethodID method_onRequestPinCode;
@@ -92,6 +94,10 @@
 
     method_onCreatePairedDeviceResult = env->GetMethodID(clazz, "onCreatePairedDeviceResult",
                                                          "(Ljava/lang/String;I)V");
+    method_onCreateDeviceResult = env->GetMethodID(clazz, "onCreateDeviceResult",
+                                                         "(Ljava/lang/String;Z)V");
+    method_onDiscoverServicesResult = env->GetMethodID(clazz, "onDiscoverServicesResult",
+                                                         "(Ljava/lang/String;Z)V");
 
     method_onAgentAuthorize = env->GetMethodID(clazz, "onAgentAuthorize",
                                                "(Ljava/lang/String;Ljava/lang/String;)Z");
@@ -1097,6 +1103,54 @@
     free(user);
 }
 
+void onCreateDeviceResult(DBusMessage *msg, void *user, void *n) {
+    LOGV(__FUNCTION__);
+
+    native_data_t *nat = (native_data_t *)n;
+    const char *address= (const char *)user;
+    DBusError err;
+    dbus_error_init(&err);
+    JNIEnv *env;
+    nat->vm->GetEnv((void**)&env, nat->envVer);
+
+    LOGV("... Address = %s", address);
+
+    bool result = JNI_TRUE;
+    if (dbus_set_error_from_message(&err, msg)) {
+        LOG_AND_FREE_DBUS_ERROR(&err);
+        result = JNI_FALSE;
+    }
+    env->CallVoidMethod(nat->me,
+                        method_onCreateDeviceResult,
+                        env->NewStringUTF(address),
+                        result);
+    free(user);
+}
+
+void onDiscoverServicesResult(DBusMessage *msg, void *user, void *n) {
+    LOGV(__FUNCTION__);
+
+    native_data_t *nat = (native_data_t *)n;
+    const char *path = (const char *)user;
+    DBusError err;
+    dbus_error_init(&err);
+    JNIEnv *env;
+    nat->vm->GetEnv((void**)&env, nat->envVer);
+
+    LOGV("... Device Path = %s", path);
+
+    bool result = JNI_TRUE;
+    if (dbus_set_error_from_message(&err, msg)) {
+        LOG_AND_FREE_DBUS_ERROR(&err);
+        result = JNI_FALSE;
+    }
+    env->CallVoidMethod(nat->me,
+                        method_onDiscoverServicesResult,
+                        env->NewStringUTF(path),
+                        result);
+    free(user);
+}
+
 void onGetDeviceServiceChannelResult(DBusMessage *msg, void *user, void *n) {
     LOGV(__FUNCTION__);
 
diff --git a/core/jni/android_server_BluetoothService.cpp b/core/jni/android_server_BluetoothService.cpp
index 0b71acb..c2f93eea 100644
--- a/core/jni/android_server_BluetoothService.cpp
+++ b/core/jni/android_server_BluetoothService.cpp
@@ -66,6 +66,8 @@
                                             DBusMessage *msg,
                                             void *data);
 void onCreatePairedDeviceResult(DBusMessage *msg, void *user, void *nat);
+void onDiscoverServicesResult(DBusMessage *msg, void *user, void *nat);
+void onCreateDeviceResult(DBusMessage *msg, void *user, void *nat);
 
 
 /** Get native data stored in the opaque (Java code maintained) pointer mNativeData
@@ -385,33 +387,24 @@
 
 static jboolean removeDeviceNative(JNIEnv *env, jobject object, jstring object_path) {
     LOGV(__FUNCTION__);
-    jboolean result = JNI_FALSE;
 #ifdef HAVE_BLUETOOTH
     native_data_t *nat = get_native_data(env, object);
     if (nat) {
         const char *c_object_path = env->GetStringUTFChars(object_path, NULL);
-        DBusError err;
-        dbus_error_init(&err);
-        DBusMessage *reply =
-            dbus_func_args_error(env, nat->conn, &err,
-                                 get_adapter_path(env, object),
-                                 DBUS_ADAPTER_IFACE, "RemoveDevice",
-                                 DBUS_TYPE_OBJECT_PATH, &c_object_path,
-                                 DBUS_TYPE_INVALID);
-        if (!reply) {
-            if (dbus_error_is_set(&err)) {
-                LOG_AND_FREE_DBUS_ERROR(&err);
-            } else
-                LOGE("DBus reply is NULL in function %s", __FUNCTION__);
-            result = JNI_FALSE;
-        } else {
-            result = JNI_TRUE;
-        }
+        bool ret = dbus_func_args_async(env, nat->conn, -1,
+                                        NULL,
+                                        NULL,
+                                        NULL,
+                                        get_adapter_path(env, object),
+                                        DBUS_ADAPTER_IFACE,
+                                        "RemoveDevice",
+                                        DBUS_TYPE_OBJECT_PATH, &c_object_path,
+                                        DBUS_TYPE_INVALID);
         env->ReleaseStringUTFChars(object_path, c_object_path);
-        if (reply) dbus_message_unref(reply);
+        return ret ? JNI_TRUE : JNI_FALSE;
     }
 #endif
-    return result;
+    return JNI_FALSE;
 }
 
 static jint enableNative(JNIEnv *env, jobject object) {
@@ -757,6 +750,75 @@
 #endif
 }
 
+
+static jboolean createDeviceNative(JNIEnv *env, jobject object,
+                                                jstring address) {
+    LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+    native_data_t *nat = get_native_data(env, object);
+    jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
+    struct event_loop_native_data_t *eventLoopNat =
+            get_EventLoop_native_data(env, eventLoop);
+
+    if (nat && eventLoopNat) {
+        const char *c_address = env->GetStringUTFChars(address, NULL);
+        LOGV("... address = %s", c_address);
+        char *context_address = (char *)calloc(BTADDR_SIZE, sizeof(char));
+        strlcpy(context_address, c_address, BTADDR_SIZE);  // for callback
+
+        bool ret = dbus_func_args_async(env, nat->conn, -1,
+                                        onCreateDeviceResult,
+                                        context_address,
+                                        eventLoopNat,
+                                        get_adapter_path(env, object),
+                                        DBUS_ADAPTER_IFACE,
+                                        "CreateDevice",
+                                        DBUS_TYPE_STRING, &c_address,
+                                        DBUS_TYPE_INVALID);
+        env->ReleaseStringUTFChars(address, c_address);
+        return ret ? JNI_TRUE : JNI_FALSE;
+    }
+#endif
+    return JNI_FALSE;
+}
+
+static jboolean discoverServicesNative(JNIEnv *env, jobject object,
+                                               jstring path, jstring pattern) {
+    LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+    native_data_t *nat = get_native_data(env, object);
+    jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
+    struct event_loop_native_data_t *eventLoopNat =
+            get_EventLoop_native_data(env, eventLoop);
+
+    if (nat && eventLoopNat) {
+        const char *c_path = env->GetStringUTFChars(path, NULL);
+        const char *c_pattern = env->GetStringUTFChars(pattern, NULL);
+        int len = env->GetStringLength(path) + 1;
+        char *context_path = (char *)calloc(len, sizeof(char));
+        strlcpy(context_path, c_path, len);  // for callback
+
+        LOGV("... Object Path = %s", c_path);
+        LOGV("... Pattern = %s, strlen = %d", c_pattern, strlen(c_pattern));
+
+        bool ret = dbus_func_args_async(env, nat->conn, -1,
+                                        onDiscoverServicesResult,
+                                        context_path,
+                                        eventLoopNat,
+                                        c_path,
+                                        DBUS_DEVICE_IFACE,
+                                        "DiscoverServices",
+                                        DBUS_TYPE_STRING, &c_pattern,
+                                        DBUS_TYPE_INVALID);
+        env->ReleaseStringUTFChars(path, c_path);
+        env->ReleaseStringUTFChars(pattern, c_pattern);
+        return ret ? JNI_TRUE : JNI_FALSE;
+    }
+#endif
+    return JNI_FALSE;
+}
+
+
 static JNINativeMethod sMethods[] = {
      /* name, signature, funcPtr */
     {"classInitNative", "()V", (void*)classInitNative},
@@ -797,6 +859,8 @@
             (void *)cancelPairingUserInputNative},
     {"setDevicePropertyBooleanNative", "(Ljava/lang/String;Ljava/lang/String;I)Z",
             (void *)setDevicePropertyBooleanNative},
+    {"createDeviceNative", "(Ljava/lang/String;)Z", (void *)createDeviceNative},
+    {"discoverServicesNative", "(Ljava/lang/String;Ljava/lang/String;)Z", (void *)discoverServicesNative},
 };
 
 int register_android_server_BluetoothService(JNIEnv *env) {
diff --git a/core/res/res/anim/activity_close_enter.xml b/core/res/res/anim/activity_close_enter.xml
index 9d1ef53..f1258e8 100644
--- a/core/res/res/anim/activity_close_enter.xml
+++ b/core/res/res/anim/activity_close_enter.xml
@@ -21,5 +21,5 @@
         android:interpolator="@anim/decelerate_interpolator"
         android:zAdjustment="top">
 	<translate android:fromXDelta="-100%" android:toXDelta="0"
-        android:duration="@android:integer/config_mediumAnimTime"/>
+        android:duration="@android:integer/config_shortAnimTime"/>
 </set>
diff --git a/core/res/res/anim/activity_close_exit.xml b/core/res/res/anim/activity_close_exit.xml
index 47cb6d6..bf3d8cd3 100644
--- a/core/res/res/anim/activity_close_exit.xml
+++ b/core/res/res/anim/activity_close_exit.xml
@@ -20,5 +20,5 @@
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:interpolator="@anim/decelerate_interpolator">
 	<translate android:fromXDelta="0%" android:toXDelta="33%"
-        android:duration="@android:integer/config_mediumAnimTime"/>
+        android:duration="@android:integer/config_shortAnimTime"/>
 </set>
diff --git a/core/res/res/anim/activity_open_enter.xml b/core/res/res/anim/activity_open_enter.xml
index e4c7e9b..a9ea381 100644
--- a/core/res/res/anim/activity_open_enter.xml
+++ b/core/res/res/anim/activity_open_enter.xml
@@ -20,5 +20,5 @@
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:interpolator="@anim/decelerate_interpolator">
 	<translate android:fromXDelta="33%" android:toXDelta="0"
-        android:duration="@android:integer/config_mediumAnimTime"/>
+        android:duration="@android:integer/config_shortAnimTime"/>
 </set>
diff --git a/core/res/res/anim/activity_open_exit.xml b/core/res/res/anim/activity_open_exit.xml
index 9d47b7f..b04b79e 100644
--- a/core/res/res/anim/activity_open_exit.xml
+++ b/core/res/res/anim/activity_open_exit.xml
@@ -21,5 +21,5 @@
         android:interpolator="@anim/decelerate_interpolator"
         android:zAdjustment="top">
 	<translate android:fromXDelta="0%" android:toXDelta="-100%"
-        android:duration="@android:integer/config_mediumAnimTime"/>
+        android:duration="@android:integer/config_shortAnimTime"/>
 </set>
diff --git a/core/res/res/anim/dialog_enter.xml b/core/res/res/anim/dialog_enter.xml
index 167f4bc..d4983c6 100644
--- a/core/res/res/anim/dialog_enter.xml
+++ b/core/res/res/anim/dialog_enter.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* //device/apps/common/res/anim/fade_in.xml
-**
+/*
 ** Copyright 2007, The Android Open Source Project
 **
 ** Licensed under the Apache License, Version 2.0 (the "License"); 
@@ -22,7 +21,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%p" android:pivotY="50%p"
+           android:pivotX="50%" android:pivotY="50%"
            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 d412cfb..2aa629a 100644
--- a/core/res/res/anim/dialog_exit.xml
+++ b/core/res/res/anim/dialog_exit.xml
@@ -1,7 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* //device/apps/common/res/anim/fade_out.xml
-**
+/*
 ** Copyright 2007, The Android Open Source Project
 **
 ** Licensed under the Apache License, Version 2.0 (the "License"); 
@@ -17,11 +16,12 @@
 ** limitations under the License.
 */
 -->
+
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         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%p" android:pivotY="50%p"
+           android:pivotX="50%" android:pivotY="50%"
            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
index deeb96b..8faa2c1 100644
--- a/core/res/res/anim/recent_enter.xml
+++ b/core/res/res/anim/recent_enter.xml
@@ -19,10 +19,10 @@
 
 <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" />
+    <scale android:fromXScale="0.9" android:toXScale="1.0"
+           android:fromYScale="0.9" android:toYScale="1.0"
+           android:pivotX="50%" android:pivotY="50%"
+           android:duration="@android:integer/config_shortAnimTime" />
     <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
-            android:duration="@android:integer/config_mediumAnimTime"/>
+            android:duration="@android:integer/config_shortAnimTime" />
 </set>
diff --git a/core/res/res/anim/recent_exit.xml b/core/res/res/anim/recent_exit.xml
index fed7014..9399329 100644
--- a/core/res/res/anim/recent_exit.xml
+++ b/core/res/res/anim/recent_exit.xml
@@ -18,12 +18,11 @@
 -->
 
 <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"/>
+        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:duration="@android:integer/config_shortAnimTime" />
+    <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+            android:duration="@android:integer/config_shortAnimTime"/>
 </set>
diff --git a/core/res/res/anim/task_open_exit.xml b/core/res/res/anim/task_open_exit.xml
index 98975fb9..db331b1 100644
--- a/core/res/res/anim/task_open_exit.xml
+++ b/core/res/res/anim/task_open_exit.xml
@@ -18,8 +18,7 @@
 -->
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
-        android:interpolator="@anim/decelerate_interpolator"
-        android:zAdjustment="top">
+        android:interpolator="@anim/decelerate_interpolator">
     <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"
diff --git a/core/res/res/anim/translucent_enter.xml b/core/res/res/anim/translucent_enter.xml
index fb4c1c3..04852a8 100644
--- a/core/res/res/anim/translucent_enter.xml
+++ b/core/res/res/anim/translucent_enter.xml
@@ -20,7 +20,7 @@
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:interpolator="@anim/decelerate_interpolator">
 	<translate android:fromXDelta="75%" android:toXDelta="0"
-        android:duration="@android:integer/config_mediumAnimTime"/>
+        android:duration="@android:integer/config_shortAnimTime"/>
     <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
-            android:duration="@android:integer/config_mediumAnimTime"/>
+            android:duration="@android:integer/config_shortAnimTime"/>
 </set>
diff --git a/core/res/res/anim/translucent_exit.xml b/core/res/res/anim/translucent_exit.xml
index 1d424e1..adaf3d1 100644
--- a/core/res/res/anim/translucent_exit.xml
+++ b/core/res/res/anim/translucent_exit.xml
@@ -20,7 +20,7 @@
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:interpolator="@anim/accelerate_interpolator">
 	<translate android:fromXDelta="0%" android:toXDelta="75%"
-        android:duration="@android:integer/config_mediumAnimTime"/>
+        android:duration="@android:integer/config_shortAnimTime"/>
     <alpha android:fromAlpha="1.0" android:toAlpha="0"
-            android:duration="@android:integer/config_mediumAnimTime"/>
+            android:duration="@android:integer/config_shortAnimTime"/>
 </set>
diff --git a/core/res/res/anim/wallpaper_close_enter.xml b/core/res/res/anim/wallpaper_close_enter.xml
index e4c7e9b..0d13009 100644
--- a/core/res/res/anim/wallpaper_close_enter.xml
+++ b/core/res/res/anim/wallpaper_close_enter.xml
@@ -17,8 +17,22 @@
 */
 -->
 
+<!-- This version zooms the new non-wallpaper down on top of the
+     wallpaper. -->
+<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" />
+</set>
+
+<!-- This version is a variation on the inter-activity slide that
+    also scales the wallpaper. -->
+<!--
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:interpolator="@anim/decelerate_interpolator">
 	<translate android:fromXDelta="33%" android:toXDelta="0"
         android:duration="@android:integer/config_mediumAnimTime"/>
 </set>
+-->
diff --git a/core/res/res/anim/wallpaper_close_exit.xml b/core/res/res/anim/wallpaper_close_exit.xml
index 16edec1..5d91e30 100644
--- a/core/res/res/anim/wallpaper_close_exit.xml
+++ b/core/res/res/anim/wallpaper_close_exit.xml
@@ -17,6 +17,22 @@
 */
 -->
 
+<!-- This version zooms the new non-wallpaper down on top of the
+     wallpaper.  The wallpaper here just stays fixed behind. -->
+<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=".5"
+           android:fromYScale="1.0" android:toYScale=".5"
+           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>
+
+<!-- This version is a variation on the inter-activity slide that
+    also scales the wallpaper. -->
+<!--
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:interpolator="@anim/decelerate_interpolator"
         android:zAdjustment="top">
@@ -27,3 +43,4 @@
 	<translate android:fromXDelta="0%" android:toXDelta="-100%"
         android:duration="@android:integer/config_mediumAnimTime"/>
 </set>
+-->
diff --git a/core/res/res/anim/wallpaper_open_enter.xml b/core/res/res/anim/wallpaper_open_enter.xml
index af22b47..cf27cf0 100644
--- a/core/res/res/anim/wallpaper_open_enter.xml
+++ b/core/res/res/anim/wallpaper_open_enter.xml
@@ -17,6 +17,22 @@
 */
 -->
 
+<!-- This version zooms the new non-wallpaper up off the wallpaper the
+     wallpaper.  The wallpaper here just stays fixed behind. -->
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+        android:interpolator="@anim/decelerate_interpolator"
+        android:zAdjustment="top">
+    <scale android:fromXScale=".5" android:toXScale="1.0"
+           android:fromYScale=".5" 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>
+
+<!-- This version is a variation on the inter-activity slide that
+    also scales the wallpaper. -->
+<!--
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:interpolator="@anim/decelerate_interpolator"
         android:zAdjustment="top">
@@ -27,3 +43,4 @@
 	<translate android:fromXDelta="-100%" android:toXDelta="0"
         android:duration="@android:integer/config_mediumAnimTime"/>
 </set>
+-->
diff --git a/core/res/res/anim/wallpaper_open_exit.xml b/core/res/res/anim/wallpaper_open_exit.xml
index 47cb6d6..b7a539c 100644
--- a/core/res/res/anim/wallpaper_open_exit.xml
+++ b/core/res/res/anim/wallpaper_open_exit.xml
@@ -17,8 +17,22 @@
 */
 -->
 
+<!-- This version zooms the new non-wallpaper down on top of the
+     wallpaper. -->
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+        android:interpolator="@anim/decelerate_interpolator">
+    <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" />
+</set>
+
+<!-- This version is a variation on the inter-activity slide that
+    also scales the wallpaper. -->
+<!--
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:interpolator="@anim/decelerate_interpolator">
 	<translate android:fromXDelta="0%" android:toXDelta="33%"
         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/fasttrack_badge.9.png b/core/res/res/drawable-hdpi/fasttrack_badge.9.png
new file mode 100644
index 0000000..1eeabf4
--- /dev/null
+++ b/core/res/res/drawable-hdpi/fasttrack_badge.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/fasttrack_badge_pressed.9.png b/core/res/res/drawable-hdpi/fasttrack_badge_pressed.9.png
new file mode 100644
index 0000000..0cfd09d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/fasttrack_badge_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/fasttrack_badge_small.9.png b/core/res/res/drawable-hdpi/fasttrack_badge_small.9.png
new file mode 100644
index 0000000..7140957
--- /dev/null
+++ b/core/res/res/drawable-hdpi/fasttrack_badge_small.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/fasttrack_badge_small_pressed.9.png b/core/res/res/drawable-hdpi/fasttrack_badge_small_pressed.9.png
new file mode 100644
index 0000000..ee030fbe
--- /dev/null
+++ b/core/res/res/drawable-hdpi/fasttrack_badge_small_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_aggregated.png b/core/res/res/drawable-hdpi/ic_aggregated.png
new file mode 100644
index 0000000..7ca15b1
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_aggregated.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lock_ringer_off.png b/core/res/res/drawable-hdpi/ic_lock_ringer_off.png
new file mode 100644
index 0000000..e7cb234
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lock_ringer_off.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_lock_ringer_on.png b/core/res/res/drawable-hdpi/ic_lock_ringer_on.png
new file mode 100644
index 0000000..ce0cfab9
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_lock_ringer_on.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/drawable-mdpi/fasttrack_badge.9.png b/core/res/res/drawable-mdpi/fasttrack_badge.9.png
new file mode 100644
index 0000000..d8dff34
--- /dev/null
+++ b/core/res/res/drawable-mdpi/fasttrack_badge.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/fasttrack_badge_pressed.9.png b/core/res/res/drawable-mdpi/fasttrack_badge_pressed.9.png
new file mode 100644
index 0000000..c8ca33a
--- /dev/null
+++ b/core/res/res/drawable-mdpi/fasttrack_badge_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/fasttrack_badge_small.9.png b/core/res/res/drawable-mdpi/fasttrack_badge_small.9.png
new file mode 100644
index 0000000..38f14f7
--- /dev/null
+++ b/core/res/res/drawable-mdpi/fasttrack_badge_small.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/fasttrack_badge_small_pressed.9.png b/core/res/res/drawable-mdpi/fasttrack_badge_small_pressed.9.png
new file mode 100644
index 0000000..b23e921
--- /dev/null
+++ b/core/res/res/drawable-mdpi/fasttrack_badge_small_pressed.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_aggregated.png b/core/res/res/drawable-mdpi/ic_aggregated.png
new file mode 100644
index 0000000..7c2e2b0
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_aggregated.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lock_ringer_off.png b/core/res/res/drawable-mdpi/ic_lock_ringer_off.png
new file mode 100644
index 0000000..98cfb11
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lock_ringer_off.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_lock_ringer_on.png b/core/res/res/drawable-mdpi/ic_lock_ringer_on.png
new file mode 100644
index 0000000..691b99e
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_lock_ringer_on.png
Binary files differ
diff --git a/core/res/res/drawable/fasttrack_badge_dark.xml b/core/res/res/drawable/fasttrack_badge.xml
similarity index 86%
rename from core/res/res/drawable/fasttrack_badge_dark.xml
rename to core/res/res/drawable/fasttrack_badge.xml
index c60d403..89c63a1 100644
--- a/core/res/res/drawable/fasttrack_badge_dark.xml
+++ b/core/res/res/drawable/fasttrack_badge.xml
@@ -19,10 +19,10 @@
         android:state_focused="false"
         android:state_selected="false"
         android:state_pressed="false"
-        android:drawable="@drawable/fasttrack_badge_dark_normal" />
+        android:drawable="@drawable/fasttrack_badge" />
 
     <item
         android:state_pressed="true"
-        android:drawable="@drawable/fasttrack_badge_dark_pressed" />
+        android:drawable="@drawable/fasttrack_badge_pressed" />
 
 </selector>
diff --git a/core/res/res/drawable/fasttrack_badge_dark_normal.9.png b/core/res/res/drawable/fasttrack_badge_dark_normal.9.png
deleted file mode 100644
index 52bb08c..0000000
--- a/core/res/res/drawable/fasttrack_badge_dark_normal.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/fasttrack_badge_dark_pressed.9.png b/core/res/res/drawable/fasttrack_badge_dark_pressed.9.png
deleted file mode 100644
index 84a6783..0000000
--- a/core/res/res/drawable/fasttrack_badge_dark_pressed.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/fasttrack_badge_light_normal.9.png b/core/res/res/drawable/fasttrack_badge_light_normal.9.png
deleted file mode 100644
index 595b179..0000000
--- a/core/res/res/drawable/fasttrack_badge_light_normal.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/fasttrack_badge_light_pressed.9.png b/core/res/res/drawable/fasttrack_badge_light_pressed.9.png
deleted file mode 100644
index 8e3f557..0000000
--- a/core/res/res/drawable/fasttrack_badge_light_pressed.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/fasttrack_badge_middle_large.xml b/core/res/res/drawable/fasttrack_badge_middle_large.xml
deleted file mode 100644
index dd591bd..0000000
--- a/core/res/res/drawable/fasttrack_badge_middle_large.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item
-        android:state_focused="false"
-        android:state_selected="false"
-        android:state_pressed="false"
-        android:drawable="@drawable/fasttrack_badge_middle_large_normal" />
-
-    <item
-        android:state_pressed="true"
-        android:drawable="@drawable/fasttrack_badge_middle_large_pressed" />
-
-</selector>
\ No newline at end of file
diff --git a/core/res/res/drawable/fasttrack_badge_middle_large_normal.9.png b/core/res/res/drawable/fasttrack_badge_middle_large_normal.9.png
deleted file mode 100644
index ca275cd..0000000
--- a/core/res/res/drawable/fasttrack_badge_middle_large_normal.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/fasttrack_badge_middle_large_pressed.9.png b/core/res/res/drawable/fasttrack_badge_middle_large_pressed.9.png
deleted file mode 100644
index b69ccbd..0000000
--- a/core/res/res/drawable/fasttrack_badge_middle_large_pressed.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/fasttrack_badge_light.xml b/core/res/res/drawable/fasttrack_badge_small.xml
similarity index 87%
rename from core/res/res/drawable/fasttrack_badge_light.xml
rename to core/res/res/drawable/fasttrack_badge_small.xml
index fd81258..269e936 100644
--- a/core/res/res/drawable/fasttrack_badge_light.xml
+++ b/core/res/res/drawable/fasttrack_badge_small.xml
@@ -19,10 +19,10 @@
         android:state_focused="false"
         android:state_selected="false"
         android:state_pressed="false"
-        android:drawable="@drawable/fasttrack_badge_light_normal" />
+        android:drawable="@drawable/fasttrack_badge_small" />
 
     <item
         android:state_pressed="true"
-        android:drawable="@drawable/fasttrack_badge_light_pressed" />
+        android:drawable="@drawable/fasttrack_badge_small_pressed" />
 
 </selector>
diff --git a/core/res/res/layout/contact_header.xml b/core/res/res/layout/contact_header.xml
index e800dfa..d19bb04 100644
--- a/core/res/res/layout/contact_header.xml
+++ b/core/res/res/layout/contact_header.xml
@@ -38,8 +38,24 @@
         android:layout_marginTop="5dip"
         android:orientation="vertical">
 
-        <!-- "Name" field is locale-specific. -->
-        <include layout="@layout/contact_header_name"/>
+        <LinearLayout
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal">
+
+            <ImageView
+                android:id="@+id/aggregate_badge"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:paddingRight="3dip"
+                android:paddingTop="3dip"
+                android:src="@drawable/ic_aggregated"
+            />
+
+            <!-- "Name" field is locale-specific. -->
+            <include layout="@layout/contact_header_name"/>
+
+        </LinearLayout>
 
         <TextView android:id="@+id/status"
             android:layout_width="fill_parent"
diff --git a/core/res/res/layout/keyguard_screen_rotary_unlock.xml b/core/res/res/layout/keyguard_screen_rotary_unlock.xml
index cf97d04..9f18124 100644
--- a/core/res/res/layout/keyguard_screen_rotary_unlock.xml
+++ b/core/res/res/layout/keyguard_screen_rotary_unlock.xml
@@ -83,6 +83,7 @@
         android:layout_marginTop="6dip"
         android:textAppearance="?android:attr/textAppearanceMedium"
         android:textColor="?android:attr/textColorSecondary"
+        android:drawablePadding="4dip"
         />
 
     <TextView
@@ -94,6 +95,7 @@
         android:layout_marginTop="6dip"
         android:textAppearance="?android:attr/textAppearanceMedium"
         android:textColor="?android:attr/textColorSecondary"
+        android:drawablePadding="4dip"
         />
 
     <TextView
@@ -108,15 +110,15 @@
         android:layout_marginTop="12dip"
         />
 
-    <!-- By having the rotary selector hang below "screen locked" text, we get a layout more
-         robust for different screen sizes.  On wvga, the widget should be flush with the bottom.-->
+    <!-- By having the rotary selector hang from the top, we get a layout more
+         robust for different screen sizes.  On hvga, the widget should be flush with the bottom.-->
     <com.android.internal.widget.RotarySelector
         android:id="@+id/rotary"
         android:layout_width="fill_parent"
         android:layout_height="wrap_content"
-        android:layout_below="@id/screenLocked"
         android:layout_centerHorizontal="true"
-        android:layout_marginTop="24dip"
+        android:layout_alignParentTop="true"
+        android:layout_marginTop="286dip"
         />
 
     <!-- emergency call button shown when sim is missing or PUKd -->
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/attrs.xml b/core/res/res/values/attrs.xml
index eae838a..a0d046f 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -102,9 +102,9 @@
         <!-- Text color, typeface, size, and style for "small" inverse text. Defaults to secondary inverse text color. -->
         <attr name="textAppearanceSmallInverse" format="reference" />
 
-        <!-- Text color, typeface, size, and style for system search result title. Defaults to primary inverse text color. @hide -->
+        <!-- Text color, typeface, size, and style for system search result title. Defaults to primary inverse text color. -->
         <attr name="textAppearanceSearchResultTitle" format="reference" />
-        <!-- Text color, typeface, size, and style for system search result subtitle. Defaults to primary inverse text color. @hide -->
+        <!-- Text color, typeface, size, and style for system search result subtitle. Defaults to primary inverse text color. -->
         <attr name="textAppearanceSearchResultSubtitle" format="reference" />
 
 
@@ -396,14 +396,20 @@
         <attr name="spinnerItemStyle" format="reference" />
         <!-- Default MapView style. -->
         <attr name="mapViewStyle" format="reference" />
-        <!-- Dark Fasttrack badge style. -->
+        <!-- Default Fasttrack badge style. -->
         <attr name="fasttrackBadgeWidgetStyle" format="reference" />
-        <!-- Dark Fasttrack badge style with small fasttrack window. -->
+        <!-- Default Fasttrack badge style with small fasttrack window. -->
         <attr name="fasttrackBadgeWidgetStyleWindowSmall" format="reference" />
-        <!-- Dark Fasttrack badge style with medium fasttrack window. -->
+        <!-- Default Fasttrack badge style with medium fasttrack window. -->
         <attr name="fasttrackBadgeWidgetStyleWindowMedium" format="reference" />
-        <!-- Dark Fasttrack badge style with large fasttrack window. -->
+        <!-- Default Fasttrack badge style with large fasttrack window. -->
         <attr name="fasttrackBadgeWidgetStyleWindowLarge" format="reference" />
+        <!-- Default Fasttrack badge style with small fasttrack window. -->
+        <attr name="fasttrackBadgeWidgetStyleSmallWindowSmall" format="reference" />
+        <!-- Default Fasttrack badge style with medium fasttrack window. -->
+        <attr name="fasttrackBadgeWidgetStyleSmallWindowMedium" format="reference" />
+        <!-- Default Fasttrack badge style with large fasttrack window. -->
+        <attr name="fasttrackBadgeWidgetStyleSmallWindowLarge" format="reference" />
 
         <!-- =================== -->
         <!-- Preference styles   -->
@@ -3486,13 +3492,29 @@
     <!-- Contacts meta-data attributes -->
     <!-- =============================== -->
 
+    <!-- TODO: remove this deprecated styleable -->
     <declare-styleable name="Icon">
         <attr name="icon" />
         <attr name="mimeType" />
     </declare-styleable>
 
+    <!-- TODO: remove this deprecated styleable -->
     <declare-styleable name="IconDefault">
         <attr name="icon" />
     </declare-styleable>
 
+    <!-- Maps a specific contact data MIME-type to styling information -->
+    <declare-styleable name="ContactsDataKind">
+        <!-- Mime-type handled by this mapping -->
+        <attr name="mimeType" />
+        <!-- Icon used to represent data of this kind -->
+        <attr name="icon" />
+        <!-- Column in data table that summarizes this data -->
+        <attr name="summaryColumn" format="string" />
+        <!-- Column in data table that contains details for this data -->
+        <attr name="detailColumn" format="string" />
+        <!-- Flag indicating that detail should be built from SocialProvider -->
+        <attr name="detailSocialSummary" format="boolean" />
+    </declare-styleable>
+
 </resources>
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index c967c4c..15841a8 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">#ff000000</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">#ff000000</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/config.xml b/core/res/res/values/config.xml
index b710acb6..7aeaec4 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -27,13 +27,13 @@
     <bool name="config_sf_limitedAlpha">false</bool>
     
     <!-- The duration (in milliseconds) of a short animation. -->
-    <integer name="config_shortAnimTime">100</integer>
+    <integer name="config_shortAnimTime">150</integer>
     
     <!-- The duration (in milliseconds) of a medium-length animation. -->
-    <integer name="config_mediumAnimTime">150</integer>
+    <integer name="config_mediumAnimTime">250</integer>
     
     <!-- The duration (in milliseconds) of a long animation. -->
-    <integer name="config_longAnimTime">300</integer>
+    <integer name="config_longAnimTime">400</integer>
 
     <!-- XXXXX NOTE THE FOLLOWING RESOURCES USE THE WRONG NAMING CONVENTION.
          Please don't copy them, copy anything else. -->
@@ -78,6 +78,20 @@
          A value of -1 means no change in orientation by default. -->
     <integer name="config_carDockRotation">-1</integer>
 
+    <!-- Control whether being in the desk dock (and powered) always
+         keeps the screen on.  By default it doesn't.  Set to true to make it. -->
+    <bool name="config_deskDockKeepsScreenOn">false</bool>
+
+    <!-- Control whether being in the car dock (and powered) always
+         keeps the screen on.  By default it does.  Set to false to not keep on. -->
+    <bool name="config_carDockKeepsScreenOn">true</bool>
+
+    <!-- Control whether being in the desk dock should enable accelerometer based screen orientation -->
+    <bool name="config_deskDockEnablesAccelerometer">false</bool>
+
+    <!-- Control whether being in the car dock should enable accelerometer based screen orientation -->
+    <bool name="config_carDockEnablesAccelerometer">false</bool>
+
     <!-- Indicate whether the lid state impacts the accessibility of
          the physical keyboard.  0 means it doesn't, 1 means it is accessible
          when the lid is open, 2 means it is accessible when the lid is
@@ -105,5 +119,7 @@
         <item>20</item>
         <item>30</item>
     </integer-array>
-    
+
+    <bool name="config_use_strict_phone_number_comparation">false</bool>
+
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 2bc2a0f..b08a58a 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1164,12 +1164,19 @@
   <public type="attr" name="restoreNeedsApplication" />
   <public type="attr" name="smallIcon" />
   <public type="attr" name="accountPreferences" />
+  <public type="attr" name="textAppearanceSearchResultSubtitle" />
+  <public type="attr" name="textAppearanceSearchResultTitle" />
+  <public type="attr" name="summaryColumn" />
+  <public type="attr" name="detailColumn" />
+  <public type="attr" name="detailSocialSummary" />
 
   <public type="style" name="Theme.Wallpaper" />
   <public type="style" name="Theme.Wallpaper.NoTitleBar" />
   <public type="style" name="Theme.Wallpaper.NoTitleBar.Fullscreen" />
   <public type="style" name="Theme.WallpaperSettings" />
   <public type="style" name="Theme.Light.WallpaperSettings" />
+  <public type="style" name="TextAppearance.SearchResult.Title" />
+  <public type="style" name="TextAppearance.SearchResult.Subtitle" />
   
   <!-- Semi-transparent background that can be used when placing a dark
        themed UI on top of some arbitrary background (such as the
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index bd79c75..e2f6981 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1200,6 +1200,106 @@
         <item>Jabber</item>
     </string-array>
 
+    <!-- Custom phone number type -->
+    <string name="phoneTypeCustom">Custom</string>
+    <!-- Home phone number type -->
+    <string name="phoneTypeHome">Home</string>
+    <!-- Mobile phone number type -->
+    <string name="phoneTypeMobile">Mobile</string>
+    <!-- Work phone number type -->
+    <string name="phoneTypeWork">Work</string>
+    <!-- Work fax phone number type -->
+    <string name="phoneTypeFaxWork">Work Fax</string>
+    <!-- Home fax phone number type -->
+    <string name="phoneTypeFaxHome">Home Fax</string>
+    <!-- Pager phone number type -->
+    <string name="phoneTypePager">Pager</string>
+    <!-- Other phone number type -->
+    <string name="phoneTypeOther">Other</string>
+    <!-- Callback phone number type -->
+    <string name="phoneTypeCallback">Callback</string>
+    <!-- Car phone number type -->
+    <string name="phoneTypeCar">Car</string>
+    <!-- Company main phone number type -->
+    <string name="phoneTypeCompanyMain">Company Main</string>
+    <!-- ISDN phone number type -->
+    <string name="phoneTypeIsdn">ISDN</string>
+    <!-- Main phone number type -->
+    <string name="phoneTypeMain">Main</string>
+    <!-- Other fax phone number type -->
+    <string name="phoneTypeOtherFax">Other Fax</string>
+    <!-- Radio phone number type -->
+    <string name="phoneTypeRadio">Radio</string>
+    <!-- Telex phone number type -->
+    <string name="phoneTypeTelex">Telex</string>
+    <!-- TTY TDD phone number type -->
+    <string name="phoneTypeTtyTdd">TTY TDD</string>
+    <!-- Work mobile phone number type -->
+    <string name="phoneTypeWorkMobile">Work Mobile</string>
+    <!-- Work pager phone number type -->
+    <string name="phoneTypeWorkPager">Work Pager</string>
+    <!-- Assistant phone number type -->
+    <string name="phoneTypeAssistant">Assistant</string>
+    <!-- MMS phone number type -->
+    <string name="phoneTypeMms">MMS</string>
+
+    <!-- Custom email type -->
+    <string name="emailTypeCustom">Custom</string>
+    <!-- Home email type -->
+    <string name="emailTypeHome">Home</string>
+    <!-- Work email type -->
+    <string name="emailTypeWork">Work</string>
+    <!-- Other email type -->
+    <string name="emailTypeOther">Other</string>
+    <!-- Mobile email type -->
+    <string name="emailTypeMobile">Mobile</string>
+
+    <!-- Custom postal address type -->
+    <string name="postalTypeCustom">Custom</string>
+    <!-- Home postal address type -->
+    <string name="postalTypeHome">Home</string>
+    <!-- Work postal address type -->
+    <string name="postalTypeWork">Work</string>
+    <!-- Other postal address type -->
+    <string name="postalTypeOther">Other</string>
+
+    <!-- Custom IM address type -->
+    <string name="imTypeCustom">Custom</string>
+    <!-- Home IM address type -->
+    <string name="imTypeHome">Home</string>
+    <!-- Work IM address type -->
+    <string name="imTypeWork">Work</string>
+    <!-- Other IM address type -->
+    <string name="imTypeOther">Other</string>
+
+    <!-- Custom IM address type -->
+    <string name="imProtocolCustom">Custom</string>
+    <!-- AIM IM protocol type -->
+    <string name="imProtocolAim">AIM</string>
+    <!-- MSN IM protocol type -->
+    <string name="imProtocolMsn">Windows Live</string>
+    <!-- Yahoo IM protocol type -->
+    <string name="imProtocolYahoo">Yahoo</string>
+    <!-- Skype IM protocol type -->
+    <string name="imProtocolSkype">Skype</string>
+    <!-- QQ IM protocol type -->
+    <string name="imProtocolQq">QQ</string>
+    <!-- Google Talk IM protocol type -->
+    <string name="imProtocolGoogleTalk">Google Talk</string>
+    <!-- ICQ IM protocol type -->
+    <string name="imProtocolIcq">ICQ</string>
+    <!-- Jabber IM protocol type -->
+    <string name="imProtocolJabber">Jabber</string>
+    <!-- NetMeeting IM protocol type -->
+    <string name="imProtocolNetMeeting">NetMeeting</string>
+
+    <!-- Work organization type -->
+    <string name="orgTypeWork">Work</string>
+    <!-- Other organization type -->
+    <string name="orgTypeOther">Other</string>
+    <!-- Custom organization type -->
+    <string name="orgTypeCustom">Custom</string>
+
     <!-- Instructions telling the user to enter their pin to unlock the keyguard.
          Displayed in one line in a large font.  -->
     <string name="keyguard_password_enter_pin_code">Enter PIN code</string>
@@ -1391,6 +1491,9 @@
     <!-- Title of the WebView save password dialog.  If the user enters a password in a form on a website, a dialog will come up asking if they want to save the password. -->
     <string name="save_password_label">Confirm</string>
 
+    <!-- Toast for double-tap -->
+    <string name="double_tap_toast">Tip: double-tap to zoom in and out.</string>
+
     <!-- Title of an application permission, listed so the user can choose whether
         they want to allow the application to do this. -->
     <string name="permlab_readHistoryBookmarks">read Browser\'s history and bookmarks</string>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 35db8ee..e78c213 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -58,6 +58,19 @@
         <item name="activityOpenExitAnimation">@anim/activity_open_exit</item>
         <item name="activityCloseEnterAnimation">@anim/activity_close_enter</item>
         <item name="activityCloseExitAnimation">@anim/activity_close_exit</item>
+        <item name="taskOpenEnterAnimation">@anim/activity_open_enter</item>
+        <item name="taskOpenExitAnimation">@anim/activity_open_exit</item>
+        <item name="taskCloseEnterAnimation">@anim/activity_close_enter</item>
+        <item name="taskCloseExitAnimation">@anim/activity_close_exit</item>
+        <item name="taskToFrontEnterAnimation">@anim/activity_open_enter</item>
+        <item name="taskToFrontExitAnimation">@anim/activity_open_exit</item>
+        <item name="taskToBackEnterAnimation">@anim/activity_close_enter</item>
+        <item name="taskToBackExitAnimation">@anim/activity_close_exit</item>
+        <!-- There is a good argument to be made that the user shouldn't
+             be aware of task transitions, so we are going to use the same
+             animation for them as we do for regular activity transitions. -->
+        <!-- These provide an alternative animation for task transitions. -->
+        <!--
         <item name="taskOpenEnterAnimation">@anim/task_open_enter</item>
         <item name="taskOpenExitAnimation">@anim/task_open_exit</item>
         <item name="taskCloseEnterAnimation">@anim/task_close_enter</item>
@@ -66,6 +79,7 @@
         <item name="taskToFrontExitAnimation">@anim/task_open_exit</item>
         <item name="taskToBackEnterAnimation">@anim/task_close_enter</item>
         <item name="taskToBackExitAnimation">@anim/task_close_exit</item>
+        -->
         <item name="wallpaperOpenEnterAnimation">@anim/wallpaper_open_enter</item>
         <item name="wallpaperOpenExitAnimation">@anim/wallpaper_open_exit</item>
         <item name="wallpaperCloseEnterAnimation">@anim/wallpaper_close_enter</item>
@@ -524,9 +538,17 @@
     </style>
 
     <style name="Widget.FasttrackBadgeWidget">
-        <item name="android:layout_width">48dip</item>
-        <item name="android:layout_height">52dip</item>
-        <item name="android:background">@android:drawable/fasttrack_badge_dark</item>
+        <item name="android:layout_width">50dip</item>
+        <item name="android:layout_height">56dip</item>
+        <item name="android:background">@android:drawable/fasttrack_badge</item>
+        <item name="android:clickable">true</item>
+        <item name="android:scaleType">fitCenter</item>
+    </style>
+    
+    <style name="Widget.FasttrackBadgeWidgetSmall">
+        <item name="android:layout_width">39dip</item>
+        <item name="android:layout_height">42dip</item>
+        <item name="android:background">@android:drawable/fasttrack_badge_small</item>
         <item name="android:clickable">true</item>
         <item name="android:scaleType">fitCenter</item>
     </style>
@@ -542,6 +564,18 @@
     <style name="Widget.FasttrackBadgeWidget.WindowLarge">
         <item name="android:fasttrackWindowSize">modeLarge</item>
     </style>
+    
+    <style name="Widget.FasttrackBadgeWidgetSmall.WindowSmall">
+        <item name="android:fasttrackWindowSize">modeSmall</item>
+    </style>
+
+    <style name="Widget.FasttrackBadgeWidgetSmall.WindowMedium">
+        <item name="android:fasttrackWindowSize">modeMedium</item>
+    </style>
+
+    <style name="Widget.FasttrackBadgeWidgetSmall.WindowLarge">
+        <item name="android:fasttrackWindowSize">modeLarge</item>
+    </style>
 
     <!-- Text Appearances -->
     <eat-comment />
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 04402fd..c0ca21b 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -59,11 +59,7 @@
         <item name="textAppearanceLargeInverse">@android:style/TextAppearance.Large.Inverse</item>
         <item name="textAppearanceMediumInverse">@android:style/TextAppearance.Medium.Inverse</item>
         <item name="textAppearanceSmallInverse">@android:style/TextAppearance.Small.Inverse</item>
-
-        <!-- @hide -->
         <item name="textAppearanceSearchResultTitle">@android:style/TextAppearance.SearchResult.Title</item>
-        
-        <!-- @hide -->
         <item name="textAppearanceSearchResultSubtitle">@android:style/TextAppearance.SearchResult.Subtitle</item>
         
         <item name="textAppearanceButton">@android:style/TextAppearance.Widget.Button</item>
@@ -179,6 +175,9 @@
         <item name="fasttrackBadgeWidgetStyleWindowSmall">@android:style/Widget.FasttrackBadgeWidget.WindowSmall</item>
         <item name="fasttrackBadgeWidgetStyleWindowMedium">@android:style/Widget.FasttrackBadgeWidget.WindowMedium</item>
         <item name="fasttrackBadgeWidgetStyleWindowLarge">@android:style/Widget.FasttrackBadgeWidget.WindowLarge</item>
+        <item name="fasttrackBadgeWidgetStyleSmallWindowSmall">@android:style/Widget.FasttrackBadgeWidgetSmall.WindowSmall</item>
+        <item name="fasttrackBadgeWidgetStyleSmallWindowMedium">@android:style/Widget.FasttrackBadgeWidgetSmall.WindowMedium</item>
+        <item name="fasttrackBadgeWidgetStyleSmallWindowLarge">@android:style/Widget.FasttrackBadgeWidgetSmall.WindowLarge</item>
         
         <!-- Preference styles -->
         <item name="preferenceScreenStyle">@android:style/Preference.PreferenceScreen</item>
@@ -358,7 +357,7 @@
     <style name="Theme.NoDisplay">
         <item name="android:windowBackground">@null</item>
         <item name="android:windowContentOverlay">@null</item>
-        <item name="android:windowIsTranslucent">false</item>
+        <item name="android:windowIsTranslucent">true</item>
         <item name="android:windowAnimationStyle">@null</item>
         <item name="android:windowDisablePreview">true</item>
         <item name="android:windowNoDisplay">true</item>
diff --git a/core/res/res/xml/power_profile.xml b/core/res/res/xml/power_profile.xml
index 859902e..710b71e 100644
--- a/core/res/res/xml/power_profile.xml
+++ b/core/res/res/xml/power_profile.xml
@@ -26,15 +26,24 @@
   <item name="wifi.on">0.1</item>
   <item name="wifi.active">0.1</item>
   <item name="wifi.scan">0.1</item>
-  <item name="cpu.idle">0.1</item>
-  <item name="cpu.normal">0.2</item>
-  <item name="cpu.full">1</item>
   <item name="dsp.audio">0.1</item>
   <item name="dsp.video">0.1</item>
   <item name="radio.active">1</item>
   <item name="gps.on">1</item>
+  <!-- Current consumed by the radio at different signal strengths, when paging -->
   <array name="radio.on"> <!-- Strength 0 to BINS-1 -->
       <value>1</value>
       <value>0.1</value>
   </array>
+  <!-- Different CPU speeds as reported in
+       /sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state -->
+  <array name="cpu.speeds">
+      <value>400000</value> <!-- 400 MHz CPU speed -->
+  </array>
+  <!-- Power consumption when CPU is idle -->
+  <item name="cpu.idle">0.1</item>
+  <!-- Power consumption at different speeds -->
+  <array name="cpu.active">
+      <value>0.2</value>
+  </array>
 </device>
diff --git a/graphics/java/android/graphics/PixelFormat.java b/graphics/java/android/graphics/PixelFormat.java
index 221c2f8..c76cee7 100644
--- a/graphics/java/android/graphics/PixelFormat.java
+++ b/graphics/java/android/graphics/PixelFormat.java
@@ -60,6 +60,13 @@
      */
     public static final int YCbCr_420_SP= 0x11;
 
+    /** YCbCr format used for images, which uses YUYV (YUY2) encoding format.
+     *  This is an alternative format for camera preview images. Whether this
+     *  format is supported by the camera hardware can be determined by
+     *  {@link android.hardware.Camera.Parameters#getSupportedPreviewFormats()}.
+     */
+    public static final int YCbCr_422_I = 0x14;
+
     /**
      * Encoded formats.  These are not necessarily supported by the hardware.
      */
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index 30c81ab..957f2dd 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -48,50 +48,49 @@
     }
 
     public void data(int[] d) {
-        int size;
-        if(mType != null && mType.mElement != null) {
-            size = mType.mElement.mSize;
-            for(int ct=0; ct < mType.mValues.length; ct++) {
-                if(mType.mValues[ct] != 0) {
-                    size *= mType.mValues[ct];
-                }
-            }
-            if((d.length * 4) < size) {
-                throw new IllegalArgumentException("Array too small for allocation type.");
-            }
-            Log.e("rs", "Alloc data size=" + size);
-            mRS.nAllocationData(mID, d, size);
-            return;
-        }
-        mRS.nAllocationData(mID, d, d.length * 4);
+        subData1D(0, mType.getElementCount(), d);
+    }
+    public void data(short[] d) {
+        subData1D(0, mType.getElementCount(), d);
+    }
+    public void data(byte[] d) {
+        subData1D(0, mType.getElementCount(), d);
+    }
+    public void data(float[] d) {
+        subData1D(0, mType.getElementCount(), d);
     }
 
-    public void data(float[] d) {
-        int size;
-        if(mType != null && mType.mElement != null) {
-            size = mType.mElement.mSize;
-            for(int ct=0; ct < mType.mValues.length; ct++) {
-                if(mType.mValues[ct] != 0) {
-                    size *= mType.mValues[ct];
-                }
-            }
-            if((d.length * 4) < size) {
-                throw new IllegalArgumentException("Array too small for allocation type.");
-            }
-            Log.e("rs", "Alloc data size=" + size);
-            mRS.nAllocationData(mID, d, size);
-            return;
+    private void data1DChecks(int off, int count, int len, int dataSize) {
+        if((off < 0) || (count < 1) || ((off + count) > mType.getElementCount())) {
+            throw new IllegalArgumentException("Offset or Count out of bounds.");
         }
-        mRS.nAllocationData(mID, d, d.length * 4);
+        if((len) < dataSize) {
+            throw new IllegalArgumentException("Array too small for allocation type.");
+        }
     }
 
     public void subData1D(int off, int count, int[] d) {
-        mRS.nAllocationSubData1D(mID, off, count, d, count * 4);
+        int dataSize = mType.mElement.getSizeBytes() * count;
+        data1DChecks(off, count, d.length * 4, dataSize);
+        mRS.nAllocationSubData1D(mID, off, count, d, dataSize);
+    }
+    public void subData1D(int off, int count, short[] d) {
+        int dataSize = mType.mElement.getSizeBytes() * count;
+        data1DChecks(off, count, d.length * 2, dataSize);
+        mRS.nAllocationSubData1D(mID, off, count, d, dataSize);
+    }
+    public void subData1D(int off, int count, byte[] d) {
+        int dataSize = mType.mElement.getSizeBytes() * count;
+        data1DChecks(off, count, d.length, dataSize);
+        mRS.nAllocationSubData1D(mID, off, count, d, dataSize);
+    }
+    public void subData1D(int off, int count, float[] d) {
+        int dataSize = mType.mElement.getSizeBytes() * count;
+        data1DChecks(off, count, d.length * 4, dataSize);
+        mRS.nAllocationSubData1D(mID, off, count, d, dataSize);
     }
 
-    public void subData1D(int off, int count, float[] d) {
-        mRS.nAllocationSubData1D(mID, off, count, d, d.length * 4);
-    }
+
 
     public void subData2D(int xoff, int yoff, int w, int h, int[] d) {
         mRS.nAllocationSubData2D(mID, xoff, yoff, w, h, d, d.length * 4);
@@ -213,11 +212,15 @@
     static public Allocation createSized(RenderScript rs, Element e, int count)
         throws IllegalArgumentException {
 
-        int id = rs.nAllocationCreateSized(e.mID, count);
+        Type.Builder b = new Type.Builder(rs, e);
+        b.add(Dimension.X, count);
+        Type t = b.create();
+
+        int id = rs.nAllocationCreateTyped(t.mID);
         if(id == 0) {
             throw new IllegalStateException("Bad element.");
         }
-        return new Allocation(id, rs, null);
+        return new Allocation(id, rs, t);
     }
 
     static public Allocation createFromBitmap(RenderScript rs, Bitmap b, Element dstFmt, boolean genMips)
diff --git a/graphics/java/android/renderscript/Element.java b/graphics/java/android/renderscript/Element.java
index 04c36fd..0a586c4 100644
--- a/graphics/java/android/renderscript/Element.java
+++ b/graphics/java/android/renderscript/Element.java
@@ -26,18 +26,40 @@
     int mSize;
     Entry[] mEntries;
 
+    int getSizeBytes() {
+        return mSize;
+    }
+    int getComponentCount() {
+        return mEntries.length;
+    }
+    Element.DataType getComponentDataType(int num) {
+        return mEntries[num].mType;
+    }
+    Element.DataKind getComponentDataKind(int num) {
+        return mEntries[num].mKind;
+    }
+    boolean getComponentIsNormalized(int num) {
+        return mEntries[num].mIsNormalized;
+    }
+    int getComponentBits(int num) {
+        return mEntries[num].mBits;
+    }
+    String getComponentName(int num) {
+        return mEntries[num].mName;
+    }
+
     static class Entry {
-        Element mElement;
+        //Element mElement;
         Element.DataType mType;
         Element.DataKind mKind;
         boolean mIsNormalized;
         int mBits;
         String mName;
 
-        Entry(Element e, int bits) {
-            mElement = e;
-            int mBits = bits;
-        }
+        //Entry(Element e, int bits) {
+            //mElement = e;
+            //int mBits = bits;
+        //}
 
         Entry(DataType dt, DataKind dk, boolean isNorm, int bits, String name) {
             mType = dt;
@@ -266,14 +288,11 @@
         int bits = 0;
         for (int ct=0; ct < e.mEntries.length; ct++) {
             Entry en = e.mEntries[ct];
-            if(en.mElement !=  null) {
+            //if(en.mElement !=  null) {
                 //rs.nElementAdd(en.mElement.mID);
-            } else {
-                int norm = 0;
-                if (en.mIsNormalized) {
-                    norm = 1;
-                }
-                rs.nElementAdd(en.mKind.mID, en.mType.mID, norm, en.mBits, en.mName);
+            //} else
+            {
+                rs.nElementAdd(en.mKind.mID, en.mType.mID, en.mIsNormalized, en.mBits, en.mName);
                 bits += en.mBits;
             }
         }
@@ -308,11 +327,11 @@
             mEntryCount++;
         }
 
-        public Builder add(Element e) throws IllegalArgumentException {
-            Entry en = new Entry(e, e.mSize * 8);
-            addEntry(en);
-            return this;
-        }
+        //public Builder add(Element e) throws IllegalArgumentException {
+            //Entry en = new Entry(e, e.mSize * 8);
+            //addEntry(en);
+            //return this;
+        //}
 
         public Builder add(Element.DataType dt, Element.DataKind dk, boolean isNormalized, int bits, String name) {
             Entry en = new Entry(dt, dk, isNormalized, bits, name);
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index d35c5e3..5831d13 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -80,7 +80,7 @@
     native int  nFileOpen(byte[] name);
 
     native void nElementBegin();
-    native void nElementAdd(int kind, int type, int norm, int bits, String s);
+    native void nElementAdd(int kind, int type, boolean norm, int bits, String s);
     native int  nElementCreate();
 
     native void nTypeBegin(int elementID);
@@ -90,17 +90,19 @@
     native void nTypeSetupFields(Type t, int[] types, int[] bits, Field[] IDs);
 
     native int  nAllocationCreateTyped(int type);
-    native int  nAllocationCreateSized(int elem, int count);
+    //native int  nAllocationCreateSized(int elem, int count);
     native int  nAllocationCreateFromBitmap(int dstFmt, boolean genMips, Bitmap bmp);
     native int  nAllocationCreateFromBitmapBoxed(int dstFmt, boolean genMips, Bitmap bmp);
     native int  nAllocationCreateFromAssetStream(int dstFmt, boolean genMips, int assetStream);
 
     native void nAllocationUploadToTexture(int alloc, int baseMioLevel);
     native void nAllocationUploadToBufferObject(int alloc);
-    native void nAllocationData(int id, int[] d, int sizeBytes);
-    native void nAllocationData(int id, float[] d, int sizeBytes);
+
     native void nAllocationSubData1D(int id, int off, int count, int[] d, int sizeBytes);
+    native void nAllocationSubData1D(int id, int off, int count, short[] d, int sizeBytes);
+    native void nAllocationSubData1D(int id, int off, int count, byte[] d, int sizeBytes);
     native void nAllocationSubData1D(int id, int off, int count, float[] d, int sizeBytes);
+
     native void nAllocationSubData2D(int id, int xoff, int yoff, int w, int h, int[] d, int sizeBytes);
     native void nAllocationSubData2D(int id, int xoff, int yoff, int w, int h, float[] d, int sizeBytes);
     native void nAllocationRead(int id, int[] d);
diff --git a/graphics/java/android/renderscript/SimpleMesh.java b/graphics/java/android/renderscript/SimpleMesh.java
index 5d87654..dc74c61 100644
--- a/graphics/java/android/renderscript/SimpleMesh.java
+++ b/graphics/java/android/renderscript/SimpleMesh.java
@@ -162,7 +162,6 @@
         }
 
         public SimpleMesh create() {
-            Log.e("rs", "SimpleMesh create");
             SimpleMesh sm = internalCreate(mRS, this);
             sm.mVertexTypes = new Type[mVertexTypeCount];
             for(int ct=0; ct < mVertexTypeCount; ct++) {
@@ -177,7 +176,7 @@
     public static class TriangleMeshBuilder {
         float mVtxData[];
         int mVtxCount;
-        int mIndexData[];
+        short mIndexData[];
         int mIndexCount;
         RenderScript mRS;
         Element mElement;
@@ -191,7 +190,7 @@
             mVtxCount = 0;
             mIndexCount = 0;
             mVtxData = new float[128];
-            mIndexData = new int[128];
+            mIndexData = new short[128];
             mVtxSize = vtxSize;
             mNorm = norm;
             mTex = tex;
@@ -268,13 +267,13 @@
 
         public void addTriangle(int idx1, int idx2, int idx3) {
             if((mIndexCount + 3) >= mIndexData.length) {
-                int t[] = new int[mIndexData.length * 2];
+                short t[] = new short[mIndexData.length * 2];
                 System.arraycopy(mIndexData, 0, t, 0, mIndexData.length);
                 mIndexData = t;
             }
-            mIndexData[mIndexCount++] = idx1;
-            mIndexData[mIndexCount++] = idx2;
-            mIndexData[mIndexCount++] = idx3;
+            mIndexData[mIndexCount++] = (short)idx1;
+            mIndexData[mIndexCount++] = (short)idx2;
+            mIndexData[mIndexCount++] = (short)idx3;
         }
 
         public SimpleMesh create() {
@@ -309,10 +308,6 @@
             vertexAlloc.data(mVtxData);
             vertexAlloc.uploadToBufferObject();
 
-            // This is safe because length is a pow2
-            for(int ct=0; ct < (mIndexCount+1); ct += 2) {
-                mIndexData[ct >> 1] = mIndexData[ct] | (mIndexData[ct+1] << 16);
-            }
             indexAlloc.data(mIndexData);
             indexAlloc.uploadToBufferObject();
 
diff --git a/graphics/java/android/renderscript/Type.java b/graphics/java/android/renderscript/Type.java
index b6b7adf..df60990 100644
--- a/graphics/java/android/renderscript/Type.java
+++ b/graphics/java/android/renderscript/Type.java
@@ -23,13 +23,74 @@
  *
  **/
 public class Type extends BaseObj {
-    Dimension[] mDimensions;
-    int[] mValues;
+    int mDimX;
+    int mDimY;
+    int mDimZ;
+    boolean mDimLOD;
+    boolean mDimFaces;
+    int mElementCount;
     Element mElement;
+
     private int mNativeCache;
     Class mJavaClass;
 
 
+    public int getX() {
+        return mDimX;
+    }
+    public int getY() {
+        return mDimY;
+    }
+    public int getZ() {
+        return mDimZ;
+    }
+    public boolean getLOD() {
+        return mDimLOD;
+    }
+    public boolean getFaces() {
+        return mDimFaces;
+    }
+    public int getElementCount() {
+        return mElementCount;
+    }
+
+    void calcElementCount() {
+        boolean hasLod = getLOD();
+        int x = getX();
+        int y = getY();
+        int z = getZ();
+        int faces = 1;
+        if(getFaces()) {
+            faces = 6;
+        }
+        if(x == 0) {
+            x = 1;
+        }
+        if(y == 0) {
+            y = 1;
+        }
+        if(z == 0) {
+            z = 1;
+        }
+
+        int count = x * y * z * faces;
+        if(hasLod && (x > 1) && (y > 1) && (z > 1)) {
+            if(x > 1) {
+                x >>= 1;
+            }
+            if(y > 1) {
+                y >>= 1;
+            }
+            if(z > 1) {
+                z >>= 1;
+            }
+
+            count += x * y * z * faces;
+        }
+        mElementCount = count;
+    }
+
+
     Type(int id, RenderScript rs) {
         super(rs);
         mID = id;
@@ -131,12 +192,25 @@
         public Type create() {
             Type t = internalCreate(mRS, this);
             t.mElement = mElement;
-            t.mDimensions = new Dimension[mEntryCount];
-            t.mValues = new int[mEntryCount];
+
             for(int ct=0; ct < mEntryCount; ct++) {
-                t.mDimensions[ct] = mEntries[ct].mDim;
-                t.mValues[ct] = mEntries[ct].mValue;
+                if(mEntries[ct].mDim == Dimension.X) {
+                    t.mDimX = mEntries[ct].mValue;
+                }
+                if(mEntries[ct].mDim == Dimension.Y) {
+                    t.mDimY = mEntries[ct].mValue;
+                }
+                if(mEntries[ct].mDim == Dimension.Z) {
+                    t.mDimZ = mEntries[ct].mValue;
+                }
+                if(mEntries[ct].mDim == Dimension.LOD) {
+                    t.mDimLOD = mEntries[ct].mValue != 0;
+                }
+                if(mEntries[ct].mDim == Dimension.FACE) {
+                    t.mDimFaces = mEntries[ct].mValue != 0;
+                }
             }
+            t.calcElementCount();
             return t;
         }
     }
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index eae6f24..56a4223 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -181,7 +181,7 @@
 
 
 static void
-nElementAdd(JNIEnv *_env, jobject _this, jint kind, jint type, jint norm, jint bits, jstring name)
+nElementAdd(JNIEnv *_env, jobject _this, jint kind, jint type, jboolean norm, jint bits, jstring name)
 {
     RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
     const char* n = NULL;
@@ -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;
 }
@@ -363,14 +359,6 @@
     return (jint) rsAllocationCreateTyped(con, (RsElement)e);
 }
 
-static jint
-nAllocationCreateSized(JNIEnv *_env, jobject _this, jint e, jint count)
-{
-    RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
-    LOG_API("nAllocationCreateSized, con(%p), e(%p), count(%i)", con, (RsElement)e, count);
-    return (jint) rsAllocationCreateSized(con, (RsElement)e, count);
-}
-
 static void
 nAllocationUploadToTexture(JNIEnv *_env, jobject _this, jint a, jint mip)
 {
@@ -480,44 +468,44 @@
 
 
 static void
-nAllocationData_i(JNIEnv *_env, jobject _this, jint alloc, jintArray data, int sizeBytes)
-{
-    RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
-    jint len = _env->GetArrayLength(data);
-    LOG_API("nAllocationData_i, con(%p), alloc(%p), len(%i)", con, (RsAllocation)alloc, len);
-    jint *ptr = _env->GetIntArrayElements(data, NULL);
-    rsAllocationData(con, (RsAllocation)alloc, ptr, sizeBytes);
-    _env->ReleaseIntArrayElements(data, ptr, JNI_ABORT);
-}
-
-static void
-nAllocationData_f(JNIEnv *_env, jobject _this, jint alloc, jfloatArray data, int sizeBytes)
-{
-    RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
-    jint len = _env->GetArrayLength(data);
-    LOG_API("nAllocationData_i, con(%p), alloc(%p), len(%i)", con, (RsAllocation)alloc, len);
-    jfloat *ptr = _env->GetFloatArrayElements(data, NULL);
-    rsAllocationData(con, (RsAllocation)alloc, ptr, sizeBytes);
-    _env->ReleaseFloatArrayElements(data, ptr, JNI_ABORT);
-}
-
-static void
 nAllocationSubData1D_i(JNIEnv *_env, jobject _this, jint alloc, jint offset, jint count, jintArray data, int sizeBytes)
 {
     RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
     jint len = _env->GetArrayLength(data);
-    LOG_API("nAllocation1DSubData_i, con(%p), adapter(%p), offset(%i), count(%i), len(%i)", con, (RsAllocation)alloc, offset, count, len);
+    LOG_API("nAllocation1DSubData_i, con(%p), adapter(%p), offset(%i), count(%i), len(%i), sizeBytes(%i)", con, (RsAllocation)alloc, offset, count, len, sizeBytes);
     jint *ptr = _env->GetIntArrayElements(data, NULL);
     rsAllocation1DSubData(con, (RsAllocation)alloc, offset, count, ptr, sizeBytes);
     _env->ReleaseIntArrayElements(data, ptr, JNI_ABORT);
 }
 
 static void
+nAllocationSubData1D_s(JNIEnv *_env, jobject _this, jint alloc, jint offset, jint count, jshortArray data, int sizeBytes)
+{
+    RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+    jint len = _env->GetArrayLength(data);
+    LOG_API("nAllocation1DSubData_s, con(%p), adapter(%p), offset(%i), count(%i), len(%i), sizeBytes(%i)", con, (RsAllocation)alloc, offset, count, len, sizeBytes);
+    jshort *ptr = _env->GetShortArrayElements(data, NULL);
+    rsAllocation1DSubData(con, (RsAllocation)alloc, offset, count, ptr, sizeBytes);
+    _env->ReleaseShortArrayElements(data, ptr, JNI_ABORT);
+}
+
+static void
+nAllocationSubData1D_b(JNIEnv *_env, jobject _this, jint alloc, jint offset, jint count, jbyteArray data, int sizeBytes)
+{
+    RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+    jint len = _env->GetArrayLength(data);
+    LOG_API("nAllocation1DSubData_b, con(%p), adapter(%p), offset(%i), count(%i), len(%i), sizeBytes(%i)", con, (RsAllocation)alloc, offset, count, len, sizeBytes);
+    jbyte *ptr = _env->GetByteArrayElements(data, NULL);
+    rsAllocation1DSubData(con, (RsAllocation)alloc, offset, count, ptr, sizeBytes);
+    _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
+}
+
+static void
 nAllocationSubData1D_f(JNIEnv *_env, jobject _this, jint alloc, jint offset, jint count, jfloatArray data, int sizeBytes)
 {
     RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
     jint len = _env->GetArrayLength(data);
-    LOG_API("nAllocation1DSubData_f, con(%p), adapter(%p), offset(%i), count(%i), len(%i)", con, (RsAllocation)alloc, offset, count, len);
+    LOG_API("nAllocation1DSubData_f, con(%p), adapter(%p), offset(%i), count(%i), len(%i), sizeBytes(%i)", con, (RsAllocation)alloc, offset, count, len, sizeBytes);
     jfloat *ptr = _env->GetFloatArrayElements(data, NULL);
     rsAllocation1DSubData(con, (RsAllocation)alloc, offset, count, ptr, sizeBytes);
     _env->ReleaseFloatArrayElements(data, ptr, JNI_ABORT);
@@ -601,11 +589,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);
@@ -1330,7 +1315,7 @@
 {"nFileOpen",                      "([B)I",                                (void*)nFileOpen },
 
 {"nElementBegin",                  "()V",                                  (void*)nElementBegin },
-{"nElementAdd",                    "(IIIILjava/lang/String;)V",            (void*)nElementAdd },
+{"nElementAdd",                    "(IIZILjava/lang/String;)V",            (void*)nElementAdd },
 {"nElementCreate",                 "()I",                                  (void*)nElementCreate },
 
 {"nTypeBegin",                     "(I)V",                                 (void*)nTypeBegin },
@@ -1340,15 +1325,14 @@
 {"nTypeSetupFields",               "(Landroid/renderscript/Type;[I[I[Ljava/lang/reflect/Field;)V", (void*)nTypeSetupFields },
 
 {"nAllocationCreateTyped",         "(I)I",                                 (void*)nAllocationCreateTyped },
-{"nAllocationCreateSized",         "(II)I",                                (void*)nAllocationCreateSized },
 {"nAllocationCreateFromBitmap",    "(IZLandroid/graphics/Bitmap;)I",       (void*)nAllocationCreateFromBitmap },
 {"nAllocationCreateFromBitmapBoxed","(IZLandroid/graphics/Bitmap;)I",      (void*)nAllocationCreateFromBitmapBoxed },
 {"nAllocationCreateFromAssetStream","(IZI)I",                              (void*)nAllocationCreateFromAssetStream },
 {"nAllocationUploadToTexture",     "(II)V",                                (void*)nAllocationUploadToTexture },
 {"nAllocationUploadToBufferObject","(I)V",                                 (void*)nAllocationUploadToBufferObject },
-{"nAllocationData",                "(I[II)V",                              (void*)nAllocationData_i },
-{"nAllocationData",                "(I[FI)V",                              (void*)nAllocationData_f },
 {"nAllocationSubData1D",           "(III[II)V",                            (void*)nAllocationSubData1D_i },
+{"nAllocationSubData1D",           "(III[SI)V",                            (void*)nAllocationSubData1D_s },
+{"nAllocationSubData1D",           "(III[BI)V",                            (void*)nAllocationSubData1D_b },
 {"nAllocationSubData1D",           "(III[FI)V",                            (void*)nAllocationSubData1D_f },
 {"nAllocationSubData2D",           "(IIIII[II)V",                          (void*)nAllocationSubData2D_i },
 {"nAllocationSubData2D",           "(IIIII[FI)V",                          (void*)nAllocationSubData2D_f },
diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java
index 28c2992..43042c0b 100644
--- a/keystore/java/android/security/Credentials.java
+++ b/keystore/java/android/security/Credentials.java
@@ -28,9 +28,12 @@
  */
 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;
+
+    public static final String UNLOCK_ACTION = "android.credentials.UNLOCK";
+
+    public static final String INSTALL_ACTION = "android.credentials.INSTALL";
+
+    public static final String SYSTEM_INSTALL_ACTION = "android.credentials.SYSTEM_INSTALL";
 
     /** Key prefix for CA certificates. */
     public static final String CA_CERTIFICATE = "CACERT_";
@@ -59,6 +62,8 @@
     /** Data type for PKCS12. */
     public static final String PKCS12 = "PKCS12";
 
+    private static Credentials singleton;
+
     public static Credentials getInstance() {
         if (singleton == null) {
             singleton = new Credentials();
@@ -95,4 +100,12 @@
             Log.w(LOGTAG, e.toString());
         }
     }
+
+    public void installFromSdCard(Context context) {
+        try {
+            context.startActivity(new Intent(INSTALL_ACTION));
+        } catch (ActivityNotFoundException e) {
+            Log.w(LOGTAG, e.toString());
+        }
+    }
 }
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
new file mode 100644
index 0000000..a47534b
--- /dev/null
+++ b/keystore/java/android/security/KeyStore.java
@@ -0,0 +1,208 @@
+/*
+ * 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.net.LocalSocketAddress;
+import android.net.LocalSocket;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+
+/**
+ * {@hide}
+ */
+public class KeyStore {
+    public static int NO_ERROR = 1;
+    public static int LOCKED = 2;
+    public static int UNINITIALIZED = 3;
+    public static int SYSTEM_ERROR = 4;
+    public static int PROTOCOL_ERROR = 5;
+    public static int PERMISSION_DENIED = 6;
+    public static int KEY_NOT_FOUND = 7;
+    public static int VALUE_CORRUPTED = 8;
+    public static int UNDEFINED_ACTION = 9;
+    public static int WRONG_PASSWORD = 10;
+
+    private static final LocalSocketAddress sAddress = new LocalSocketAddress(
+            "keystore", LocalSocketAddress.Namespace.RESERVED);
+
+    private int mError = NO_ERROR;
+
+    private KeyStore() {}
+
+    public static KeyStore getInstance() {
+        return new KeyStore();
+    }
+
+    public int test() {
+        execute('t');
+        return mError;
+    }
+
+    public byte[] get(byte[] key) {
+        byte[][] values = execute('g', key);
+        return (values == null) ? null : values[0];
+    }
+
+    public String get(String key) {
+        byte[] value = get(key.getBytes());
+        return (value == null) ? null : new String(value);
+    }
+
+    public boolean put(byte[] key, byte[] value) {
+        execute('i', key, value);
+        return mError == NO_ERROR;
+    }
+
+    public boolean put(String key, String value) {
+        return put(key.getBytes(), value.getBytes());
+    }
+
+    public boolean delete(byte[] key) {
+        execute('d', key);
+        return mError == NO_ERROR;
+    }
+
+    public boolean delete(String key) {
+        return delete(key.getBytes());
+    }
+
+    public boolean contains(byte[] key) {
+        execute('e', key);
+        return mError == NO_ERROR;
+    }
+
+    public boolean contains(String key) {
+        return contains(key.getBytes());
+    }
+
+    public byte[][] saw(byte[] prefix) {
+        return execute('s', prefix);
+    }
+
+    public String[] saw(String prefix) {
+        byte[][] values = saw(prefix.getBytes());
+        if (values == null) {
+            return null;
+        }
+        String[] strings = new String[values.length];
+        for (int i = 0; i < values.length; ++i) {
+            strings[i] = new String(values[i]);
+        }
+        return strings;
+    }
+
+    public boolean reset() {
+        execute('r');
+        return mError == NO_ERROR;
+    }
+
+    public boolean password(byte[] oldPassword, byte[] newPassword) {
+        execute('p', oldPassword, newPassword);
+        return mError == NO_ERROR;
+    }
+
+    public boolean password(String oldPassword, String newPassword) {
+        return password(oldPassword.getBytes(), newPassword.getBytes());
+    }
+
+    public boolean password(byte[] password) {
+        return password(password, password);
+    }
+
+    public boolean password(String password) {
+        return password(password.getBytes());
+    }
+
+    public boolean lock() {
+        execute('l');
+        return mError == NO_ERROR;
+    }
+
+    public boolean unlock(byte[] password) {
+        execute('u', password);
+        return mError == NO_ERROR;
+    }
+
+    public boolean unlock(String password) {
+        return unlock(password.getBytes());
+    }
+
+    public int getLastError() {
+        return mError;
+    }
+
+    private byte[][] execute(int code, byte[]... parameters) {
+        mError = PROTOCOL_ERROR;
+
+        for (byte[] parameter : parameters) {
+            if (parameter == null || parameter.length > 65535) {
+                return null;
+            }
+        }
+
+        LocalSocket socket = new LocalSocket();
+        try {
+            socket.connect(sAddress);
+
+            OutputStream out = socket.getOutputStream();
+            out.write(code);
+            for (byte[] parameter : parameters) {
+                out.write(parameter.length >> 8);
+                out.write(parameter.length);
+                out.write(parameter);
+            }
+            out.flush();
+            socket.shutdownOutput();
+
+            InputStream in = socket.getInputStream();
+            code = in.read();
+            if (code == -1) {
+                return null;
+            }
+
+            ArrayList<byte[]> results = new ArrayList<byte[]>();
+            while (true) {
+                int i, j;
+                if ((i = in.read()) == -1) {
+                    break;
+                }
+                if ((j = in.read()) == -1) {
+                    return null;
+                }
+                byte[] result = new byte[i << 8 | j];
+                for (i = 0; i < result.length; i += j) {
+                    if ((j = in.read(result, i, result.length - i)) == -1) {
+                        return null;
+                    }
+                }
+                results.add(result);
+            }
+            mError = code;
+            return results.toArray(new byte[results.size()][]);
+        } catch (IOException e) {
+            // ignore
+        } finally {
+            try {
+                socket.close();
+            } catch (IOException e) {}
+        }
+        return null;
+    }
+}
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index e534447..6500791 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -1227,44 +1227,46 @@
             enabledTracks = prepareTracks_l(activeTracks, &tracksToRemove);
        }
 
-
-        // output audio to hardware
-        if (mSuspended) {
-            usleep(kMaxBufferRecoveryInUsecs);
+        if (LIKELY(enabledTracks)) {
+            // mix buffers...
+            mAudioMixer->process(curBuf);
+            sleepTime = 0;
+            standbyTime = systemTime() + kStandbyTimeInNsecs;
         } else {
-            if (LIKELY(enabledTracks)) {
-                // mix buffers...
-                mAudioMixer->process(curBuf);
+            sleepTime += kBufferRecoveryInUsecs;
+            if (sleepTime > kMaxBufferRecoveryInUsecs) {
+                sleepTime = kMaxBufferRecoveryInUsecs;
+            }
+            // There was nothing to mix this round, which means all
+            // active tracks were late. Sleep a little bit to give
+            // them another chance. If we're too late, write 0s to audio
+            // hardware to avoid underrun.
+            if (mBytesWritten != 0 && sleepTime >= kMaxBufferRecoveryInUsecs) {
+                memset (curBuf, 0, mixBufferSize);
                 sleepTime = 0;
-                standbyTime = systemTime() + kStandbyTimeInNsecs;
-            } else {
-                sleepTime += kBufferRecoveryInUsecs;
-                // There was nothing to mix this round, which means all
-                // active tracks were late. Sleep a little bit to give
-                // them another chance. If we're too late, write 0s to audio
-                // hardware to avoid underrun.
-                if (mBytesWritten == 0 || sleepTime < kMaxBufferRecoveryInUsecs) {
-                    usleep(kBufferRecoveryInUsecs);
-                } else {
-                    memset (curBuf, 0, mixBufferSize);
-                    sleepTime = 0;
-                }
             }
-            // sleepTime == 0 means PCM data were written to mMixBuffer[]
-            if (sleepTime == 0) {
-                mLastWriteTime = systemTime();
-                mInWrite = true;
-                int bytesWritten = (int)mOutput->write(curBuf, mixBufferSize);
-                if (bytesWritten > 0) mBytesWritten += bytesWritten;
-                mNumWrites++;
-                mInWrite = false;
-                mStandby = false;
-                nsecs_t delta = systemTime() - mLastWriteTime;
-                if (delta > maxPeriod) {
-                    LOGW("write blocked for %llu msecs", ns2ms(delta));
-                    mNumDelayedWrites++;
-                }
+        }
+
+        if (mSuspended) {
+            sleepTime = kMaxBufferRecoveryInUsecs;
+        }
+        // sleepTime == 0 means we must write to audio hardware
+        if (sleepTime == 0) {
+            mLastWriteTime = systemTime();
+            mInWrite = true;
+            LOGV("mOutput->write() thread %p frames %d", this, mFrameCount);
+            int bytesWritten = (int)mOutput->write(curBuf, mixBufferSize);
+            if (bytesWritten > 0) mBytesWritten += bytesWritten;
+            mNumWrites++;
+            mInWrite = false;
+            mStandby = false;
+            nsecs_t delta = systemTime() - mLastWriteTime;
+            if (delta > maxPeriod) {
+                LOGW("write blocked for %llu msecs, thread %p", ns2ms(delta), this);
+                mNumDelayedWrites++;
             }
+        } else {
+            usleep(sleepTime);
         }
 
         // finally let go of all our tracks, without the lock held
@@ -1718,50 +1720,55 @@
             }
        }
 
-        // output audio to hardware
-        if (mSuspended) {
-            usleep(kMaxBufferRecoveryInUsecs);
+        if (activeTrack != 0) {
+            AudioBufferProvider::Buffer buffer;
+            size_t frameCount = mFrameCount;
+            curBuf = (int8_t *)mMixBuffer;
+            // output audio to hardware
+            while(frameCount) {
+                buffer.frameCount = frameCount;
+                activeTrack->getNextBuffer(&buffer);
+                if (UNLIKELY(buffer.raw == 0)) {
+                    memset(curBuf, 0, frameCount * mFrameSize);
+                    break;
+                }
+                memcpy(curBuf, buffer.raw, buffer.frameCount * mFrameSize);
+                frameCount -= buffer.frameCount;
+                curBuf += buffer.frameCount * mFrameSize;
+                activeTrack->releaseBuffer(&buffer);
+            }
+            sleepTime = 0;
+            standbyTime = systemTime() + kStandbyTimeInNsecs;
         } else {
-            if (activeTrack != 0) {
-                AudioBufferProvider::Buffer buffer;
-                size_t frameCount = mFrameCount;
-                curBuf = (int8_t *)mMixBuffer;
-                // output audio to hardware
-                while(frameCount) {
-                    buffer.frameCount = frameCount;
-                    activeTrack->getNextBuffer(&buffer);
-                    if (UNLIKELY(buffer.raw == 0)) {
-                        memset(curBuf, 0, frameCount * mFrameSize);
-                        break;
-                    }
-                    memcpy(curBuf, buffer.raw, buffer.frameCount * mFrameSize);
-                    frameCount -= buffer.frameCount;
-                    curBuf += buffer.frameCount * mFrameSize;
-                    activeTrack->releaseBuffer(&buffer);
-                }
+            sleepTime += kBufferRecoveryInUsecs;
+            if (sleepTime > kMaxBufferRecoveryInUsecs) {
+                sleepTime = kMaxBufferRecoveryInUsecs;
+            }
+            // There was nothing to mix this round, which means all
+            // active tracks were late. Sleep a little bit to give
+            // them another chance. If we're too late, write 0s to audio
+            // hardware to avoid underrun.
+            if (mBytesWritten != 0 && sleepTime >= kMaxBufferRecoveryInUsecs &&
+                AudioSystem::isLinearPCM(mFormat)) {
+                memset (mMixBuffer, 0, mFrameCount * mFrameSize);
                 sleepTime = 0;
-                standbyTime = systemTime() + kStandbyTimeInNsecs;
-            } else {
-                sleepTime += kBufferRecoveryInUsecs;
-                if (mBytesWritten == 0 || !AudioSystem::isLinearPCM(mFormat) ||
-                    sleepTime < kMaxBufferRecoveryInUsecs) {
-                    usleep(kBufferRecoveryInUsecs);
-                } else {
-                    memset (mMixBuffer, 0, mFrameCount * mFrameSize);
-                    sleepTime = 0;
-                }
             }
+        }
 
-            // sleepTime == 0 means PCM data were written to mMixBuffer[]
-            if (sleepTime == 0) {
-                mLastWriteTime = systemTime();
-                mInWrite = true;
-                int bytesWritten = (int)mOutput->write(mMixBuffer, mixBufferSize);
-                if (bytesWritten) mBytesWritten += bytesWritten;
-                mNumWrites++;
-                mInWrite = false;
-                mStandby = false;
-            }
+        if (mSuspended) {
+            sleepTime = kMaxBufferRecoveryInUsecs;
+        }
+        // sleepTime == 0 means we must write to audio hardware
+        if (sleepTime == 0) {
+            mLastWriteTime = systemTime();
+            mInWrite = true;
+            int bytesWritten = (int)mOutput->write(mMixBuffer, mixBufferSize);
+            if (bytesWritten) mBytesWritten += bytesWritten;
+            mNumWrites++;
+            mInWrite = false;
+            mStandby = false;
+        } else {
+            usleep(sleepTime);
         }
 
         // finally let go of removed track, without the lock held
@@ -1913,38 +1920,40 @@
             }
 
             enabledTracks = prepareTracks_l(activeTracks, &tracksToRemove);
-       }
+        }
 
-        bool mustSleep = true;
         if (LIKELY(enabledTracks)) {
             // mix buffers...
             mAudioMixer->process(curBuf);
-            if (!mSuspended) {
-                for (size_t i = 0; i < outputTracks.size(); i++) {
-                    outputTracks[i]->write(curBuf, mFrameCount);
-                    mustSleep = false;
-                }
-                mStandby = false;
-                mBytesWritten += mixBufferSize;
-            }
+            sleepTime = 0;
+            standbyTime = systemTime() + kStandbyTimeInNsecs;
         } else {
-            // flush remaining overflow buffers in output tracks
-            for (size_t i = 0; i < outputTracks.size(); i++) {
-                if (outputTracks[i]->isActive()) {
-                    outputTracks[i]->write(curBuf, 0);
-                    standbyTime = systemTime() + kStandbyTimeInNsecs;
-                    mustSleep = false;
-                }
+            sleepTime += kBufferRecoveryInUsecs;
+            if (sleepTime > kMaxBufferRecoveryInUsecs) {
+                sleepTime = kMaxBufferRecoveryInUsecs;
+            }
+            // There was nothing to mix this round, which means all
+            // active tracks were late. Sleep a little bit to give
+            // them another chance. If we're too late, write 0s to audio
+            // hardware to avoid underrun.
+            if (mBytesWritten != 0 && sleepTime >= kMaxBufferRecoveryInUsecs) {
+                memset (curBuf, 0, mixBufferSize);
+                sleepTime = 0;
             }
         }
-        if (mustSleep) {
-//            LOGV("threadLoop() sleeping %d", sleepTime);
-            usleep(sleepTime);
-            if (sleepTime < kMaxBufferRecoveryInUsecs) {
-                sleepTime += kBufferRecoveryInUsecs;
+
+        if (mSuspended) {
+            sleepTime = kMaxBufferRecoveryInUsecs;
+        }
+        // sleepTime == 0 means we must write to audio hardware
+        if (sleepTime == 0) {
+            for (size_t i = 0; i < outputTracks.size(); i++) {
+                outputTracks[i]->write(curBuf, mFrameCount);
             }
+            mStandby = false;
+            mBytesWritten += mixBufferSize;
         } else {
-            sleepTime = kBufferRecoveryInUsecs;
+            usleep(sleepTime);
         }
 
         // finally let go of all our tracks, without the lock held
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index 04f6e07..3e4c9af 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -112,8 +112,8 @@
 #endif
     rsAssert(mRootScript->mEnviroment.mIsRoot);
 
-    //glColor4f(1,1,1,1);
-    //glEnable(GL_LIGHT0);
+    eglQuerySurface(mEGL.mDisplay, mEGL.mSurface, EGL_WIDTH, &mEGL.mWidth);
+    eglQuerySurface(mEGL.mDisplay, mEGL.mSurface, EGL_HEIGHT, &mEGL.mHeight);
     glViewport(0, 0, mEGL.mWidth, mEGL.mHeight);
     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
     glEnable(GL_POINT_SMOOTH);
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/Layer.cpp b/libs/surfaceflinger/Layer.cpp
index 8dfc2cf..5ff9284 100644
--- a/libs/surfaceflinger/Layer.cpp
+++ b/libs/surfaceflinger/Layer.cpp
@@ -88,7 +88,6 @@
         mBuffers[i].clear();
         mWidth = mHeight = 0;
     }
-    mSurface.clear();
 }
 
 sp<LayerBaseClient::Surface> Layer::createSurface() const
@@ -99,7 +98,8 @@
 status_t Layer::ditch()
 {
     // the layer is not on screen anymore. free as much resources as possible
-    destroy();
+    //destroy();
+    mSurface.clear();
     return NO_ERROR;
 }
 
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index e87b563..831c446 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -1084,9 +1084,12 @@
 
 status_t SurfaceFlinger::purgatorizeLayer_l(const sp<LayerBase>& layerBase)
 {
-    // remove the layer from the main list (through a transaction).
+    // First add the layer to the purgatory list, which makes sure it won't 
+    // go away, then remove it from the main list (through a transaction).
     ssize_t err = removeLayer_l(layerBase);
-
+    if (err >= 0) {
+        mLayerPurgatory.add(layerBase);
+    }
     // it's possible that we don't find a layer, because it might
     // have been destroyed already -- this is not technically an error
     // from the user because there is a race between BClient::destroySurface(),
@@ -1359,8 +1362,18 @@
              * to use the purgatory.
              */
             status_t err = flinger->removeLayer_l(l);
-            LOGE_IF(err<0 && err != NAME_NOT_FOUND,
-                    "error removing layer=%p (%s)", l.get(), strerror(-err));
+            if (err == NAME_NOT_FOUND) {
+                // The surface wasn't in the current list, which means it was
+                // removed already, which means it is in the purgatory, 
+                // and need to be removed from there.
+                // This needs to happen from the main thread since its dtor
+                // must run from there (b/c of OpenGL ES). Additionally, we
+                // can't really acquire our internal lock from 
+                // destroySurface() -- see postMessage() below.
+                ssize_t idx = flinger->mLayerPurgatory.remove(l);
+                LOGE_IF(idx < 0,
+                        "layer=%p is not in the purgatory list", l.get());
+            }
             return true;
         }
     };
diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/libs/surfaceflinger/SurfaceFlinger.h
index f207f85..493e777 100644
--- a/libs/surfaceflinger/SurfaceFlinger.h
+++ b/libs/surfaceflinger/SurfaceFlinger.h
@@ -250,7 +250,9 @@
           GraphicPlane&     graphicPlane(int dpy);
 
             void        waitForEvent();
+public:     // hack to work around gcc 4.0.3 bug
             void        signalEvent();
+private:
             void        signalDelayedEvent(nsecs_t delay);
 
             void        handleConsoleEvents();
@@ -312,6 +314,7 @@
     volatile    int32_t                 mTransactionCount;
                 Condition               mTransactionCV;
                 bool                    mResizeTransationPending;
+                SortedVector< sp<LayerBase> > mLayerPurgatory;
                 
                 // protected by mStateLock (but we could use another lock)
                 Tokenizer                               mTokens;
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index f80843d..a5a8cc9 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -1740,7 +1740,11 @@
     const int e = Res_GETENTRY(resID);
 
     if (p < 0) {
-        LOGW("No package identifier when getting name for resource number 0x%08x", resID);
+        if (Res_GETPACKAGE(resID)+1 == 0) {
+            LOGW("No package identifier when getting name for resource number 0x%08x", resID);
+        } else {
+            LOGW("Resources don't contain pacakge for resource number 0x%08x", resID);
+        }
         return false;
     }
     if (t < 0) {
@@ -1786,7 +1790,11 @@
     const int e = Res_GETENTRY(resID);
 
     if (p < 0) {
-        LOGW("No package identifier when getting value for resource number 0x%08x", resID);
+        if (Res_GETPACKAGE(resID)+1 == 0) {
+            LOGW("No package identifier when getting name for resource number 0x%08x", resID);
+        } else {
+            LOGW("Resources don't contain pacakge for resource number 0x%08x", resID);
+        }
         return BAD_INDEX;
     }
     if (t < 0) {
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 37a3bd5..3ac5df5 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -736,6 +736,28 @@
                     if (time != -1) {
                         values.put(Images.Media.DATE_TAKEN, time);
                     }
+
+                    int orientation = exif.getAttributeInt(
+                        ExifInterface.TAG_ORIENTATION, -1);
+                    if (orientation != -1) {
+                        // We only recognize a subset of orientation tag values.
+                        int degree;
+                        switch(orientation) {
+                            case ExifInterface.ORIENTATION_ROTATE_90:
+                                degree = 90;
+                                break;
+                            case ExifInterface.ORIENTATION_ROTATE_180:
+                                degree = 180;
+                                break;
+                            case ExifInterface.ORIENTATION_ROTATE_270:
+                                degree = 270;
+                                break;
+                            default:
+                                degree = 0;
+                                break;
+                        }
+                        values.put(Images.Media.ORIENTATION, degree);
+                    }
                 }
             }
 
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaProfileReader.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaProfileReader.java
index 0401390..53afb1d 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaProfileReader.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaProfileReader.java
@@ -32,6 +32,29 @@
         return s;
     }
 
+    public static boolean getWMAEnable() {
+        // push all the property into one big table
+        int wmaEnable = 1;
+        wmaEnable = SystemProperties.getInt("ro.media.dec.aud.wma.enabled",
+                wmaEnable);
+        if (wmaEnable == 1) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    public static boolean getWMVEnable(){
+        int wmvEnable = 1;
+        wmvEnable = SystemProperties.getInt("ro.media.dec.vid.wmv.enabled",
+                wmvEnable);
+        if (wmvEnable == 1) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
     public static void createVideoProfileTable() {
         // push all the property into one big table
         String encoderType = getVideoCodecProperty();
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java
index 30e2d6c..392d1d5 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaPlayerApiTest.java
@@ -18,6 +18,7 @@
 
 import com.android.mediaframeworktest.MediaFrameworkTest;
 import com.android.mediaframeworktest.MediaNames;
+import com.android.mediaframeworktest.MediaProfileReader;
 
 import android.content.Context;
 import android.test.ActivityInstrumentationTestCase;
@@ -35,11 +36,15 @@
 public class MediaPlayerApiTest extends ActivityInstrumentationTestCase<MediaFrameworkTest> {    
    private boolean duratoinWithinTolerence = false;
    private String TAG = "MediaPlayerApiTest";
+   private boolean isWMAEnable = false;
+   private boolean isWMVEnable = false;
    
    Context mContext;
   
    public MediaPlayerApiTest() {
      super("com.android.mediaframeworktest", MediaFrameworkTest.class);
+     isWMAEnable = MediaProfileReader.getWMAEnable();
+     isWMVEnable = MediaProfileReader.getWMVEnable();
    }
 
     protected void setUp() throws Exception {
@@ -82,9 +87,11 @@
     
     @MediumTest
     public void testWMA9GetDuration() throws Exception {
-      int duration = CodecTest.getDuration(MediaNames.WMA9); 
-      duratoinWithinTolerence = verifyDuration(duration, MediaNames.WMA9_LENGTH);
-      assertTrue("WMA9 getDuration", duratoinWithinTolerence);  
+      if (isWMAEnable) {
+            int duration = CodecTest.getDuration(MediaNames.WMA9);
+            duratoinWithinTolerence = verifyDuration(duration, MediaNames.WMA9_LENGTH);
+            assertTrue("WMA9 getDuration", duratoinWithinTolerence);
+        }
     }
 
     @MediumTest
@@ -123,8 +130,10 @@
     
     @LargeTest
     public void testWMA9GetCurrentPosition() throws Exception {
-      boolean currentPosition = CodecTest.getCurrentPosition(MediaNames.WMA9);  
-      assertTrue("WMA9 GetCurrentPosition", currentPosition);  
+        if (isWMAEnable) {
+            boolean currentPosition = CodecTest.getCurrentPosition(MediaNames.WMA9);
+            assertTrue("WMA9 GetCurrentPosition", currentPosition);
+        }
     }
     
     @LargeTest
@@ -160,8 +169,10 @@
    
     @LargeTest
     public void testWMA9Pause() throws Exception {
-      boolean isPaused = CodecTest.pause(MediaNames.WMA9);  
-      assertTrue("WMA9 Pause", isPaused);  
+        if (isWMAEnable) {
+            boolean isPaused = CodecTest.pause(MediaNames.WMA9);
+            assertTrue("WMA9 Pause", isPaused);
+        }
     }
   
     @LargeTest
@@ -269,8 +280,10 @@
     
     @LargeTest
     public void testWMA9SeekTo() throws Exception {
-      boolean isLoop = CodecTest.seekTo(MediaNames.WMA9);  
-      assertTrue("WMA9 seekTo", isLoop);  
+        if (isWMAEnable) {
+            boolean isLoop = CodecTest.seekTo(MediaNames.WMA9);
+            assertTrue("WMA9 seekTo", isLoop);
+        }
     }
     
     @LargeTest
@@ -309,8 +322,10 @@
     @Suppress
     @LargeTest
     public void testWMA9SeekToEnd() throws Exception {
-      boolean isEnd = CodecTest.seekToEnd(MediaNames.WMA9);  
-      assertTrue("WMA9 seekToEnd", isEnd);  
+        if (isWMAEnable) {
+            boolean isEnd = CodecTest.seekToEnd(MediaNames.WMA9);
+            assertTrue("WMA9 seekToEnd", isEnd);
+        }
     }
     
     @LargeTest
@@ -327,8 +342,10 @@
     
     @LargeTest
     public void testWAVSeekToEnd() throws Exception {
-      boolean isEnd = CodecTest.seekToEnd(MediaNames.WAV);  
-      assertTrue("WAV seekToEnd", isEnd);  
+        if (isWMVEnable) {
+            boolean isEnd = CodecTest.seekToEnd(MediaNames.WAV);
+            assertTrue("WAV seekToEnd", isEnd);
+        }
     }  
     
     @MediumTest
@@ -385,8 +402,12 @@
    
     @LargeTest
     public void testVideoWMVSeekTo() throws Exception {
-      boolean isSeek = CodecTest.videoSeekTo(MediaNames.VIDEO_WMV);
-      assertTrue("WMV SeekTo", isSeek);         
+        Log.v(TAG, "wmv not enable");
+        if (isWMVEnable) {
+            Log.v(TAG, "wmv enable");
+            boolean isSeek = CodecTest.videoSeekTo(MediaNames.VIDEO_WMV);
+            assertTrue("WMV SeekTo", isSeek);
+        }
     }
     
     @LargeTest
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 4a4ad6f3..690eff6 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaRecorderTest.java
@@ -214,6 +214,7 @@
             Log.v(TAG, "before getduration");
             mOutputDuration = mediaPlayer.getDuration();
             Log.v(TAG, "get video dimension");
+            Thread.sleep(1000);
             mOutputVideoHeight = mediaPlayer.getVideoHeight();
             mOutputVideoWidth = mediaPlayer.getVideoWidth();
             //mOutputVideoHeight = CodecTest.videoHeight(outputFilePath);
@@ -238,7 +239,7 @@
             validVideo = true;
         }
         Log.v(TAG, "width = " + mOutputVideoWidth + " height = " + mOutputVideoHeight + " Duration = " + mOutputDuration);
-        removeFile(filePath);
+        //removeFile(filePath);
         return validVideo;
     }
     
@@ -416,7 +417,8 @@
                MediaRecorder.OutputFormat.THREE_GPP, MediaNames.RECORDED_VIDEO_3GP, false);      
         assertTrue("Invalid video Size", isTestInvalidVideoSizeSuccessful);
     }
-    
+
+    @Suppress
     @LargeTest
     public void testInvalidFrameRate() throws Exception {       
         boolean isTestInvalidFrameRateSuccessful = false;
@@ -426,8 +428,9 @@
     }
 
     @LargeTest
-    //est cases for the new codec
+    //test cases for the new codec
     public void testDeviceSpecificCodec() throws Exception {
+        int noOfFailure = 0;
         boolean recordSuccess = false;
         String deviceType = MediaProfileReader.getDeviceType();
         Log.v(TAG, "deviceType = " + deviceType);
@@ -448,10 +451,18 @@
                         } else {
                             recordSuccess = recordVideoWithPara(encoder[i], audio[j], "low");
                         }
-                        assertTrue((encoder[i] + audio[j]), recordSuccess);
+                        if (!recordSuccess){
+                            Log.v(TAG, "testDeviceSpecificCodec failed");
+                            Log.v(TAG, "Encoder = " + encoder[i] + "Audio Encoder = " + audio[j]);
+                            noOfFailure++;
+                        }
+                       //assertTrue((encoder[i] + audio[j]), recordSuccess);
                     }
                 }
             }
         }
+        if (noOfFailure != 0){
+            assertTrue("testDeviceSpecificCodec", false);
+        }
     }
 }
diff --git a/obex/javax/obex/HeaderSet.java b/obex/javax/obex/HeaderSet.java
index 8b457f6..b89b707 100644
--- a/obex/javax/obex/HeaderSet.java
+++ b/obex/javax/obex/HeaderSet.java
@@ -35,7 +35,7 @@
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.util.Calendar;
-import java.util.Random;
+import java.security.SecureRandom;
 
 /**
  * This class implements the javax.obex.HeaderSet interface for OBEX over
@@ -209,7 +209,7 @@
 
     private Long[] mIntegerUserDefined; // 4 byte unsigned integer
 
-    private final Random mRandom;
+    private final SecureRandom mRandom;
 
     /*package*/ byte[] nonce;
 
@@ -231,7 +231,7 @@
         mByteUserDefined = new Byte[16];
         mIntegerUserDefined = new Long[16];
         responseCode = -1;
-        mRandom = new Random();
+        mRandom = new SecureRandom();
     }
 
     /**
diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java
index 022da0c..b3a19e3 100644
--- a/opengl/java/android/opengl/GLSurfaceView.java
+++ b/opengl/java/android/opengl/GLSurfaceView.java
@@ -271,18 +271,52 @@
      * @param renderer the renderer to use to perform OpenGL drawing.
      */
     public void setRenderer(Renderer renderer) {
-        if (mGLThread != null) {
-            throw new IllegalStateException(
-                    "setRenderer has already been called for this instance.");
-        }
+        checkRenderThreadState();
         if (mEGLConfigChooser == null) {
             mEGLConfigChooser = new SimpleEGLConfigChooser(true);
         }
+        if (mEGLContextFactory == null) {
+            mEGLContextFactory = new DefaultContextFactory();
+        }
+        if (mEGLWindowSurfaceFactory == null) {
+            mEGLWindowSurfaceFactory = new DefaultWindowSurfaceFactory();
+        }
         mGLThread = new GLThread(renderer);
         mGLThread.start();
     }
 
     /**
+     * @hide
+     * Install a custom EGLContextFactory.
+     * <p>If this method is
+     * called, it must be called before {@link #setRenderer(Renderer)}
+     * is called.
+     * <p>
+     * If this method is not called, then by default
+     * a context will be created with no shared context and
+     * with a null attribute list.
+     */
+    public void setContextFactory(EGLContextFactory factory) {
+        checkRenderThreadState();
+        mEGLContextFactory = factory;
+    }
+
+    /**
+     * @hide
+     * Install a custom EGLWindowSurfaceFactory.
+     * <p>If this method is
+     * called, it must be called before {@link #setRenderer(Renderer)}
+     * is called.
+     * <p>
+     * If this method is not called, then by default
+     * a window surface will be created with a null attribute list.
+     */
+    public void setWindowSurfaceFactory(EGLWindowSurfaceFactory factory) {
+        checkRenderThreadState();
+        mEGLWindowSurfaceFactory = factory;
+    }
+
+    /**
      * Install a custom EGLConfigChooser.
      * <p>If this method is
      * called, it must be called before {@link #setRenderer(Renderer)}
@@ -294,10 +328,7 @@
      * @param configChooser
      */
     public void setEGLConfigChooser(EGLConfigChooser configChooser) {
-        if (mGLThread != null) {
-            throw new IllegalStateException(
-                    "setRenderer has already been called for this instance.");
-        }
+        checkRenderThreadState();
         mEGLConfigChooser = configChooser;
     }
 
@@ -578,6 +609,56 @@
     }
 
     /**
+     * @hide
+     * An interface for customizing the eglCreateContext and eglDestroyContext calls.
+     * <p>
+     * This interface must be implemented by clients wishing to call
+     * {@link GLSurfaceView#setEGLContextFactory(EGLContextFactory)}
+     */
+    public interface EGLContextFactory {
+        EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig);
+        void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context);
+    }
+
+    private static class DefaultContextFactory implements EGLContextFactory {
+
+        public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig config) {
+            return egl.eglCreateContext(display, config, EGL10.EGL_NO_CONTEXT, null);
+        }
+
+        public void destroyContext(EGL10 egl, EGLDisplay display,
+                EGLContext context) {
+            egl.eglDestroyContext(display, context);
+        }
+    }
+
+    /**
+     * @hide
+     * An interface for customizing the eglCreateWindowSurface and eglDestroySurface calls.
+     * <p>
+     * This interface must be implemented by clients wishing to call
+     * {@link GLSurfaceView#setEGLContextCreator(EGLContextCreator)}
+     */
+    public interface EGLWindowSurfaceFactory {
+        EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display, EGLConfig config,
+                Object nativeWindow);
+        void destroySurface(EGL10 egl, EGLDisplay display, EGLSurface surface);
+    }
+
+    private static class DefaultWindowSurfaceFactory implements EGLWindowSurfaceFactory {
+
+        public EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display,
+                EGLConfig config, Object nativeWindow) {
+            return egl.eglCreateWindowSurface(display, config, nativeWindow, null);
+        }
+
+        public void destroySurface(EGL10 egl, EGLDisplay display,
+                EGLSurface surface) {
+            egl.eglDestroySurface(display, surface);
+        }
+    }
+
+    /**
      * An interface for choosing an EGLConfig configuration from a list of
      * potential configurations.
      * <p>
@@ -751,8 +832,7 @@
             * Create an OpenGL ES context. This must be done only once, an
             * OpenGL context is a somewhat heavy object.
             */
-            mEglContext = mEgl.eglCreateContext(mEglDisplay, mEglConfig,
-                    EGL10.EGL_NO_CONTEXT, null);
+            mEglContext = mEGLContextFactory.createContext(mEgl, mEglDisplay, mEglConfig);
 
             mEglSurface = null;
         }
@@ -774,14 +854,14 @@
                  */
                 mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
                         EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
-                mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
+                mEGLWindowSurfaceFactory.destroySurface(mEgl, mEglDisplay, mEglSurface);
             }
 
             /*
              * Create an EGL surface we can render into.
              */
-            mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay,
-                    mEglConfig, holder, null);
+            mEglSurface = mEGLWindowSurfaceFactory.createWindowSurface(mEgl,
+                    mEglDisplay, mEglConfig, holder);
 
             /*
              * Before we can issue GL commands, we need to make sure
@@ -790,7 +870,6 @@
             mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
                     mEglContext);
 
-
             GL gl = mEglContext.getGL();
             if (mGLWrapper != null) {
                 gl = mGLWrapper.wrap(gl);
@@ -826,16 +905,19 @@
             return mEgl.eglGetError() != EGL11.EGL_CONTEXT_LOST;
         }
 
-        public void finish() {
+        public void destroySurface() {
             if (mEglSurface != null) {
                 mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE,
                         EGL10.EGL_NO_SURFACE,
                         EGL10.EGL_NO_CONTEXT);
-                mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
+                mEGLWindowSurfaceFactory.destroySurface(mEgl, mEglDisplay, mEglSurface);
                 mEglSurface = null;
             }
+        }
+
+        public void finish() {
             if (mEglContext != null) {
-                mEgl.eglDestroyContext(mEglDisplay, mEglContext);
+                mEGLContextFactory.destroyContext(mEgl, mEglDisplay, mEglContext);
                 mEglContext = null;
             }
             if (mEglDisplay != null) {
@@ -895,78 +977,93 @@
 
         private void guardedRun() throws InterruptedException {
             mEglHelper = new EglHelper();
-            mEglHelper.start();
+            try {
+                mEglHelper.start();
 
-            GL10 gl = null;
-            boolean tellRendererSurfaceCreated = true;
-            boolean tellRendererSurfaceChanged = true;
-
-            /*
-             * This is our main activity thread's loop, we go until
-             * asked to quit.
-             */
-            while (!mDone) {
+                GL10 gl = null;
+                boolean tellRendererSurfaceCreated = true;
+                boolean tellRendererSurfaceChanged = true;
 
                 /*
-                 *  Update the asynchronous state (window size)
+                 * This is our main activity thread's loop, we go until
+                 * asked to quit.
                  */
-                int w, h;
-                boolean changed;
-                boolean needStart = false;
-                synchronized (this) {
-                    Runnable r;
-                    while ((r = getEvent()) != null) {
-                        r.run();
-                    }
-                    if (mPaused) {
-                        mEglHelper.finish();
-                        needStart = true;
-                    }
-                    while (needToWait()) {
-                        wait();
-                    }
-                    if (mDone) {
-                        break;
-                    }
-                    changed = mSizeChanged;
-                    w = mWidth;
-                    h = mHeight;
-                    mSizeChanged = false;
-                    mRequestRender = false;
-                }
-                if (needStart) {
-                    mEglHelper.start();
-                    tellRendererSurfaceCreated = true;
-                    changed = true;
-                }
-                if (changed) {
-                    gl = (GL10) mEglHelper.createSurface(getHolder());
-                    tellRendererSurfaceChanged = true;
-                }
-                if (tellRendererSurfaceCreated) {
-                    mRenderer.onSurfaceCreated(gl, mEglHelper.mEglConfig);
-                    tellRendererSurfaceCreated = false;
-                }
-                if (tellRendererSurfaceChanged) {
-                    mRenderer.onSurfaceChanged(gl, w, h);
-                    tellRendererSurfaceChanged = false;
-                }
-                if ((w > 0) && (h > 0)) {
-                    /* draw a frame here */
-                    mRenderer.onDrawFrame(gl);
+                while (!mDone) {
 
                     /*
-                     * Once we're done with GL, we need to call swapBuffers()
-                     * to instruct the system to display the rendered frame
+                     *  Update the asynchronous state (window size)
                      */
-                    mEglHelper.swap();
-                }
-             }
+                    int w, h;
+                    boolean changed;
+                    boolean needStart = false;
+                    synchronized (this) {
+                        Runnable r;
+                        while ((r = getEvent()) != null) {
+                            r.run();
+                        }
+                        if (mPaused) {
+                            mEglHelper.destroySurface();
+                            mEglHelper.finish();
+                            needStart = true;
+                        }
+                        while (needToWait()) {
+                            if (!mHasSurface) {
+                                if (!mWaitingForSurface) {
+                                    mEglHelper.destroySurface();
+                                    mWaitingForSurface = true;
+                                    notify();
+                                }
+                            }
+                            wait();
+                        }
+                        if (mDone) {
+                            break;
+                        }
+                        changed = mSizeChanged;
+                        w = mWidth;
+                        h = mHeight;
+                        mSizeChanged = false;
+                        mRequestRender = false;
+                        if (mHasSurface && mWaitingForSurface) {
+                            changed = true;
+                            mWaitingForSurface = false;
+                        }
+                    }
+                    if (needStart) {
+                        mEglHelper.start();
+                        tellRendererSurfaceCreated = true;
+                        changed = true;
+                    }
+                    if (changed) {
+                        gl = (GL10) mEglHelper.createSurface(getHolder());
+                        tellRendererSurfaceChanged = true;
+                    }
+                    if (tellRendererSurfaceCreated) {
+                        mRenderer.onSurfaceCreated(gl, mEglHelper.mEglConfig);
+                        tellRendererSurfaceCreated = false;
+                    }
+                    if (tellRendererSurfaceChanged) {
+                        mRenderer.onSurfaceChanged(gl, w, h);
+                        tellRendererSurfaceChanged = false;
+                    }
+                    if ((w > 0) && (h > 0)) {
+                        /* draw a frame here */
+                        mRenderer.onDrawFrame(gl);
 
-            /*
-             * clean-up everything...
-             */
-            mEglHelper.finish();
+                        /*
+                         * Once we're done with GL, we need to call swapBuffers()
+                         * to instruct the system to display the rendered frame
+                         */
+                        mEglHelper.swap();
+                    }
+                 }
+            } finally {
+                /*
+                 * clean-up everything...
+                 */
+                mEglHelper.destroySurface();
+                mEglHelper.finish();
+            }
         }
 
         private boolean needToWait() {
@@ -1021,6 +1118,13 @@
             synchronized(this) {
                 mHasSurface = false;
                 notify();
+                while(!mWaitingForSurface && isAlive()) {
+                    try {
+                        wait();
+                    } catch (InterruptedException e) {
+                        Thread.currentThread().interrupt();
+                    }
+                }
             }
         }
 
@@ -1083,6 +1187,7 @@
         private boolean mDone;
         private boolean mPaused;
         private boolean mHasSurface;
+        private boolean mWaitingForSurface;
         private int mWidth;
         private int mHeight;
         private int mRenderMode;
@@ -1124,11 +1229,21 @@
         private StringBuilder mBuilder = new StringBuilder();
     }
 
+
+    private void checkRenderThreadState() {
+        if (mGLThread != null) {
+            throw new IllegalStateException(
+                    "setRenderer has already been called for this instance.");
+        }
+    }
+
     private static final Semaphore sEglSemaphore = new Semaphore(1);
     private boolean mSizeChanged = true;
 
     private GLThread mGLThread;
     private EGLConfigChooser mEGLConfigChooser;
+    private EGLContextFactory mEGLContextFactory;
+    private EGLWindowSurfaceFactory mEGLWindowSurfaceFactory;
     private GLWrapper mGLWrapper;
     private int mDebugFlags;
 }
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index d51b333..7e7da1b 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -222,19 +222,28 @@
     }
 }
 
-void *Loader::load_driver(const char* driver, gl_hooks_t* hooks, uint32_t mask)
+void *Loader::load_driver(const char* driver_absolute_path,
+        gl_hooks_t* hooks, uint32_t mask)
 {
-    void* dso = dlopen(driver, RTLD_NOW | RTLD_LOCAL);
-    if (dso == 0)
+    if (access(driver_absolute_path, R_OK)) {
+        // this happens often, we don't want to log an error
         return 0;
+    }
 
-    LOGD("loaded %s", driver);
+    void* dso = dlopen(driver_absolute_path, RTLD_NOW | RTLD_LOCAL);
+    if (dso == 0) {
+        const char* err = dlerror();
+        LOGE("load_driver(%s): %s", driver_absolute_path, err?err:"unknown");
+        return 0;
+    }
+
+    LOGD("loaded %s", driver_absolute_path);
 
     if (mask & EGL) {
         getProcAddress = (getProcAddressType)dlsym(dso, "eglGetProcAddress");
 
         LOGE_IF(!getProcAddress, 
-                "can't find eglGetProcAddress() in %s", driver);        
+                "can't find eglGetProcAddress() in %s", driver_absolute_path);
 
         gl_hooks_t::egl_t* egl = &hooks->egl;
         __eglMustCastToProperFunctionPointerType* curr =
diff --git a/opengl/tests/gl2_basic/gl2_basic.cpp b/opengl/tests/gl2_basic/gl2_basic.cpp
index d4887ba..f97d347 100644
--- a/opengl/tests/gl2_basic/gl2_basic.cpp
+++ b/opengl/tests/gl2_basic/gl2_basic.cpp
@@ -21,8 +21,8 @@
 #include <sys/resource.h>
 
 #include <EGL/egl.h>
-#include <GLES/gl.h>
-#include <GLES/glext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
 
 #include <utils/Timers.h>
 
@@ -31,144 +31,267 @@
 
 using namespace android;
 
-static void printGLString(const char *name, GLenum s)
-{
-     fprintf(stderr, "printGLString %s, %d\n", name, s);
-#if 0 // causes hangs
-     const char *v = (const char *)glGetString(s);
-     int error = glGetError();
-     fprintf(stderr, "glGetError() = %d, result of glGetString = %x\n", error,
-         (unsigned int)v);
-     if ((v < (const char*) 0) || (v > (const char*) 0x10000))
-         fprintf(stderr, "GL %s = %s\n", name, v);
-     else
-         fprintf(stderr, "GL %s = (null) 0x%08x\n", name, (unsigned int) v);
-#endif
+static void printGLString(const char *name, GLenum s) {
+    // fprintf(stderr, "printGLString %s, %d\n", name, s);
+    const char *v = (const char *) glGetString(s);
+    // int error = glGetError();
+    // fprintf(stderr, "glGetError() = %d, result of glGetString = %x\n", error,
+    //        (unsigned int) v);
+    // if ((v < (const char*) 0) || (v > (const char*) 0x10000))
+    //    fprintf(stderr, "GL %s = %s\n", name, v);
+    // else
+    //    fprintf(stderr, "GL %s = (null) 0x%08x\n", name, (unsigned int) v);
+    fprintf(stderr, "GL %s = %s\n", name, v);
 }
 
 static const char* eglErrorToString[] = {
-    "EGL_SUCCESS",      // 0x3000 12288
-    "EGL_NOT_INITIALIZED",
-    "EGL_BAD_ACCESS",   // 0x3002 12290
-    "EGL_BAD_ALLOC",
-    "EGL_BAD_ATTRIBUTE",
-    "EGL_BAD_CONFIG",
-    "EGL_BAD_CONTEXT",  // 0x3006 12294
-    "EGL_BAD_CURRENT_SURFACE",
-    "EGL_BAD_DISPLAY",
-    "EGL_BAD_MATCH",
-    "EGL_BAD_NATIVE_PIXMAP",
-    "EGL_BAD_NATIVE_WINDOW",
-    "EGL_BAD_PARAMETER",  // 0x300c 12300
-    "EGL_BAD_SURFACE"
-};
+        "EGL_SUCCESS", // 0x3000 12288
+        "EGL_NOT_INITIALIZED",
+        "EGL_BAD_ACCESS", // 0x3002 12290
+        "EGL_BAD_ALLOC", "EGL_BAD_ATTRIBUTE",
+        "EGL_BAD_CONFIG",
+        "EGL_BAD_CONTEXT", // 0x3006 12294
+        "EGL_BAD_CURRENT_SURFACE", "EGL_BAD_DISPLAY", "EGL_BAD_MATCH",
+        "EGL_BAD_NATIVE_PIXMAP", "EGL_BAD_NATIVE_WINDOW", "EGL_BAD_PARAMETER", // 0x300c 12300
+        "EGL_BAD_SURFACE" };
 
 static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) {
     if (returnVal != EGL_TRUE) {
         fprintf(stderr, "%s() returned %d\n", op, returnVal);
     }
 
-    for(EGLint error = eglGetError();
-		error != EGL_SUCCESS;
-	error = eglGetError()) {
+    for (EGLint error = eglGetError(); error != EGL_SUCCESS; error
+            = eglGetError()) {
         const char* errorString = "unknown";
         if (error >= EGL_SUCCESS && error <= EGL_BAD_SURFACE) {
             errorString = eglErrorToString[error - EGL_SUCCESS];
         }
-        fprintf(stderr, "after %s() eglError %s (0x%x)\n", op,
-            errorString, error);
+        fprintf(stderr, "after %s() eglError %s (0x%x)\n", op, errorString,
+                error);
     }
 }
 
-int main(int argc, char** argv)
-{
+static void checkGlError(const char* op) {
+    for (GLint error = glGetError(); error; error
+            = glGetError()) {
+        fprintf(stderr, "after %s() glError (0x%x)\n", op, error);
+    }
+}
+
+static const char gVertexShader[] = "attribute vec4 vPosition;\n"
+    "void main() {\n"
+    "  gl_Position = vPosition;\n"
+    "}\n";
+
+static const char gFragmentShader[] = "precision mediump float;\n"
+    "void main() {\n"
+    "  gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
+    "}\n";
+
+GLuint loadShader(GLenum shaderType, const char* pSource) {
+    GLuint shader = glCreateShader(shaderType);
+    if (shader) {
+        glShaderSource(shader, 1, &pSource, NULL);
+        glCompileShader(shader);
+        GLint compiled = 0;
+        glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+        if (!compiled) {
+            GLint infoLen = 0;
+            glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
+            if (infoLen) {
+                char* buf = (char*) malloc(infoLen);
+                if (buf) {
+                    glGetShaderInfoLog(shader, infoLen, NULL, buf);
+                    fprintf(stderr, "Could not compile shader %d:\n%s\n",
+                            shaderType, buf);
+                    free(buf);
+                }
+                glDeleteShader(shader);
+                shader = 0;
+            }
+        }
+    }
+    return shader;
+}
+
+GLuint createProgram(const char* pVertexSource, const char* pFragmentSource) {
+    GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource);
+    if (!vertexShader) {
+        return 0;
+    }
+
+    GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);
+    if (!pixelShader) {
+        return 0;
+    }
+
+    GLuint program = glCreateProgram();
+    if (program) {
+        glAttachShader(program, vertexShader);
+        checkGlError("glAttachShader");
+        glAttachShader(program, pixelShader);
+        checkGlError("glAttachShader");
+        glLinkProgram(program);
+        GLint linkStatus = GL_FALSE;
+        glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
+        if (linkStatus != GL_TRUE) {
+            GLint bufLength = 0;
+            glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
+            if (bufLength) {
+                char* buf = (char*) malloc(bufLength);
+                if (buf) {
+                    glGetProgramInfoLog(program, bufLength, NULL, buf);
+                    fprintf(stderr, "Could not link program:\n%s\n", buf);
+                    free(buf);
+                }
+            }
+            glDeleteProgram(program);
+            program = 0;
+        }
+    }
+    return program;
+}
+
+GLuint gProgram;
+GLuint gvPositionHandle;
+
+bool setupGraphics(int w, int h) {
+    gProgram = createProgram(gVertexShader, gFragmentShader);
+    if (!gProgram) {
+        return false;
+    }
+    gvPositionHandle = glGetAttribLocation(gProgram, "vPosition");
+    checkGlError("glGetAttribLocation");
+    fprintf(stderr, "glGetAttribLocation(\"vPosition\") = %d\n",
+            gvPositionHandle);
+
+    glViewport(0, 0, w, h);
+    checkGlError("glViewport");
+    return true;
+}
+
+const GLfloat gTriangleVertices[] = { 0.0f, 0.5f, -0.5f, -0.5f,
+        0.5f, -0.5f };
+
+void renderFrame() {
+    glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
+    checkGlError("glClearColor");
+    glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+    checkGlError("glClear");
+
+    glUseProgram(gProgram);
+    checkGlError("glUseProgram");
+
+    glVertexAttribPointer(gvPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, gTriangleVertices);
+    checkGlError("glVertexAttribPointer");
+    glEnableVertexAttribArray(gvPositionHandle);
+    checkGlError("glEnableVertexAttribArray");
+    glDrawArrays(GL_TRIANGLES, 0, 3);
+    checkGlError("glDrawArrays");
+}
+
+int main(int argc, char** argv) {
     EGLBoolean returnValue;
     EGLConfig configs[2];
     EGLint config_count;
 
-	EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
-    EGLint s_configAttribs[] = {
-	EGL_BUFFER_SIZE,     EGL_DONT_CARE,
-	EGL_RED_SIZE,        5,
-	EGL_GREEN_SIZE,      6,
-	EGL_BLUE_SIZE,       5,
-	EGL_DEPTH_SIZE,      8,
-	EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
-	EGL_NONE
-     };
+    EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
+    EGLint s_configAttribs[] = { EGL_BUFFER_SIZE, EGL_DONT_CARE, EGL_RED_SIZE,
+            5, EGL_GREEN_SIZE, 6, EGL_BLUE_SIZE, 5, EGL_DEPTH_SIZE, 8,
+            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE };
 
-     EGLint majorVersion;
-     EGLint minorVersion;
-     EGLContext context;
-     EGLSurface surface;
-     EGLint w, h;
+    EGLint s_configAttribs2[] =
+    {
+            EGL_DEPTH_SIZE,     16,
+            EGL_NONE
+    };
 
-     EGLDisplay dpy;
+    EGLint majorVersion;
+    EGLint minorVersion;
+    EGLContext context;
+    EGLSurface surface;
+    EGLint w, h;
 
-     EGLNativeWindowType window = 0;
-     window = android_createDisplaySurface();
+    EGLDisplay dpy;
 
-     checkEglError("<init>");
-     dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-     checkEglError("eglGetDisplay");
-     if (dpy == EGL_NO_DISPLAY) {
-         printf("eglGetDisplay returned EGL_NO_DISPLAY.\n");
-         return 0;
-     }
-     returnValue = eglInitialize(dpy, &majorVersion, &minorVersion);
-     checkEglError("eglInitialize", returnValue);
-     fprintf(stderr, "EGL version %d.%d\n", majorVersion, minorVersion);
+    EGLNativeWindowType window = 0;
+    window = android_createDisplaySurface();
 
-     returnValue = eglGetConfigs (dpy, configs, 2, &config_count);
-     checkEglError("eglGetConfigs", returnValue);
-     fprintf(stderr, "Config count: %d\n", config_count);
-     for(int i = 0; i < config_count; i++) {
+    checkEglError("<init>");
+    dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    checkEglError("eglGetDisplay");
+    if (dpy == EGL_NO_DISPLAY) {
+        printf("eglGetDisplay returned EGL_NO_DISPLAY.\n");
+        return 0;
+    }
+
+    returnValue = eglInitialize(dpy, &majorVersion, &minorVersion);
+    checkEglError("eglInitialize", returnValue);
+    fprintf(stderr, "EGL version %d.%d\n", majorVersion, minorVersion);
+    if (returnValue != EGL_TRUE) {
+        printf("eglInitialize failed\n");
+        return 0;
+    }
+
+    returnValue = eglGetConfigs(dpy, configs, 2, &config_count);
+    checkEglError("eglGetConfigs", returnValue);
+    fprintf(stderr, "Config count: %d\n", config_count);
+    for (int i = 0; i < config_count; i++) {
         fprintf(stderr, "%d: 0x%08x\n", i, (unsigned int) configs[i]);
-     }
+    }
+
 #if 0
-     EGLConfig config;
-     EGLUtils::selectConfigForNativeWindow(dpy, s_configAttribs, window, &config);
-     checkEglError("EGLUtils::selectConfigForNativeWindow");
+    EGLConfig config;
+    EGLUtils::selectConfigForNativeWindow(dpy, s_configAttribs, window, &config);
+    checkEglError("EGLUtils::selectConfigForNativeWindow");
 #else
-    int chooseConfigResult = eglChooseConfig(dpy, s_configAttribs, configs, 2, &config_count);
+    int chooseConfigResult = eglChooseConfig(dpy, s_configAttribs2, configs, 2,
+            &config_count);
     checkEglError("eglChooseConfig", chooseConfigResult);
-    if (chooseConfigResult != EGL_TRUE )

-    {

+    if (chooseConfigResult != EGL_TRUE) {
         printf("eglChooseConfig failed\n");
-        return 0;

+        return 0;
     }
 #endif
 
-     surface = eglCreateWindowSurface(dpy, configs[0], window, NULL);
-     checkEglError("eglCreateWindowSurface");
-     if (surface == EGL_NO_SURFACE)
-	 {
-         printf("gelCreateWindowSurface failed.\n");
-         return 0;
-	 }
-     EGLint gl2_0Attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
+    surface = eglCreateWindowSurface(dpy, configs[0], window, NULL);
+    checkEglError("eglCreateWindowSurface");
+    if (surface == EGL_NO_SURFACE) {
+        printf("gelCreateWindowSurface failed.\n");
+        return 0;
+    }
+    EGLint gl2_0Attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
 
-     context = eglCreateContext(dpy, configs[0], EGL_NO_CONTEXT, context_attribs);
-     checkEglError("eglCreateContext");
-	 if (context == EGL_NO_CONTEXT)
-     {
+    context = eglCreateContext(dpy, configs[0], EGL_NO_CONTEXT, context_attribs);
+    checkEglError("eglCreateContext");
+    if (context == EGL_NO_CONTEXT) {
         printf("eglCreateContext failed\n");
         return 0;
-	 }
-     eglMakeCurrent(dpy, surface, surface, context);
-     checkEglError("eglMakeCurrent");
-     eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
-     checkEglError("eglQuerySurface");
-     eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
-     checkEglError("eglQuerySurface");
-     GLint dim = w<h ? w : h;
+    }
+    eglMakeCurrent(dpy, surface, surface, context);
+    checkEglError("eglMakeCurrent");
+    eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
+    checkEglError("eglQuerySurface");
+    eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
+    checkEglError("eglQuerySurface");
+    GLint dim = w < h ? w : h;
 
-     fprintf(stderr, "Window dimensions: %d x %d\n", w, h);
+    fprintf(stderr, "Window dimensions: %d x %d\n", w, h);
 
-     printGLString("Version", GL_VERSION);
-     printGLString("Vendor", GL_VENDOR);
-     printGLString("Renderer", GL_RENDERER);
-     printGLString("Extensions", GL_EXTENSIONS);
+    printGLString("Version", GL_VERSION);
+    printGLString("Vendor", GL_VENDOR);
+    printGLString("Renderer", GL_RENDERER);
+    printGLString("Extensions", GL_EXTENSIONS);
 
-     return 0;
+    if(!setupGraphics(w, h)) {
+        fprintf(stderr, "Could not set up graphics.\n");
+        return 0;
+    }
+
+    for (;;) {
+        renderFrame();
+        eglSwapBuffers(dpy, surface);
+    }
+
+    return 0;
 }
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index d5f1c61..db1b5f1 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -29,7 +29,7 @@
     <integer name="def_screen_brightness">102</integer>
     <bool name="def_screen_brightness_automatic_mode">false</bool>
     <fraction name="def_window_animation_scale">100%</fraction>
-    <fraction name="def_window_transition_scale">0%</fraction>
+    <fraction name="def_window_transition_scale">100%</fraction>
     
     <bool name="def_bluetooth_on">false</bool>
     <bool name="def_install_non_market_apps">false</bool>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index f99eb58..c561078 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -71,7 +71,7 @@
     // database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
     // is properly propagated through your change.  Not doing so will result in a loss of user
     // settings.
-    private static final int DATABASE_VERSION = 40;
+    private static final int DATABASE_VERSION = 41;
 
     private Context mContext;
 
@@ -481,6 +481,27 @@
             upgradeVersion = 40;
         }
 
+        if (upgradeVersion == 40) {
+            /*
+             * All animations are now turned on by default!
+             */
+            db.beginTransaction();
+            try {
+                db.execSQL("DELETE FROM system WHERE name='"
+                        + Settings.System.WINDOW_ANIMATION_SCALE + "'");
+                db.execSQL("DELETE FROM system WHERE name='"
+                        + Settings.System.TRANSITION_ANIMATION_SCALE + "'");
+                SQLiteStatement stmt = db.compileStatement("INSERT INTO system(name,value)"
+                        + " VALUES(?,?);");
+                loadDefaultAnimationSettings(stmt);
+                stmt.close();
+                db.setTransactionSuccessful();
+            } finally {
+                db.endTransaction();
+            }
+            upgradeVersion = 41;
+        }
+
         if (upgradeVersion != currentVersion) {
             Log.w(TAG, "Got stuck trying to upgrade from version " + upgradeVersion
                     + ", must wipe the settings provider");
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 8cfd956..fb5e4e6 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -50,19 +50,22 @@
  * List of settings that are backed up are stored in the Settings.java file
  */
 public class SettingsBackupAgent extends BackupHelperAgent {
+    // STOPSHIP: set DEBUG to false
     private static final boolean DEBUG = true;
 
     private static final String KEY_SYSTEM = "system";
     private static final String KEY_SECURE = "secure";
-    private static final String KEY_SYNC = "sync_providers";
     private static final String KEY_LOCALE = "locale";
 
+    // Versioning of the state file.  Increment this version
+    // number any time the set of state items is altered.
+    private static final int STATE_VERSION = 1;
+
     private static final int STATE_SYSTEM = 0;
     private static final int STATE_SECURE = 1;
-    private static final int STATE_SYNC   = 2;
-    private static final int STATE_LOCALE = 3;
-    private static final int STATE_WIFI   = 4;
-    private static final int STATE_SIZE   = 5; // The number of state items
+    private static final int STATE_LOCALE = 2;
+    private static final int STATE_WIFI   = 3;
+    private static final int STATE_SIZE   = 4; // The number of state items
 
     private static String[] sortedSystemKeys = null;
     private static String[] sortedSecureKeys = null;
@@ -101,7 +104,6 @@
 
         byte[] systemSettingsData = getSystemSettings();
         byte[] secureSettingsData = getSecureSettings();
-        byte[] syncProviders = mSettingsHelper.getSyncProviders();
         byte[] locale = mSettingsHelper.getLocaleData();
         byte[] wifiData = getWifiSupplicant(FILE_WIFI_SUPPLICANT);
 
@@ -111,8 +113,6 @@
                 writeIfChanged(stateChecksums[STATE_SYSTEM], KEY_SYSTEM, systemSettingsData, data);
         stateChecksums[STATE_SECURE] =
                 writeIfChanged(stateChecksums[STATE_SECURE], KEY_SECURE, secureSettingsData, data);
-        stateChecksums[STATE_SYNC] =
-                writeIfChanged(stateChecksums[STATE_SYNC], KEY_SYNC, syncProviders, data);
         stateChecksums[STATE_LOCALE] =
                 writeIfChanged(stateChecksums[STATE_LOCALE], KEY_LOCALE, locale, data);
         stateChecksums[STATE_WIFI] =
@@ -143,8 +143,6 @@
                 // retain the previous WIFI state.
                 enableWifi(retainedWifiState == WifiManager.WIFI_STATE_ENABLED ||
                         retainedWifiState == WifiManager.WIFI_STATE_ENABLING);
-            } else if (KEY_SYNC.equals(key)) {
-                mSettingsHelper.setSyncProviders(data);
             } else if (KEY_LOCALE.equals(key)) {
                 byte[] localeData = new byte[size];
                 data.readEntityData(localeData, 0, size);
@@ -160,12 +158,17 @@
 
         DataInputStream dataInput = new DataInputStream(
                 new FileInputStream(oldState.getFileDescriptor()));
-        for (int i = 0; i < STATE_SIZE; i++) {
-            try {
-                stateChecksums[i] = dataInput.readLong();
-            } catch (EOFException eof) {
-                break;
+
+        try {
+            int stateVersion = dataInput.readInt();
+            if (stateVersion == STATE_VERSION) {
+                for (int i = 0; i < STATE_SIZE; i++) {
+                    stateChecksums[i] = dataInput.readLong();
+                }
             }
+        } catch (EOFException eof) {
+            // With the default 0 checksum we'll wind up forcing a backup of
+            // any unhandled data sets, which is appropriate.
         }
         dataInput.close();
         return stateChecksums;
@@ -175,6 +178,8 @@
             throws IOException {
         DataOutputStream dataOutput = new DataOutputStream(
                 new FileOutputStream(newState.getFileDescriptor()));
+
+        dataOutput.writeInt(STATE_VERSION);
         for (int i = 0; i < STATE_SIZE; i++) {
             dataOutput.writeLong(checksums[i]);
         }
@@ -223,6 +228,14 @@
     }
 
     private void restoreSettings(BackupDataInput data, Uri contentUri) {
+        if (DEBUG) Log.i(TAG, "restoreSettings: " + contentUri);
+        String[] whitelist = null;
+        if (contentUri.equals(Settings.Secure.CONTENT_URI)) {
+            whitelist = Settings.Secure.SETTINGS_TO_BACKUP;
+        } else if (contentUri.equals(Settings.System.CONTENT_URI)) {
+            whitelist = Settings.System.SETTINGS_TO_BACKUP;
+        }
+
         ContentValues cv = new ContentValues(2);
         byte[] settings = new byte[data.getDataSize()];
         try {
@@ -244,9 +257,8 @@
             if (!TextUtils.isEmpty(settingName) && !TextUtils.isEmpty(settingValue)) {
                 //Log.i(TAG, "Restore " + settingName + " = " + settingValue);
 
-                // TODO: versioning rather than just an ad hoc blacklist to handle
-                // older varieties of backed-up data
-                if (invalidSavedSetting(contentUri, settingName, settingValue)) {
+                // Only restore settings in our list of known-acceptable data
+                if (invalidSavedSetting(whitelist, settingName)) {
                     continue;
                 }
 
@@ -260,20 +272,23 @@
         }
     }
 
-    private boolean invalidSavedSetting(Uri contentUri, String settingName, String settingValue) {
-        // Even if these settings were stored, don't use them on restore
-        if (contentUri.equals(Settings.Secure.CONTENT_URI)) {
-            if (settingName.equals(Settings.Secure.PREFERRED_NETWORK_MODE)
-                    || settingName.equals(Settings.Secure.PREFERRED_TTY_MODE)
-                    || settingName.equals(Settings.Secure.CDMA_CELL_BROADCAST_SMS)
-                    || settingName.equals(Settings.Secure.PREFERRED_CDMA_SUBSCRIPTION)
-                    || settingName.equals(Settings.Secure.ENHANCED_VOICE_PRIVACY_ENABLED)) {
-                if (DEBUG) Log.v(TAG, "Ignoring restore datum: " + settingName);
-                return true;
+    // Returns 'true' if the given setting is one that we refuse to restore
+    private boolean invalidSavedSetting(String[] knownNames, String candidate) {
+        // no filter? allow everything
+        if (knownNames == null) {
+            return false;
+        }
+
+        // whitelisted setting?  allow it
+        for (String name : knownNames) {
+            if (name.equals(candidate)) {
+                return false;
             }
         }
 
-        return false;
+        // refuse everything else
+        if (DEBUG) Log.v(TAG, "Ignoring restore datum: " + candidate);
+        return true;
     }
 
     private String[] copyAndSort(String[] keys) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index 39084a7..77da8f1 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -116,43 +116,6 @@
         }
     }
 
-    byte[] getSyncProviders() {
-        byte[] sync = new byte[1 + PROVIDERS.length];
-        // TODO: Sync backup needs to be moved to SystemBackupAgent
-        /*
-        try {
-            sync[0] = (byte) (mContentService.getListenForNetworkTickles() ? 1 : 0);
-            for (int i = 0; i < PROVIDERS.length; i++) {
-                sync[i + 1] = (byte) 
-                        (mContentService.getSyncAutomatically(PROVIDERS[i]) ? 1 : 0);
-            }
-        } catch (RemoteException re) {
-            Log.w(TAG, "Unable to backup sync providers");
-            return sync;
-        }
-        */
-        return sync;
-    }
-
-    void setSyncProviders(BackupDataInput backup) {
-        byte[] sync = new byte[backup.getDataSize()];
-
-        try {
-            backup.readEntityData(sync, 0, sync.length);
-            // TODO: Sync backup needs to be moved to SystemBackupAgent
-            /*
-            mContentService.setListenForNetworkTickles(sync[0] == 1);
-            for (int i = 0; i < PROVIDERS.length; i++) {
-                mContentService.setSyncProviderAutomatically(PROVIDERS[i], sync[i + 1] > 0);
-            }
-        } catch (RemoteException re) {
-            Log.w(TAG, "Unable to restore sync providers");
-            */
-        } catch (java.io.IOException ioe) {
-            Log.w(TAG, "Unable to read sync settings");
-        }
-    }
-
     byte[] getLocaleData() {
         Configuration conf = mContext.getResources().getConfiguration();
         final Locale loc = conf.locale;
diff --git a/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java b/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java
index 13b4952..9909905 100644
--- a/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java
+++ b/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java
@@ -17,7 +17,7 @@
 package com.android.server.vpn;
 
 import android.net.vpn.L2tpIpsecProfile;
-import android.security.CertTool;
+import android.security.Credentials;
 
 import java.io.IOException;
 
@@ -30,16 +30,18 @@
     @Override
     protected void connect(String serverIp, String username, String password)
             throws IOException {
+        L2tpIpsecProfile p = getProfile();
         // IPSEC
         DaemonProxy ipsec = startDaemon(IPSEC);
         ipsec.sendCommand(serverIp, L2tpService.L2TP_PORT,
-                getUserkeyPath(), getUserCertPath(), getCaCertPath());
+                Credentials.USER_PRIVATE_KEY + p.getUserCertificate(),
+                Credentials.USER_CERTIFICATE + p.getUserCertificate(),
+                Credentials.CA_CERTIFICATE + p.getCaCertificate());
         ipsec.closeControlSocket();
 
         sleep(2000); // 2 seconds
 
         // L2TP
-        L2tpIpsecProfile p = getProfile();
         MtpdHelper.sendCommand(this, L2tpService.L2TP_DAEMON, serverIp,
                 L2tpService.L2TP_PORT,
                 (p.isSecretEnabled() ? p.getSecretString() : null),
@@ -51,19 +53,4 @@
         stopDaemon(IPSEC);
         stopDaemon(MtpdHelper.MTPD);
     }
-
-    private String getCaCertPath() {
-        return CertTool.getInstance().getCaCertificate(
-                getProfile().getCaCertificate());
-    }
-
-    private String getUserCertPath() {
-        return CertTool.getInstance().getUserCertificate(
-                getProfile().getUserCertificate());
-    }
-
-    private String getUserkeyPath() {
-        return CertTool.getInstance().getUserPrivateKey(
-                getProfile().getUserCertificate());
-    }
 }
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index c6be61d..2fa18bf 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -57,6 +57,7 @@
 import android.backup.IRestoreSession;
 import android.backup.RestoreSet;
 
+import com.android.internal.backup.BackupConstants;
 import com.android.internal.backup.LocalTransport;
 import com.android.internal.backup.IBackupTransport;
 
@@ -101,6 +102,7 @@
     private static final int BACKUP_AGENT_FAILURE_EVENT = 2823;
     private static final int BACKUP_PACKAGE_EVENT = 2824;
     private static final int BACKUP_SUCCESS_EVENT = 2825;
+    private static final int BACKUP_RESET_EVENT = 2826;
 
     private static final int RESTORE_START_EVENT = 2830;
     private static final int RESTORE_TRANSPORT_FAILURE_EVENT = 2831;
@@ -406,6 +408,47 @@
         }
     }
 
+    // Reset all of our bookkeeping, in response to having been told that
+    // the backend data has been wiped [due to idle expiry, for example],
+    // so we must re-upload all saved settings.
+    void resetBackupState(File stateFileDir) {
+        synchronized (mQueueLock) {
+            // Wipe the "what we've ever backed up" tracking
+            try {
+                // close the ever-stored journal...
+                if (mEverStoredStream != null) {
+                    mEverStoredStream.close();
+                }
+                // ... so we can delete it and start over
+                mEverStored.delete();
+                mEverStoredStream = new RandomAccessFile(mEverStored, "rwd");
+            } catch (IOException e) {
+                Log.e(TAG, "Unable to open known-stored file!");
+                mEverStoredStream = null;
+            }
+            mEverStoredApps.clear();
+
+            // Remove all the state files
+            for (File sf : stateFileDir.listFiles()) {
+                sf.delete();
+            }
+
+            // Enqueue a new backup of every participant
+            int N = mBackupParticipants.size();
+            for (int i=0; i<N; i++) {
+                int uid = mBackupParticipants.keyAt(i);
+                HashSet<ApplicationInfo> participants = mBackupParticipants.valueAt(i);
+                for (ApplicationInfo app: participants) {
+                    try {
+                        dataChanged(app.packageName);
+                    } catch (RemoteException e) {
+                        // can't happen; we're in the same process
+                    }
+                }
+            }
+        }
+    }
+
     // Add a transport to our set of available backends
     private void registerTransport(String name, IBackupTransport transport) {
         synchronized (mTransports) {
@@ -869,6 +912,7 @@
 
         @Override
         public void run() {
+            int status = BackupConstants.TRANSPORT_OK;
             long startRealtime = SystemClock.elapsedRealtime();
             if (DEBUG) Log.v(TAG, "Beginning backup of " + mQueue.size() + " targets");
 
@@ -878,43 +922,83 @@
             try {
                 EventLog.writeEvent(BACKUP_START_EVENT, mTransport.transportDirName());
 
+                // If we haven't stored anything yet, we need to do an init operation.
+                if (status == BackupConstants.TRANSPORT_OK && mEverStoredApps.size() == 0) {
+                    status = mTransport.initializeDevice();
+                }
+
                 // The package manager doesn't have a proper <application> etc, but since
                 // it's running here in the system process we can just set up its agent
                 // directly and use a synthetic BackupRequest.  We always run this pass
                 // because it's cheap and this way we guarantee that we don't get out of
                 // step even if we're selecting among various transports at run time.
-                PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
-                        mPackageManager, allAgentPackages());
-                BackupRequest pmRequest = new BackupRequest(new ApplicationInfo(), false);
-                pmRequest.appInfo.packageName = PACKAGE_MANAGER_SENTINEL;
-                processOneBackup(pmRequest,
-                        IBackupAgent.Stub.asInterface(pmAgent.onBind()), mTransport);
-
-                // Now run all the backups in our queue
-                int count = mQueue.size();
-                doQueuedBackups(mTransport);
-
-                // Finally, tear down the transport
-                if (mTransport.finishBackup()) {
-                    int millis = (int) (SystemClock.elapsedRealtime() - startRealtime);
-                    EventLog.writeEvent(BACKUP_SUCCESS_EVENT, count, millis);
-                } else {
-                    EventLog.writeEvent(BACKUP_TRANSPORT_FAILURE_EVENT, "");
-                    Log.e(TAG, "Transport error in finishBackup()");
+                if (status == BackupConstants.TRANSPORT_OK) {
+                    PackageManagerBackupAgent pmAgent = new PackageManagerBackupAgent(
+                            mPackageManager, allAgentPackages());
+                    BackupRequest pmRequest = new BackupRequest(new ApplicationInfo(), false);
+                    pmRequest.appInfo.packageName = PACKAGE_MANAGER_SENTINEL;
+                    status = processOneBackup(pmRequest,
+                            IBackupAgent.Stub.asInterface(pmAgent.onBind()), mTransport);
                 }
 
-                if (!mJournal.delete()) {
-                    Log.e(TAG, "Unable to remove backup journal file " + mJournal);
+                if (status == BackupConstants.TRANSPORT_OK) {
+                    // Now run all the backups in our queue
+                    status = doQueuedBackups(mTransport);
+                }
+
+                if (status == BackupConstants.TRANSPORT_OK) {
+                    // Tell the transport to finish everything it has buffered
+                    status = mTransport.finishBackup();
+                    if (status == BackupConstants.TRANSPORT_OK) {
+                        int millis = (int) (SystemClock.elapsedRealtime() - startRealtime);
+                        EventLog.writeEvent(BACKUP_SUCCESS_EVENT, mQueue.size(), millis);
+                    } else {
+                        EventLog.writeEvent(BACKUP_TRANSPORT_FAILURE_EVENT, "");
+                        Log.e(TAG, "Transport error in finishBackup()");
+                    }
+                }
+
+                if (status == BackupConstants.TRANSPORT_NOT_INITIALIZED) {
+                    // The backend reports that our dataset has been wiped.  We need to
+                    // reset all of our bookkeeping and instead run a new backup pass for
+                    // everything.
+                    EventLog.writeEvent(BACKUP_RESET_EVENT, mTransport.transportDirName());
+                    resetBackupState(mStateDir);
+                    backupNow();
                 }
             } catch (Exception e) {
                 Log.e(TAG, "Error in backup thread", e);
+                status = BackupConstants.TRANSPORT_ERROR;
             } finally {
+                // If things went wrong, we need to re-stage the apps we had expected
+                // to be backing up in this pass.  This journals the package names in
+                // the current active pending-backup file, not in the we are holding
+                // here in mJournal.
+                if (status != BackupConstants.TRANSPORT_OK) {
+                    Log.w(TAG, "Backup pass unsuccessful, restaging");
+                    for (BackupRequest req : mQueue) {
+                        try {
+                            dataChanged(req.appInfo.packageName);
+                        } catch (RemoteException e) {
+                            // can't happen; it's a local call
+                        }
+                    }
+                }
+
+                // Either backup was successful, in which case we of course do not need
+                // this pass's journal any more; or it failed, in which case we just
+                // re-enqueued all of these packages in the current active journal.
+                // Either way, we no longer need this pass's journal.
+                if (!mJournal.delete()) {
+                    Log.e(TAG, "Unable to remove backup journal file " + mJournal);
+                }
+
                 // Only once we're entirely finished do we release the wakelock
                 mWakelock.release();
             }
         }
 
-        private void doQueuedBackups(IBackupTransport transport) {
+        private int doQueuedBackups(IBackupTransport transport) {
             for (BackupRequest request : mQueue) {
                 Log.d(TAG, "starting agent for backup of " + request);
 
@@ -934,26 +1018,27 @@
                 try {
                     agent = bindToAgentSynchronous(request.appInfo, mode);
                     if (agent != null) {
-                        processOneBackup(request, agent, transport);
+                        int result = processOneBackup(request, agent, transport);
+                        if (result != BackupConstants.TRANSPORT_OK) return result;
                     }
-
-                    // unbind even on timeout, just in case
-                    mActivityManager.unbindBackupAgent(request.appInfo);
                 } catch (SecurityException ex) {
                     // Try for the next one.
                     Log.d(TAG, "error in bind/backup", ex);
-                } catch (RemoteException e) {
-                    Log.v(TAG, "bind/backup threw");
-                    e.printStackTrace();
+                } finally {
+                    try {  // unbind even on timeout, just in case
+                        mActivityManager.unbindBackupAgent(request.appInfo);
+                    } catch (RemoteException e) {}
                 }
             }
+
+            return BackupConstants.TRANSPORT_OK;
         }
 
-        void processOneBackup(BackupRequest request, IBackupAgent agent, IBackupTransport transport) {
+        private int processOneBackup(BackupRequest request, IBackupAgent agent,
+                IBackupTransport transport) {
             final String packageName = request.appInfo.packageName;
             if (DEBUG) Log.d(TAG, "processOneBackup doBackup() on " + packageName);
 
-            // !!! TODO: get the state file dir from the transport
             File savedStateName = new File(mStateDir, packageName);
             File backupDataName = new File(mDataDir, packageName + ".data");
             File newStateName = new File(mStateDir, packageName + ".new");
@@ -1003,7 +1088,7 @@
                 EventLog.writeEvent(BACKUP_AGENT_FAILURE_EVENT, packageName, e.toString());
                 backupDataName.delete();
                 newStateName.delete();
-                return;
+                return BackupConstants.TRANSPORT_ERROR;
             } finally {
                 try { if (savedState != null) savedState.close(); } catch (IOException e) {}
                 try { if (backupData != null) backupData.close(); } catch (IOException e) {}
@@ -1012,13 +1097,24 @@
             }
 
             // Now propagate the newly-backed-up data to the transport
+            int result = BackupConstants.TRANSPORT_OK;
             try {
                 int size = (int) backupDataName.length();
                 if (size > 0) {
-                    backupData = ParcelFileDescriptor.open(backupDataName,
-                            ParcelFileDescriptor.MODE_READ_ONLY);
+                    if (result == BackupConstants.TRANSPORT_OK) {
+                        backupData = ParcelFileDescriptor.open(backupDataName,
+                                ParcelFileDescriptor.MODE_READ_ONLY);
+                        result = transport.performBackup(packInfo, backupData);
+                    }
 
-                    if (!transport.performBackup(packInfo, backupData)) throw new Exception();
+                    // TODO - We call finishBackup() for each application backed up, because
+                    // we need to know now whether it succeeded or failed.  Instead, we should
+                    // hold off on finishBackup() until the end, which implies holding off on
+                    // renaming *all* the output state files (see below) until that happens.
+
+                    if (result == BackupConstants.TRANSPORT_OK) {
+                        result = transport.finishBackup();
+                    }
                 } else {
                     if (DEBUG) Log.i(TAG, "no backup data written; not calling transport");
                 }
@@ -1026,16 +1122,22 @@
                 // After successful transport, delete the now-stale data
                 // and juggle the files so that next time we supply the agent
                 // with the new state file it just created.
-                backupDataName.delete();
-                newStateName.renameTo(savedStateName);
-                EventLog.writeEvent(BACKUP_PACKAGE_EVENT, packageName, size);
+                if (result == BackupConstants.TRANSPORT_OK) {
+                    backupDataName.delete();
+                    newStateName.renameTo(savedStateName);
+                    EventLog.writeEvent(BACKUP_PACKAGE_EVENT, packageName, size);
+                } else {
+                    EventLog.writeEvent(BACKUP_TRANSPORT_FAILURE_EVENT, packageName);
+                }
             } catch (Exception e) {
                 Log.e(TAG, "Transport error backing up " + packageName, e);
                 EventLog.writeEvent(BACKUP_TRANSPORT_FAILURE_EVENT, packageName);
-                return;
+                result = BackupConstants.TRANSPORT_ERROR;
             } finally {
                 try { if (backupData != null) backupData.close(); } catch (IOException e) {}
             }
+
+            return result;
         }
     }
 
@@ -1136,7 +1238,7 @@
             // build the set of apps to restore
             try {
                 // TODO: Log this before getAvailableRestoreSets, somehow
-                EventLog.writeEvent(RESTORE_START_EVENT, mTransport.transportDirName());
+                EventLog.writeEvent(RESTORE_START_EVENT, mTransport.transportDirName(), mToken);
 
                 // Get the list of all packages which have backup enabled.
                 // (Include the Package Manager metadata pseudo-package first.)
@@ -1160,7 +1262,8 @@
                     }
                 }
 
-                if (!mTransport.startRestore(mToken, restorePackages.toArray(new PackageInfo[0]))) {
+                if (mTransport.startRestore(mToken, restorePackages.toArray(new PackageInfo[0])) !=
+                        BackupConstants.TRANSPORT_OK) {
                     Log.e(TAG, "Error starting restore operation");
                     EventLog.writeEvent(RESTORE_TRANSPORT_FAILURE_EVENT);
                     return;
@@ -1360,7 +1463,7 @@
                             ParcelFileDescriptor.MODE_CREATE |
                             ParcelFileDescriptor.MODE_TRUNCATE);
 
-                if (!mTransport.getRestoreData(backupData)) {
+                if (mTransport.getRestoreData(backupData) != BackupConstants.TRANSPORT_OK) {
                     Log.e(TAG, "Error getting restore data for " + packageName);
                     EventLog.writeEvent(RESTORE_TRANSPORT_FAILURE_EVENT);
                     return;
@@ -1379,7 +1482,21 @@
                 agent.doRestore(backupData, appVersionCode, newState);
 
                 // if everything went okay, remember the recorded state now
-                newStateName.renameTo(savedStateName);
+                //
+                // !!! TODO: the restored data should be migrated on the server
+                // side into the current dataset.  In that case the new state file
+                // we just created would reflect the data already extant in the
+                // backend, so there'd be nothing more to do.  Until that happens,
+                // however, we need to make sure that we record the data to the
+                // current backend dataset.  (Yes, this means shipping the data over
+                // the wire in both directions.  That's bad, but consistency comes
+                // first, then efficiency.)  Once we introduce server-side data
+                // migration to the newly-restored device's dataset, we will change
+                // the following from a discard of the newly-written state to the
+                // "correct" operation of renaming into the canonical state blob.
+                newStateName.delete();                      // TODO: remove; see above comment
+                //newStateName.renameTo(savedStateName);    // TODO: replace with this
+
                 int size = (int) backupDataName.length();
                 EventLog.writeEvent(RESTORE_PACKAGE_EVENT, packageName, size);
             } catch (Exception e) {
@@ -1417,11 +1534,13 @@
                 stateFile.delete();
 
                 // Tell the transport to remove all the persistent storage for the app
+                // STOPSHIP TODO - need to handle failures
                 mTransport.clearBackupData(mPackage);
             } catch (RemoteException e) {
                 // can't happen; the transport is local
             } finally {
                 try {
+                    // STOPSHIP TODO - need to handle failures
                     mTransport.finishBackup();
                 } catch (RemoteException e) {
                     // can't happen; the transport is local
@@ -1562,7 +1681,6 @@
         if (DEBUG) Log.v(TAG, "Scheduling immediate backup pass");
         synchronized (mQueueLock) {
             try {
-                if (DEBUG) Log.v(TAG, "sending immediate backup broadcast");
                 mRunBackupIntent.send();
             } catch (PendingIntent.CanceledException e) {
                 // should never happen
diff --git a/services/java/com/android/server/BatteryService.java b/services/java/com/android/server/BatteryService.java
index 26fee89..d78d886 100644
--- a/services/java/com/android/server/BatteryService.java
+++ b/services/java/com/android/server/BatteryService.java
@@ -26,7 +26,6 @@
 import android.content.pm.PackageManager;
 import android.os.BatteryManager;
 import android.os.Binder;
-import android.os.Debug;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -333,16 +332,16 @@
         
         int icon = getIcon(mBatteryLevel);
 
-        intent.putExtra("status", mBatteryStatus);
-        intent.putExtra("health", mBatteryHealth);
-        intent.putExtra("present", mBatteryPresent);
-        intent.putExtra("level", mBatteryLevel);
-        intent.putExtra("scale", BATTERY_SCALE);
-        intent.putExtra("icon-small", icon);
-        intent.putExtra("plugged", mPlugType);
-        intent.putExtra("voltage", mBatteryVoltage);
-        intent.putExtra("temperature", mBatteryTemperature);
-        intent.putExtra("technology", mBatteryTechnology);
+        intent.putExtra(BatteryManager.EXTRA_STATUS, mBatteryStatus);
+        intent.putExtra(BatteryManager.EXTRA_HEALTH, mBatteryHealth);
+        intent.putExtra(BatteryManager.EXTRA_PRESENT, mBatteryPresent);
+        intent.putExtra(BatteryManager.EXTRA_LEVEL, mBatteryLevel);
+        intent.putExtra(BatteryManager.EXTRA_SCALE, BATTERY_SCALE);
+        intent.putExtra(BatteryManager.EXTRA_ICON_SMALL, icon);
+        intent.putExtra(BatteryManager.EXTRA_PLUGGED, mPlugType);
+        intent.putExtra(BatteryManager.EXTRA_VOLTAGE, mBatteryVoltage);
+        intent.putExtra(BatteryManager.EXTRA_TEMPERATURE, mBatteryTemperature);
+        intent.putExtra(BatteryManager.EXTRA_TECHNOLOGY, mBatteryTechnology);
 
         if (false) {
             Log.d(TAG, "updateBattery level:" + mBatteryLevel +
diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java
index 60195b9..a70134d3 100644
--- a/services/java/com/android/server/DockObserver.java
+++ b/services/java/com/android/server/DockObserver.java
@@ -16,7 +16,9 @@
 
 package com.android.server;
 
+import android.app.Activity;
 import android.content.ActivityNotFoundException;
+import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Handler;
@@ -44,6 +46,44 @@
     private final Context mContext;
 
     private PowerManagerService mPowerManager;
+    
+    // The broadcast receiver which receives the result of the ordered broadcast sent when
+    // the dock state changes. The original ordered broadcast is sent with an initial result
+    // code of RESULT_OK. If any of the registered broadcast receivers changes this value, e.g.,
+    // to RESULT_CANCELED, then the intent to start a dock app will not be sent.
+    private final BroadcastReceiver mResultReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (getResultCode() != Activity.RESULT_OK) {
+                return;
+            }
+            
+            // Launch a dock activity
+            String category;
+            switch (mDockState) {
+                case Intent.EXTRA_DOCK_STATE_CAR:
+                    category = Intent.CATEGORY_CAR_DOCK;
+                    break;
+                case Intent.EXTRA_DOCK_STATE_DESK:
+                    category = Intent.CATEGORY_DESK_DOCK;
+                    break;
+                default:
+                    category = null;
+                    break;
+            }
+            if (category != null) {
+                intent = new Intent(Intent.ACTION_MAIN);
+                intent.addCategory(category);
+                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                        | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+                try {
+                    mContext.startActivity(intent);
+                } catch (ActivityNotFoundException e) {
+                    Log.w(TAG, e.getCause());
+                }
+            }
+        }
+    };
 
     public DockObserver(Context context, PowerManagerService pm) {
         mContext = context;
@@ -111,31 +151,15 @@
                 mPowerManager.userActivityWithForce(SystemClock.uptimeMillis(), false, true);
                 Intent intent = new Intent(Intent.ACTION_DOCK_EVENT);
                 intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState);
-                mContext.sendStickyBroadcast(intent);
-
-                // Launch a dock activity
-                String category;
-                switch (mDockState) {
-                    case Intent.EXTRA_DOCK_STATE_CAR:
-                        category = Intent.CATEGORY_CAR_DOCK;
-                        break;
-                    case Intent.EXTRA_DOCK_STATE_DESK:
-                        category = Intent.CATEGORY_DESK_DOCK;
-                        break;
-                    default:
-                        category = null;
-                        break;
-                }
-                if (category != null) {
-                    intent = new Intent(Intent.ACTION_MAIN);
-                    intent.addCategory(category);
-                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-                    try {
-                        mContext.startActivity(intent);
-                    } catch (ActivityNotFoundException e) {
-                        Log.w(TAG, e.getCause());
-                    }
-                }
+                
+                // Send the ordered broadcast; the result receiver will receive after all
+                // broadcasts have been sent. If any broadcast receiver changes the result
+                // code from the initial value of RESULT_OK, then the result receiver will
+                // not launch the corresponding dock application. This gives apps a chance
+                // to override the behavior and stay in their app even when the device is
+                // placed into a dock.
+                mContext.sendStickyOrderedBroadcast(
+                        intent, mResultReceiver, null, Activity.RESULT_OK, null, null);
             }
         }
     };
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 84250bc..b2e3a8c 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -304,10 +304,7 @@
                     // temporarily set mUserActivityAllowed to true so this will work
                     // even when the keyguard is on.
                     synchronized (mLocks) {
-                        boolean savedActivityAllowed = mUserActivityAllowed;
-                        mUserActivityAllowed = true;
-                        userActivity(SystemClock.uptimeMillis(), false);
-                        mUserActivityAllowed = savedActivityAllowed;
+                        forceUserActivityLocked();
                     }
                 }
             }
@@ -1714,6 +1711,13 @@
         }
     }
 
+    private void forceUserActivityLocked() {
+        boolean savedActivityAllowed = mUserActivityAllowed;
+        mUserActivityAllowed = true;
+        userActivity(SystemClock.uptimeMillis(), false);
+        mUserActivityAllowed = savedActivityAllowed;
+    }
+
     public void userActivityWithForce(long time, boolean noChangeLights, boolean force) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
         userActivity(time, noChangeLights, OTHER_EVENT, force);
@@ -1858,9 +1862,10 @@
                 Log.d(TAG, "setKeyboardVisibility: " + visible);
             }
             mKeyboardVisible = visible;
-            // don't signal user activity when closing keyboard if the screen is off.
-            // otherwise, we want to make sure the backlights are adjusted.
-            if (visible || (mPowerState & SCREEN_ON_BIT) != 0) {
+            // don't signal user activity if the screen is off; other code
+            // will take care of turning on due to a true change to the lid
+            // switch and synchronized with the lock screen.
+            if ((mPowerState & SCREEN_ON_BIT) != 0) {
                 userActivity(SystemClock.uptimeMillis(), false, BUTTON_EVENT, true);
             }
         }
@@ -2114,14 +2119,21 @@
             Log.d(TAG, "disableProximityLockLocked");
         }
         mSensorManager.unregisterListener(this);
-        mProximitySensorActive = false;
+        synchronized (mLocks) {
+            if (mProximitySensorActive) {
+                mProximitySensorActive = false;
+                forceUserActivityLocked();
+            }
+        }
     }
 
     public void onSensorChanged(SensorEvent event) {
         long milliseconds = event.timestamp / 1000000;
         synchronized (mLocks) {
             float distance = event.values[0];
-            if (distance >= 0.0 && distance < PROXIMITY_THRESHOLD) {
+            // compare against getMaximumRange to support sensors that only return 0 or 1
+            if (distance >= 0.0 && distance < PROXIMITY_THRESHOLD &&
+                    distance < mProximitySensor.getMaximumRange()) {
                 if (mSpew) {
                     Log.d(TAG, "onSensorChanged: proximity active, distance: " + distance);
                 }
@@ -2135,10 +2147,7 @@
                     Log.d(TAG, "onSensorChanged: proximity inactive, distance: " + distance);
                 }
                 mProximitySensorActive = false;
-                boolean savedActivityAllowed = mUserActivityAllowed;
-                mUserActivityAllowed = true;
-                userActivity(milliseconds, false);
-                mUserActivityAllowed = savedActivityAllowed;
+                forceUserActivityLocked();
             }
         }
     }
diff --git a/services/java/com/android/server/ProcessStats.java b/services/java/com/android/server/ProcessStats.java
index af80e20..ac3b723 100644
--- a/services/java/com/android/server/ProcessStats.java
+++ b/services/java/com/android/server/ProcessStats.java
@@ -30,6 +30,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.StringTokenizer;
 
 public class ProcessStats {
     private static final String TAG = "ProcessStats";
@@ -138,7 +139,22 @@
     private boolean mFirst = true;
 
     private byte[] mBuffer = new byte[256];
-     
+
+    /**
+     * The time in microseconds that the CPU has been running at each speed.
+     */
+    private long[] mCpuSpeedTimes;
+
+    /**
+     * The relative time in microseconds that the CPU has been running at each speed.
+     */
+    private long[] mRelCpuSpeedTimes;
+
+    /**
+     * The different speeds that the CPU can be running at.
+     */
+    private long[] mCpuSpeeds;
+
     public static class Stats {
         public final int pid;
         final String statFile;
@@ -460,6 +476,70 @@
         return 0;
     }
 
+    /**
+     * Returns the times spent at each CPU speed, since the last call to this method. If this
+     * is the first time, it will return 1 for each value.
+     * @return relative times spent at different speed steps.
+     */
+    public long[] getLastCpuSpeedTimes() {
+        if (mCpuSpeedTimes == null) {
+            mCpuSpeedTimes = getCpuSpeedTimes(null);
+            mRelCpuSpeedTimes = new long[mCpuSpeedTimes.length];
+            for (int i = 0; i < mCpuSpeedTimes.length; i++) {
+                mRelCpuSpeedTimes[i] = 1; // Initialize
+            }
+        } else {
+            getCpuSpeedTimes(mRelCpuSpeedTimes);
+            for (int i = 0; i < mCpuSpeedTimes.length; i++) {
+                long temp = mRelCpuSpeedTimes[i];
+                mRelCpuSpeedTimes[i] -= mCpuSpeedTimes[i];
+                mCpuSpeedTimes[i] = temp;
+            }
+        }
+        return mRelCpuSpeedTimes;
+    }
+
+    private long[] getCpuSpeedTimes(long[] out) {
+        long[] tempTimes = out;
+        long[] tempSpeeds = mCpuSpeeds;
+        final int MAX_SPEEDS = 20;
+        if (out == null) {
+            tempTimes = new long[MAX_SPEEDS]; // Hopefully no more than that
+            tempSpeeds = new long[MAX_SPEEDS];
+        }
+        int speed = 0;
+        String file = readFile("/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state", '\0');
+        // Note: file may be null on kernels without cpufreq (i.e. the emulator's)
+        if (file != null) {
+            StringTokenizer st = new StringTokenizer(file, "\n ");
+            while (st.hasMoreElements()) {
+                String token = st.nextToken();
+                try {
+                    long val = Long.parseLong(token);
+                    tempSpeeds[speed] = val;
+                    token = st.nextToken();
+                    val = Long.parseLong(token);
+                    tempTimes[speed] = val;
+                    speed++;
+                    if (speed == MAX_SPEEDS) break; // No more
+                    if (localLOGV && out == null) {
+                        Log.v(TAG, "First time : Speed/Time = " + tempSpeeds[speed - 1]
+                              + "\t" + tempTimes[speed - 1]);
+                    }
+                } catch (NumberFormatException nfe) {
+                    Log.i(TAG, "Unable to parse time_in_state");
+                }
+            }
+        }
+        if (out == null) {
+            out = new long[speed];
+            mCpuSpeeds = new long[speed];
+            System.arraycopy(tempSpeeds, 0, mCpuSpeeds, 0, speed);
+            System.arraycopy(tempTimes, 0, out, 0, speed);
+        }
+        return out;
+    }
+
     final public int getLastUserTime() {
         return mRelUserTime;
     }
diff --git a/services/java/com/android/server/SystemBackupAgent.java b/services/java/com/android/server/SystemBackupAgent.java
index 17d0f1d..8903ebd 100644
--- a/services/java/com/android/server/SystemBackupAgent.java
+++ b/services/java/com/android/server/SystemBackupAgent.java
@@ -32,23 +32,33 @@
 import java.io.IOException;
 
 /**
- * Backup agent for various system-managed data
+ * Backup agent for various system-managed data, currently just the system wallpaper
  */
 public class SystemBackupAgent extends BackupHelperAgent {
     private static final String TAG = "SystemBackupAgent";
 
+    // These paths must match what the WallpaperManagerService uses
     private static final String WALLPAPER_IMAGE = "/data/data/com.android.settings/files/wallpaper";
     private static final String WALLPAPER_INFO = "/data/system/wallpaper_info.xml";
 
     @Override
-    public void onCreate() {
+    public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
+            ParcelFileDescriptor newState) throws IOException {
+        // We only back up the data under the current "wallpaper" schema with metadata
         addHelper("wallpaper", new AbsoluteFileBackupHelper(SystemBackupAgent.this,
                 new String[] { WALLPAPER_IMAGE, WALLPAPER_INFO }));
+        super.onBackup(oldState, data, newState);
     }
 
     @Override
     public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)
             throws IOException {
+        // On restore, we also support a previous data schema "system_files"
+        addHelper("wallpaper", new AbsoluteFileBackupHelper(SystemBackupAgent.this,
+                new String[] { WALLPAPER_IMAGE, WALLPAPER_INFO }));
+        addHelper("system_files", new AbsoluteFileBackupHelper(SystemBackupAgent.this,
+                new String[] { WALLPAPER_IMAGE }));
+
         boolean success = false;
         try {
             super.onRestore(data, appVersionCode, newState);
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 63bef54..cc1b697 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -295,7 +295,11 @@
         if (mWifiHandler == null) return false;
 
         synchronized (mWifiHandler) {
+            // caller may not have WAKE_LOCK permission - it's not required here
+            long ident = Binder.clearCallingIdentity();
             sWakeLock.acquire();
+            Binder.restoreCallingIdentity(ident);
+
             mLastEnableUid = Binder.getCallingUid();
             // set a flag if the user is enabling Wifi while in airplane mode
             mAirplaneModeOverwridden = (enable && isAirplaneModeOn() && isAirplaneToggleable());
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 0cd5949..38d2304 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -143,6 +143,7 @@
     static final boolean DEBUG_REORDER = false;
     static final boolean DEBUG_WALLPAPER = false;
     static final boolean SHOW_TRANSACTIONS = false;
+    static final boolean HIDE_STACK_CRAWLS = true;
     static final boolean MEASURE_LATENCY = false;
     static private LatencyTimer lt;
 
@@ -372,7 +373,7 @@
     // perform or TRANSIT_NONE if we are not waiting.  If we are waiting,
     // mOpeningApps and mClosingApps are the lists of tokens that will be
     // made visible or hidden at the next transition.
-    int mNextAppTransition = WindowManagerPolicy.TRANSIT_NONE;
+    int mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
     boolean mAppTransitionReady = false;
     boolean mAppTransitionRunning = false;
     boolean mAppTransitionTimeout = false;
@@ -622,7 +623,7 @@
 
     private void placeWindowAfter(Object pos, WindowState window) {
         final int i = mWindows.indexOf(pos);
-        if (localLOGV || DEBUG_FOCUS) Log.v(
+        if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT) Log.v(
             TAG, "Adding window " + window + " at "
             + (i+1) + " of " + mWindows.size() + " (after " + pos + ")");
         mWindows.add(i+1, window);
@@ -630,7 +631,7 @@
 
     private void placeWindowBefore(Object pos, WindowState window) {
         final int i = mWindows.indexOf(pos);
-        if (localLOGV || DEBUG_FOCUS) Log.v(
+        if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT) Log.v(
             TAG, "Adding window " + window + " at "
             + i + " of " + mWindows.size() + " (before " + pos + ")");
         mWindows.add(i, window);
@@ -687,6 +688,9 @@
                                 //apptoken note that the window could be a floating window
                                 //that was created later or a window at the top of the list of
                                 //windows associated with this token.
+                                if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT) Log.v(
+                                        TAG, "Adding window " + win + " at "
+                                        + (newIdx+1) + " of " + N);
                                 localmWindows.add(newIdx+1, win);
                             }
                         }
@@ -766,9 +770,9 @@
                                     break;
                                 }
                             }
-                            if (localLOGV || DEBUG_FOCUS) Log.v(
-                                TAG, "Adding window " + win + " at "
-                                + i + " of " + N);
+                            if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT) Log.v(
+                                    TAG, "Adding window " + win + " at "
+                                    + i + " of " + N);
                             localmWindows.add(i, win);
                         }
                     }
@@ -783,9 +787,9 @@
                     }
                 }
                 if (i < 0) i = 0;
-                if (localLOGV || DEBUG_FOCUS) Log.v(
-                    TAG, "Adding window " + win + " at "
-                    + i + " of " + N);
+                if (DEBUG_FOCUS || DEBUG_WINDOW_MOVEMENT) Log.v(
+                        TAG, "Adding window " + win + " at "
+                        + i + " of " + N);
                 localmWindows.add(i, win);
             }
             if (addToToken) {
@@ -932,7 +936,7 @@
                             + " layer=" + highestTarget.mAnimLayer
                             + " new layer=" + w.mAnimLayer);
 
-                    if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
+                    if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
                         // If we are currently setting up for an animation,
                         // hold everything until we can find out what will happen.
                         mInputMethodTargetWaitingAnim = true;
@@ -955,7 +959,7 @@
         if (w != null) {
             if (willMove) {
                 RuntimeException e = new RuntimeException();
-                e.fillInStackTrace();
+                if (!HIDE_STACK_CRAWLS) e.fillInStackTrace();
                 if (DEBUG_INPUT_METHOD) Log.w(TAG, "Moving IM target from "
                         + mInputMethodTarget + " to " + w, e);
                 mInputMethodTarget = w;
@@ -969,7 +973,7 @@
         }
         if (willMove) {
             RuntimeException e = new RuntimeException();
-            e.fillInStackTrace();
+            if (!HIDE_STACK_CRAWLS) e.fillInStackTrace();
             if (DEBUG_INPUT_METHOD) Log.w(TAG, "Moving IM target from "
                     + mInputMethodTarget + " to null", e);
             mInputMethodTarget = null;
@@ -982,6 +986,8 @@
         int pos = findDesiredInputMethodWindowIndexLocked(true);
         if (pos >= 0) {
             win.mTargetAppToken = mInputMethodTarget.mAppToken;
+            if (DEBUG_WINDOW_MOVEMENT) Log.v(
+                    TAG, "Adding input method window " + win + " at " + pos);
             mWindows.add(pos, win);
             moveInputMethodDialogsLocked(pos+1);
             return;
@@ -1022,6 +1028,7 @@
         int wpos = mWindows.indexOf(win);
         if (wpos >= 0) {
             if (wpos < interestingPos) interestingPos--;
+            if (DEBUG_WINDOW_MOVEMENT) Log.v(TAG, "Temp removing at " + wpos + ": " + win);
             mWindows.remove(wpos);
             int NC = win.mChildWindows.size();
             while (NC > 0) {
@@ -1030,6 +1037,8 @@
                 int cpos = mWindows.indexOf(cw);
                 if (cpos >= 0) {
                     if (cpos < interestingPos) interestingPos--;
+                    if (DEBUG_WINDOW_MOVEMENT) Log.v(TAG, "Temp removing child at "
+                            + cpos + ": " + cw);
                     mWindows.remove(cpos);
                 }
             }
@@ -1044,6 +1053,8 @@
         // this case should be rare, so it shouldn't be that big a deal.
         int wpos = mWindows.indexOf(win);
         if (wpos >= 0) {
+            if (DEBUG_WINDOW_MOVEMENT) Log.v(TAG, "ReAdd removing from " + wpos
+                    + ": " + win);
             mWindows.remove(wpos);
             reAddWindowLocked(wpos, win);
         }
@@ -1270,7 +1281,7 @@
             }
         }
 
-        if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
+        if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
             // If we are currently waiting for an app transition, and either
             // the current target or the next target are involved with it,
             // then hold off on doing anything with the wallpaper.
@@ -1472,6 +1483,8 @@
                 // not in the list.
                 int oldIndex = localmWindows.indexOf(wallpaper);
                 if (oldIndex >= 0) {
+                    if (DEBUG_WINDOW_MOVEMENT) Log.v(TAG, "Wallpaper removing at "
+                            + oldIndex + ": " + wallpaper);
                     localmWindows.remove(oldIndex);
                     if (oldIndex < foundI) {
                         foundI--;
@@ -1479,7 +1492,8 @@
                 }
                 
                 // Now stick it in.
-                if (DEBUG_WALLPAPER) Log.v(TAG, "Moving wallpaper " + wallpaper
+                if (DEBUG_WALLPAPER || DEBUG_WINDOW_MOVEMENT) Log.v(TAG,
+                        "Moving wallpaper " + wallpaper
                         + " from " + oldIndex + " to " + foundI);
                 
                 localmWindows.add(foundI, wallpaper);
@@ -2003,6 +2017,7 @@
 
         mWindowMap.remove(win.mClient.asBinder());
         mWindows.remove(win);
+        if (DEBUG_WINDOW_MOVEMENT) Log.v(TAG, "Final remove of window: " + win);
 
         if (mInputMethodWindow == win) {
             mInputMethodWindow = null;
@@ -2447,7 +2462,7 @@
             if (a != null) {
                 if (DEBUG_ANIM) {
                     RuntimeException e = new RuntimeException();
-                    e.fillInStackTrace();
+                    if (!HIDE_STACK_CRAWLS) e.fillInStackTrace();
                     Log.v(TAG, "Loaded animation " + a + " for " + win, e);
                 }
                 win.setAnimation(a);
@@ -2542,7 +2557,7 @@
                                 : com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation;
                         break;
                 }
-                a = loadAnimation(lp, animAttr);
+                a = animAttr != 0 ? loadAnimation(lp, animAttr) : null;
                 if (DEBUG_ANIM) Log.v(TAG, "applyAnimation: wtoken=" + wtoken
                         + " anim=" + a
                         + " animAttr=0x" + Integer.toHexString(animAttr)
@@ -2551,7 +2566,7 @@
             if (a != null) {
                 if (DEBUG_ANIM) {
                     RuntimeException e = new RuntimeException();
-                    e.fillInStackTrace();
+                    if (!HIDE_STACK_CRAWLS) e.fillInStackTrace();
                     Log.v(TAG, "Loaded animation " + a + " for " + wtoken, e);
                 }
                 wtoken.setAnimation(a);
@@ -2990,7 +3005,8 @@
                     TAG, "Prepare app transition: transit=" + transit
                     + " mNextAppTransition=" + mNextAppTransition);
             if (!mDisplayFrozen) {
-                if (mNextAppTransition == WindowManagerPolicy.TRANSIT_NONE) {
+                if (mNextAppTransition == WindowManagerPolicy.TRANSIT_UNSET
+                        || mNextAppTransition == WindowManagerPolicy.TRANSIT_NONE) {
                     mNextAppTransition = transit;
                 } else if (transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
                         && mNextAppTransition == WindowManagerPolicy.TRANSIT_TASK_CLOSE) {
@@ -3025,7 +3041,7 @@
         synchronized(mWindowMap) {
             if (DEBUG_APP_TRANSITIONS) Log.v(
                     TAG, "Execute app transition: mNextAppTransition=" + mNextAppTransition);
-            if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
+            if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
                 mAppTransitionReady = true;
                 final long origId = Binder.clearCallingIdentity();
                 performLayoutAndPlaceSurfacesLocked();
@@ -3092,6 +3108,8 @@
                         startingWindow.mToken = wtoken;
                         startingWindow.mRootToken = wtoken;
                         startingWindow.mAppToken = wtoken;
+                        if (DEBUG_WINDOW_MOVEMENT) Log.v(TAG,
+                                "Removing starting window: " + startingWindow);
                         mWindows.remove(startingWindow);
                         ttoken.windows.remove(startingWindow);
                         ttoken.allAppWindows.remove(startingWindow);
@@ -3228,7 +3246,7 @@
 
             boolean runningAppAnimation = false;
 
-            if (transit != WindowManagerPolicy.TRANSIT_NONE) {
+            if (transit != WindowManagerPolicy.TRANSIT_UNSET) {
                 if (wtoken.animation == sDummyAnimation) {
                     wtoken.animation = null;
                 }
@@ -3319,7 +3337,7 @@
 
             if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) {
                 RuntimeException e = new RuntimeException();
-                e.fillInStackTrace();
+                if (!HIDE_STACK_CRAWLS) e.fillInStackTrace();
                 Log.v(TAG, "setAppVisibility(" + token + ", " + visible
                         + "): mNextAppTransition=" + mNextAppTransition
                         + " hidden=" + wtoken.hidden
@@ -3328,7 +3346,7 @@
 
             // If we are preparing an app transition, then delay changing
             // the visibility of this token until we execute that transition.
-            if (!mDisplayFrozen && mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
+            if (!mDisplayFrozen && mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
                 // Already in requested state, don't do anything more.
                 if (wtoken.hiddenRequested != visible) {
                     return;
@@ -3367,7 +3385,7 @@
             }
 
             final long origId = Binder.clearCallingIdentity();
-            setTokenVisibilityLocked(wtoken, null, visible, WindowManagerPolicy.TRANSIT_NONE, true);
+            setTokenVisibilityLocked(wtoken, null, visible, WindowManagerPolicy.TRANSIT_UNSET, true);
             wtoken.updateReportedVisibilityLocked();
             Binder.restoreCallingIdentity(origId);
         }
@@ -3411,7 +3429,7 @@
             int configChanges) {
         if (DEBUG_ORIENTATION) {
             RuntimeException e = new RuntimeException();
-            e.fillInStackTrace();
+            if (!HIDE_STACK_CRAWLS) e.fillInStackTrace();
             Log.i(TAG, "Set freezing of " + wtoken.appToken
                     + ": hidden=" + wtoken.hidden + " freezing="
                     + wtoken.freezingScreen, e);
@@ -3493,13 +3511,13 @@
             mTokenList.remove(basewtoken);
             if (basewtoken != null && (wtoken=basewtoken.appWindowToken) != null) {
                 if (DEBUG_APP_TRANSITIONS) Log.v(TAG, "Removing app token: " + wtoken);
-                delayed = setTokenVisibilityLocked(wtoken, null, false, WindowManagerPolicy.TRANSIT_NONE, true);
+                delayed = setTokenVisibilityLocked(wtoken, null, false, WindowManagerPolicy.TRANSIT_UNSET, true);
                 wtoken.inPendingTransaction = false;
                 mOpeningApps.remove(wtoken);
                 wtoken.waitingToShow = false;
                 if (mClosingApps.contains(wtoken)) {
                     delayed = true;
-                } else if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
+                } else if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
                     mClosingApps.add(wtoken);
                     wtoken.waitingToHide = true;
                     delayed = true;
@@ -3511,6 +3529,12 @@
                 if (delayed) {
                     // set the token aside because it has an active animation to be finished
                     mExitingAppTokens.add(wtoken);
+                } else {
+                    // Make sure there is no animation running on this token,
+                    // so any windows associated with it will be removed as
+                    // soon as their animations are complete
+                    wtoken.animation = null;
+                    wtoken.animating = false;
                 }
                 mAppTokens.remove(wtoken);
                 wtoken.removed = true;
@@ -3546,7 +3570,7 @@
         final int NW = token.windows.size();
         for (int i=0; i<NW; i++) {
             WindowState win = token.windows.get(i);
-            if (DEBUG_WINDOW_MOVEMENT) Log.v(TAG, "Tmp removing window " + win);
+            if (DEBUG_WINDOW_MOVEMENT) Log.v(TAG, "Tmp removing app window " + win);
             mWindows.remove(win);
             int j = win.mChildWindows.size();
             while (j > 0) {
@@ -3781,7 +3805,7 @@
                 AppWindowToken wt = findAppWindowToken(tokens.get(i));
                 if (wt != null) {
                     mAppTokens.add(wt);
-                    if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
+                    if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
                         mToTopApps.remove(wt);
                         mToBottomApps.remove(wt);
                         mToTopApps.add(wt);
@@ -3791,7 +3815,7 @@
                 }
             }
             
-            if (mNextAppTransition == WindowManagerPolicy.TRANSIT_NONE) {
+            if (mNextAppTransition == WindowManagerPolicy.TRANSIT_UNSET) {
                 moveAppWindowsLocked(tokens, mAppTokens.size());
             }
         }
@@ -3813,7 +3837,7 @@
                 AppWindowToken wt = findAppWindowToken(tokens.get(i));
                 if (wt != null) {
                     mAppTokens.add(pos, wt);
-                    if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
+                    if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
                         mToTopApps.remove(wt);
                         mToBottomApps.remove(wt);
                         mToBottomApps.add(i, wt);
@@ -3824,7 +3848,7 @@
                 }
             }
             
-            if (mNextAppTransition == WindowManagerPolicy.TRANSIT_NONE) {
+            if (mNextAppTransition == WindowManagerPolicy.TRANSIT_UNSET) {
                 moveAppWindowsLocked(tokens, 0);
             }
         }
@@ -6998,13 +7022,13 @@
                 try {
                     if (DEBUG_VISIBILITY) {
                         RuntimeException e = new RuntimeException();
-                        e.fillInStackTrace();
+                        if (!HIDE_STACK_CRAWLS) e.fillInStackTrace();
                         Log.w(TAG, "Window " + this + " destroying surface "
                                 + mSurface + ", session " + mSession, e);
                     }
                     if (SHOW_TRANSACTIONS) {
                         RuntimeException ex = new RuntimeException();
-                        ex.fillInStackTrace();
+                        if (!HIDE_STACK_CRAWLS) ex.fillInStackTrace();
                         Log.i(TAG, "  SURFACE " + mSurface + ": DESTROY ("
                                 + mAttrs.getTitle() + ")", ex);
                     }
@@ -7059,7 +7083,7 @@
         boolean performShowLocked() {
             if (DEBUG_VISIBILITY) {
                 RuntimeException e = new RuntimeException();
-                e.fillInStackTrace();
+                if (!HIDE_STACK_CRAWLS) e.fillInStackTrace();
                 Log.v(TAG, "performShow on " + this
                         + ": readyToShow=" + mReadyToShow + " readyForDisplay=" + isReadyForDisplay()
                         + " starting=" + (mAttrs.type == TYPE_APPLICATION_STARTING), e);
@@ -7319,10 +7343,11 @@
                 final Matrix tmpMatrix = mTmpMatrix;
 
                 // Compute the desired transformation.
-                tmpMatrix.setTranslate(frame.left, frame.top);
+                tmpMatrix.setTranslate(0, 0);
                 if (selfTransformation) {
                     tmpMatrix.postConcat(mTransformation.getMatrix());
                 }
+                tmpMatrix.postTranslate(frame.left, frame.top);
                 if (attachedTransformation != null) {
                     tmpMatrix.postConcat(attachedTransformation.getMatrix());
                 }
@@ -7458,7 +7483,7 @@
          */
         boolean isReadyForDisplay() {
             if (mRootToken.waitingToShow &&
-                    mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
+                    mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
                 return false;
             }
             final AppWindowToken atoken = mAppToken;
@@ -8529,7 +8554,7 @@
 
                 case APP_TRANSITION_TIMEOUT: {
                     synchronized (mWindowMap) {
-                        if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
+                        if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
                             if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
                                     "*** APP TRANSITION TIMEOUT");
                             mAppTransitionReady = true;
@@ -8660,6 +8685,7 @@
     final void rebuildAppWindowListLocked() {
         int NW = mWindows.size();
         int i;
+        int numRemoved = 0;
         
         // First remove all existing app windows.
         i=0;
@@ -8669,6 +8695,7 @@
                 if (DEBUG_WINDOW_MOVEMENT) Log.v(TAG,
                         "Rebuild removing window: " + win);
                 NW--;
+                numRemoved++;
                 continue;
             }
             i++;
@@ -8689,6 +8716,11 @@
         for (int j=0; j<NT; j++) {
             i = reAddAppWindowsLocked(i, mAppTokens.get(j));
         }
+        
+        if (i != numRemoved) {
+            Log.w(TAG, "Rebuild removed " + numRemoved
+                    + " windows but added " + i);
+        }
     }
     
     private final void assignLayersLocked() {
@@ -8851,13 +8883,34 @@
                 }
             }
 
-            if (!mPolicy.finishLayoutLw()) {
+            int changes = mPolicy.finishLayoutLw();
+            if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
+                if ((adjustWallpaperWindowsLocked()&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
+                    assignLayersLocked();
+                }
+            }
+            if (changes == 0) {
                 mLayoutNeeded = false;
             } else if (repeats > 2) {
                 Log.w(TAG, "Layout repeat aborted after too many iterations");
                 mLayoutNeeded = false;
+                if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) {
+                    Configuration newConfig = updateOrientationFromAppTokensLocked(
+                            null, null);
+                    if (newConfig != null) {
+                        mLayoutNeeded = true;
+                        mH.sendEmptyMessage(H.COMPUTE_AND_SEND_NEW_CONFIGURATION);
+                    }
+                }
             } else {
                 repeats++;
+                if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) {
+                    Configuration newConfig = updateOrientationFromAppTokensLocked(
+                            null, null);
+                    if (newConfig != null) {
+                        mH.sendEmptyMessage(H.COMPUTE_AND_SEND_NEW_CONFIGURATION);
+                    }
+                }
             }
         }
     }
@@ -9073,9 +9126,9 @@
                         if (DEBUG_APP_TRANSITIONS) Log.v(TAG, "**** GOOD TO GO");
                         int transit = mNextAppTransition;
                         if (mSkipAppTransitionAnimation) {
-                            transit = WindowManagerPolicy.TRANSIT_NONE;
+                            transit = WindowManagerPolicy.TRANSIT_UNSET;
                         }
-                        mNextAppTransition = WindowManagerPolicy.TRANSIT_NONE;
+                        mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
                         mAppTransitionReady = false;
                         mAppTransitionRunning = true;
                         mAppTransitionTimeout = false;
@@ -9782,6 +9835,11 @@
         for (i=mExitingAppTokens.size()-1; i>=0; i--) {
             AppWindowToken token = mExitingAppTokens.get(i);
             if (!token.hasVisible && !mClosingApps.contains(token)) {
+                // Make sure there is no animation running on this token,
+                // so any windows associated with it will be removed as
+                // soon as their animations are complete
+                token.animation = null;
+                token.animating = false;
                 mAppTokens.remove(token);
                 mExitingAppTokens.remove(i);
             }
@@ -10091,8 +10149,8 @@
         }
 
         mDisplayFrozen = true;
-        if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
-            mNextAppTransition = WindowManagerPolicy.TRANSIT_NONE;
+        if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) {
+            mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET;
             mAppTransitionReady = true;
         }
 
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 4db5239..82664eb 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -458,6 +458,13 @@
             = new ArrayList<HistoryRecord>();
 
     /**
+     * Animations that for the current transition have requested not to
+     * be considered for the transition animation.
+     */
+    final ArrayList<HistoryRecord> mNoAnimActivities
+            = new ArrayList<HistoryRecord>();
+    
+    /**
      * List of intents that were used to start the most recent tasks.
      */
     final ArrayList<TaskRecord> mRecentTasks
@@ -1572,6 +1579,7 @@
                 }
             }
             
+            long[] cpuSpeedTimes = mProcessStats.getLastCpuSpeedTimes();
             final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
             synchronized(bstats) {
                 synchronized(mPidsSelfLocked) {
@@ -1585,11 +1593,13 @@
                                 if (pr != null) {
                                     BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
                                     ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
+                                    ps.addSpeedStepTimes(cpuSpeedTimes);
                                 } else {
                                     BatteryStatsImpl.Uid.Proc ps =
                                             bstats.getProcessStatsLocked(st.name, st.pid);
                                     if (ps != null) {
                                         ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
+                                        ps.addSpeedStepTimes(cpuSpeedTimes);
                                     }
                                 }
                             }
@@ -2246,6 +2256,7 @@
         next.resumeKeyDispatchingLocked();
         ensureActivitiesVisibleLocked(null, 0);
         mWindowManager.executeAppTransition();
+        mNoAnimActivities.clear();
 
         // Mark the point when the activity is resuming
         // TODO: To be more accurate, the mark should be before the onCreate,
@@ -2562,6 +2573,7 @@
             // Make sure we have executed any pending transitions, since there
             // should be nothing left to do at this point.
             mWindowManager.executeAppTransition();
+            mNoAnimActivities.clear();
             return false;
         }
 
@@ -2572,6 +2584,7 @@
             // Make sure we have executed any pending transitions, since there
             // should be nothing left to do at this point.
             mWindowManager.executeAppTransition();
+            mNoAnimActivities.clear();
             return false;
         }
         
@@ -2634,17 +2647,25 @@
             if (prev.finishing) {
                 if (DEBUG_TRANSITION) Log.v(TAG,
                         "Prepare close transition: prev=" + prev);
-                mWindowManager.prepareAppTransition(prev.task == next.task
-                        ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
-                        : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
+                if (mNoAnimActivities.contains(prev)) {
+                    mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
+                } else {
+                    mWindowManager.prepareAppTransition(prev.task == next.task
+                            ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
+                            : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
+                }
                 mWindowManager.setAppWillBeHidden(prev);
                 mWindowManager.setAppVisibility(prev, false);
             } else {
                 if (DEBUG_TRANSITION) Log.v(TAG,
                         "Prepare open transition: prev=" + prev);
-                mWindowManager.prepareAppTransition(prev.task == next.task
-                        ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
-                        : WindowManagerPolicy.TRANSIT_TASK_OPEN);
+                if (mNoAnimActivities.contains(next)) {
+                    mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
+                } else {
+                    mWindowManager.prepareAppTransition(prev.task == next.task
+                            ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
+                            : WindowManagerPolicy.TRANSIT_TASK_OPEN);
+                }
             }
             if (false) {
                 mWindowManager.setAppWillBeHidden(prev);
@@ -2653,7 +2674,11 @@
         } else if (mHistory.size() > 1) {
             if (DEBUG_TRANSITION) Log.v(TAG,
                     "Prepare open transition: no previous");
-            mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
+            if (mNoAnimActivities.contains(next)) {
+                mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
+            } else {
+                mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
+            }
         }
 
         if (next.app != null && next.app.thread != null) {
@@ -2696,6 +2721,7 @@
                     mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
                 }
                 mWindowManager.executeAppTransition();
+                mNoAnimActivities.clear();
                 return true;
             }
             
@@ -2856,9 +2882,18 @@
             }
             if (DEBUG_TRANSITION) Log.v(TAG,
                     "Prepare open transition: starting " + r);
-            mWindowManager.prepareAppTransition(newTask
-                    ? WindowManagerPolicy.TRANSIT_TASK_OPEN
-                    : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
+            if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
+                mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
+                mNoAnimActivities.add(r);
+            } else if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
+                mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_OPEN);
+                mNoAnimActivities.remove(r);
+            } else {
+                mWindowManager.prepareAppTransition(newTask
+                        ? WindowManagerPolicy.TRANSIT_TASK_OPEN
+                        : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
+                mNoAnimActivities.remove(r);
+            }
             mWindowManager.addAppToken(
                     addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
             boolean doShow = true;
@@ -3333,7 +3368,7 @@
                         if (callerAtFront) {
                             // We really do want to push this one into the
                             // user's face, right now.
-                            moveTaskToFrontLocked(taskTop.task);
+                            moveTaskToFrontLocked(taskTop.task, r);
                         }
                     }
                     // If the caller has requested that the target task be
@@ -6919,14 +6954,14 @@
                 for (int i=0; i<N; i++) {
                     TaskRecord tr = mRecentTasks.get(i);
                     if (tr.taskId == task) {
-                        moveTaskToFrontLocked(tr);
+                        moveTaskToFrontLocked(tr, null);
                         return;
                     }
                 }
                 for (int i=mHistory.size()-1; i>=0; i--) {
                     HistoryRecord hr = (HistoryRecord)mHistory.get(i);
                     if (hr.task.taskId == task) {
-                        moveTaskToFrontLocked(hr.task);
+                        moveTaskToFrontLocked(hr.task, null);
                         return;
                     }
                 }
@@ -6936,7 +6971,7 @@
         }
     }
 
-    private final void moveTaskToFrontLocked(TaskRecord tr) {
+    private final void moveTaskToFrontLocked(TaskRecord tr, HistoryRecord reason) {
         if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
 
         final int task = tr.taskId;
@@ -6947,10 +6982,6 @@
             return;
         }
 
-        if (DEBUG_TRANSITION) Log.v(TAG,
-                "Prepare to front transition: task=" + tr);
-        mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
-        
         ArrayList moved = new ArrayList();
 
         // Applying the affinities may have removed entries from the history,
@@ -6979,6 +7010,19 @@
             pos--;
         }
 
+        if (DEBUG_TRANSITION) Log.v(TAG,
+                "Prepare to front transition: task=" + tr);
+        if (reason != null &&
+                (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
+            mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
+            HistoryRecord r = topRunningActivityLocked(null);
+            if (r != null) {
+                mNoAnimActivities.add(r);
+            }
+        } else {
+            mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
+        }
+        
         mWindowManager.moveAppTokensToTop(moved);
         if (VALIDATE_TOKENS) {
             mWindowManager.validateAppTokens(mHistory);
@@ -7004,7 +7048,7 @@
                 }
             }
             final long origId = Binder.clearCallingIdentity();
-            moveTaskToBackLocked(task);
+            moveTaskToBackLocked(task, null);
             Binder.restoreCallingIdentity(origId);
         }
     }
@@ -7023,7 +7067,7 @@
             final long origId = Binder.clearCallingIdentity();
             int taskId = getTaskForActivityLocked(token, !nonRoot);
             if (taskId >= 0) {
-                return moveTaskToBackLocked(taskId);
+                return moveTaskToBackLocked(taskId, null);
             }
             Binder.restoreCallingIdentity(origId);
         }
@@ -7041,7 +7085,7 @@
      * @param task The taskId to collect and move to the bottom.
      * @return Returns true if the move completed, false if not.
      */
-    private final boolean moveTaskToBackLocked(int task) {
+    private final boolean moveTaskToBackLocked(int task, HistoryRecord reason) {
         Log.i(TAG, "moveTaskToBack: " + task);
         
         // If we have a watcher, preflight the move before committing to it.  First check
@@ -7092,6 +7136,16 @@
             pos++;
         }
 
+        if (reason != null &&
+                (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
+            mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
+            HistoryRecord r = topRunningActivityLocked(null);
+            if (r != null) {
+                mNoAnimActivities.add(r);
+            }
+        } else {
+            mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
+        }
         mWindowManager.moveAppTokensToBottom(moved);
         if (VALIDATE_TOKENS) {
             mWindowManager.validateAppTokens(mHistory);
diff --git a/services/java/com/android/server/am/BatteryStatsService.java b/services/java/com/android/server/am/BatteryStatsService.java
index ed0d534..61537f5 100644
--- a/services/java/com/android/server/am/BatteryStatsService.java
+++ b/services/java/com/android/server/am/BatteryStatsService.java
@@ -28,6 +28,7 @@
 
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.os.BatteryStatsImpl;
+import com.android.internal.os.PowerProfile;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -49,6 +50,7 @@
     public void publish(Context context) {
         mContext = context;
         ServiceManager.addService("batteryinfo", asBinder());
+        mStats.setNumSpeedSteps(new PowerProfile(mContext).getNumSpeedSteps());
     }
     
     public void shutdown() {
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 2672c6d..046bfea 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -111,6 +111,11 @@
         return c == PAUSE || c == WAIT;
     }
 
+    /** Returns true if ch is not dialable or alpha char */
+    private static boolean isSeparator(char ch) {
+        return !isDialable(ch) && !(('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z'));
+    }
+
     /** Extracts the phone number from an Intent.
      *
      * @param intent the intent to get the number of
@@ -293,18 +298,36 @@
     }
 
     /**
+     * Compare phone numbers a and b, return true if they're identical enough for caller ID purposes.
+     */
+    public static boolean compare(String a, String b) {
+        // We've used loose comparation at least Eclair, which may change in the future.
+        return compare(a, b, false);
+    }
+
+    /**
+     * @hide only for testing.
+     */
+    public static boolean compare(String a, String b, boolean useStrictComparation) {
+        return (useStrictComparation ? compareStrictly(a, b) : compareLoosely(a, b));
+    }
+
+    /**
      * Compare phone numbers a and b, return true if they're identical
      * enough for caller ID purposes.
      *
      * - Compares from right to left
-     * - requires MIN_MATCH (5) characters to match
+     * - requires MIN_MATCH (7) characters to match
      * - handles common trunk prefixes and international prefixes
      *   (basically, everything except the Russian trunk prefix)
      *
-     * Tolerates nulls
+     * Note that this method does not return false even when the two phone numbers
+     * are not exactly same; rather; we can call this method "similar()", not "equals()".
+     *
+     * @hide
      */
     public static boolean
-    compare(String a, String b) {
+    compareLoosely(String a, String b) {
         int ia, ib;
         int matched;
 
@@ -391,6 +414,160 @@
     }
 
     /**
+     * @hide
+     */
+    public static boolean
+    compareStrictly(String a, String b) {
+        return compareStrictly(a, b, true);
+    }
+
+    /**
+     * @hide
+     */
+    public static boolean
+    compareStrictly(String a, String b, boolean acceptInvalidCCCPrefix) {
+        if (a == null || b == null) {
+            return a == b;
+        } else if (a.length() == 0 && b.length() == 0) {
+            return false;
+        }
+
+        int forwardIndexA = 0;
+        int forwardIndexB = 0;
+
+        CountryCallingCodeAndNewIndex cccA =
+            tryGetCountryCallingCodeAndNewIndex(a, acceptInvalidCCCPrefix);
+        CountryCallingCodeAndNewIndex cccB =
+            tryGetCountryCallingCodeAndNewIndex(b, acceptInvalidCCCPrefix);
+        boolean bothHasCountryCallingCode = false;
+        boolean okToIgnorePrefix = true;
+        boolean trunkPrefixIsOmittedA = false;
+        boolean trunkPrefixIsOmittedB = false;
+        if (cccA != null && cccB != null) {
+            if (cccA.countryCallingCode != cccB.countryCallingCode) {
+                // Different Country Calling Code. Must be different phone number.
+                return false;
+            }
+            // When both have ccc, do not ignore trunk prefix. Without this,
+            // "+81123123" becomes same as "+810123123" (+81 == Japan)
+            okToIgnorePrefix = false;
+            bothHasCountryCallingCode = true;
+            forwardIndexA = cccA.newIndex;
+            forwardIndexB = cccB.newIndex;
+        } else if (cccA == null && cccB == null) {
+            // When both do not have ccc, do not ignore trunk prefix. Without this,
+            // "123123" becomes same as "0123123"
+            okToIgnorePrefix = false;
+        } else {
+            if (cccA != null) {
+                forwardIndexA = cccA.newIndex;
+            } else {
+                int tmp = tryGetTrunkPrefixOmittedIndex(b, 0);
+                if (tmp >= 0) {
+                    forwardIndexA = tmp;
+                    trunkPrefixIsOmittedA = true;
+                }
+            }
+            if (cccB != null) {
+                forwardIndexB = cccB.newIndex;
+            } else {
+                int tmp = tryGetTrunkPrefixOmittedIndex(b, 0);
+                if (tmp >= 0) {
+                    forwardIndexB = tmp;
+                    trunkPrefixIsOmittedB = true;
+                }
+            }
+        }
+
+        int backwardIndexA = a.length() - 1;
+        int backwardIndexB = b.length() - 1;
+        while (backwardIndexA >= forwardIndexA && backwardIndexB >= forwardIndexB) {
+            boolean skip_compare = false;
+            final char chA = a.charAt(backwardIndexA);
+            final char chB = b.charAt(backwardIndexB);
+            if (isSeparator(chA)) {
+                backwardIndexA--;
+                skip_compare = true;
+            }
+            if (isSeparator(chB)) {
+                backwardIndexB--;
+                skip_compare = true;
+            }
+
+            if (!skip_compare) {
+                if (chA != chB) {
+                    return false;
+                }
+                backwardIndexA--;
+                backwardIndexB--;
+            }
+        }
+
+        if (okToIgnorePrefix) {
+            if ((trunkPrefixIsOmittedA && forwardIndexA <= backwardIndexA) ||
+                !checkPrefixIsIgnorable(a, forwardIndexA, backwardIndexA)) {
+                if (acceptInvalidCCCPrefix) {
+                    // Maybe the code handling the special case for Thailand makes the
+                    // result garbled, so disable the code and try again.
+                    // e.g. "16610001234" must equal to "6610001234", but with
+                    //      Thailand-case handling code, they become equal to each other.
+                    //
+                    // Note: we select simplicity rather than adding some complicated
+                    //       logic here for performance(like "checking whether remaining
+                    //       numbers are just 66 or not"), assuming inputs are small
+                    //       enough.
+                    return compare(a, b, false);
+                } else {
+                    return false;
+                }
+            }
+            if ((trunkPrefixIsOmittedB && forwardIndexB <= backwardIndexB) ||
+                !checkPrefixIsIgnorable(b, forwardIndexA, backwardIndexB)) {
+                if (acceptInvalidCCCPrefix) {
+                    return compare(a, b, false);
+                } else {
+                    return false;
+                }
+            }
+        } else {
+            // In the US, 1-650-555-1234 must be equal to 650-555-1234,
+            // while 090-1234-1234 must not be equalt to 90-1234-1234 in Japan.
+            // This request exists just in US (with 1 trunk (NDD) prefix).
+            // In addition, "011 11 7005554141" must not equal to "+17005554141",
+            // while "011 1 7005554141" must equal to "+17005554141"
+            //
+            // In this comparison, we ignore the prefix '1' just once, when
+            // - at least either does not have CCC, or
+            // - the remaining non-separator number is 1
+            boolean maybeNamp = !bothHasCountryCallingCode;
+            while (backwardIndexA >= forwardIndexA) {
+                final char chA = a.charAt(backwardIndexA);
+                if (isDialable(chA)) {
+                    if (maybeNamp && tryGetISODigit(chA) == 1) {
+                        maybeNamp = false;
+                    } else {
+                        return false;
+                    }
+                }
+                backwardIndexA--;
+            }
+            while (backwardIndexB >= forwardIndexB) {
+                final char chB = b.charAt(backwardIndexB);
+                if (isDialable(chB)) {
+                    if (maybeNamp && tryGetISODigit(chB) == 1) {
+                        maybeNamp = false;
+                    } else {
+                        return false;
+                    }
+                }
+                backwardIndexB--;
+            }
+        }
+
+        return true;
+    }
+
+    /**
      * Returns the rightmost MIN_MATCH (5) characters in the network portion
      * in *reversed* order
      *
@@ -475,54 +652,6 @@
     }
 
     /**
-     * Phone numbers are stored in "lookup" form in the database
-     * as reversed strings to allow for caller ID lookup
-     *
-     * This method takes a phone number and makes a valid SQL "LIKE"
-     * string that will match the lookup form
-     *
-     */
-    /** all of a up to len must be an international prefix or
-     *  separators/non-dialing digits
-     */
-    private static boolean
-    matchIntlPrefix(String a, int len) {
-        /* '([^0-9*#+pwn]\+[^0-9*#+pwn] | [^0-9*#+pwn]0(0|11)[^0-9*#+pwn] )$' */
-        /*        0       1                           2 3 45               */
-
-        int state = 0;
-        for (int i = 0 ; i < len ; i++) {
-            char c = a.charAt(i);
-
-            switch (state) {
-                case 0:
-                    if      (c == '+') state = 1;
-                    else if (c == '0') state = 2;
-                    else if (isNonSeparator(c)) return false;
-                break;
-
-                case 2:
-                    if      (c == '0') state = 3;
-                    else if (c == '1') state = 4;
-                    else if (isNonSeparator(c)) return false;
-                break;
-
-                case 4:
-                    if      (c == '1') state = 5;
-                    else if (isNonSeparator(c)) return false;
-                break;
-
-                default:
-                    if (isNonSeparator(c)) return false;
-                break;
-
-            }
-        }
-
-        return state == 1 || state == 3 || state == 5;
-    }
-
-    /**
      *  3GPP TS 24.008 10.5.4.7
      *  Called Party BCD Number
      *
@@ -835,76 +964,6 @@
         return result;
     }
 
-    /** all of 'a' up to len must match non-US trunk prefix ('0') */
-    private static boolean
-    matchTrunkPrefix(String a, int len) {
-        boolean found;
-
-        found = false;
-
-        for (int i = 0 ; i < len ; i++) {
-            char c = a.charAt(i);
-
-            if (c == '0' && !found) {
-                found = true;
-            } else if (isNonSeparator(c)) {
-                return false;
-            }
-        }
-
-        return found;
-    }
-
-    /** all of 'a' up to len must be a (+|00|011)country code)
-     *  We're fast and loose with the country code. Any \d{1,3} matches */
-    private static boolean
-    matchIntlPrefixAndCC(String a, int len) {
-        /*  [^0-9*#+pwn]*(\+|0(0|11)\d\d?\d? [^0-9*#+pwn] $ */
-        /*      0          1 2 3 45  6 7  8                 */
-
-        int state = 0;
-        for (int i = 0 ; i < len ; i++ ) {
-            char c = a.charAt(i);
-
-            switch (state) {
-                case 0:
-                    if      (c == '+') state = 1;
-                    else if (c == '0') state = 2;
-                    else if (isNonSeparator(c)) return false;
-                break;
-
-                case 2:
-                    if      (c == '0') state = 3;
-                    else if (c == '1') state = 4;
-                    else if (isNonSeparator(c)) return false;
-                break;
-
-                case 4:
-                    if      (c == '1') state = 5;
-                    else if (isNonSeparator(c)) return false;
-                break;
-
-                case 1:
-                case 3:
-                case 5:
-                    if      (isISODigit(c)) state = 6;
-                    else if (isNonSeparator(c)) return false;
-                break;
-
-                case 6:
-                case 7:
-                    if      (isISODigit(c)) state++;
-                    else if (isNonSeparator(c)) return false;
-                break;
-
-                default:
-                    if (isNonSeparator(c)) return false;
-            }
-        }
-
-        return state == 6 || state == 7 || state == 8;
-    }
-
     //================ Number formatting =========================
 
     /** The current locale is unknown, look for a country code or don't format */
@@ -1143,10 +1202,24 @@
         JapanesePhoneNumberFormatter.format(text);
     }
 
-    // Three and four digit phone numbers for either special services
-    // or from the network (eg carrier-originated SMS messages) should
-    // not match
-    static final int MIN_MATCH = 5;
+    // Three and four digit phone numbers for either special services,
+    // or 3-6 digit addresses from the network (eg carrier-originated SMS messages) should
+    // not match.
+    //
+    // This constant used to be 5, but SMS short codes has increased in length and
+    // can be easily 6 digits now days. Most countries have SMS short code length between
+    // 3 to 6 digits. The exceptions are
+    //
+    // Australia: Short codes are six or eight digits in length, starting with the prefix "19"
+    //            followed by an additional four or six digits and two.
+    // Czech Republic: Codes are seven digits in length for MO and five (not billed) or
+    //            eight (billed) for MT direction
+    //
+    // see http://en.wikipedia.org/wiki/Short_code#Regional_differences for reference
+    //
+    // However, in order to loose match 650-555-1212 and 555-1212, we need to set the min match
+    // to 7.
+    static final int MIN_MATCH = 7;
 
     /**
      * isEmergencyNumber: checks a given number against the list of
@@ -1553,4 +1626,317 @@
         }
         return retStr;
     }
+
+    //===== Begining of utility methods used in compareLoosely() =====
+
+    /**
+     * Phone numbers are stored in "lookup" form in the database
+     * as reversed strings to allow for caller ID lookup
+     *
+     * This method takes a phone number and makes a valid SQL "LIKE"
+     * string that will match the lookup form
+     *
+     */
+    /** all of a up to len must be an international prefix or
+     *  separators/non-dialing digits
+     */
+    private static boolean
+    matchIntlPrefix(String a, int len) {
+        /* '([^0-9*#+pwn]\+[^0-9*#+pwn] | [^0-9*#+pwn]0(0|11)[^0-9*#+pwn] )$' */
+        /*        0       1                           2 3 45               */
+
+        int state = 0;
+        for (int i = 0 ; i < len ; i++) {
+            char c = a.charAt(i);
+
+            switch (state) {
+                case 0:
+                    if      (c == '+') state = 1;
+                    else if (c == '0') state = 2;
+                    else if (isNonSeparator(c)) return false;
+                break;
+
+                case 2:
+                    if      (c == '0') state = 3;
+                    else if (c == '1') state = 4;
+                    else if (isNonSeparator(c)) return false;
+                break;
+
+                case 4:
+                    if      (c == '1') state = 5;
+                    else if (isNonSeparator(c)) return false;
+                break;
+
+                default:
+                    if (isNonSeparator(c)) return false;
+                break;
+
+            }
+        }
+
+        return state == 1 || state == 3 || state == 5;
+    }
+
+    /** all of 'a' up to len must be a (+|00|011)country code)
+     *  We're fast and loose with the country code. Any \d{1,3} matches */
+    private static boolean
+    matchIntlPrefixAndCC(String a, int len) {
+        /*  [^0-9*#+pwn]*(\+|0(0|11)\d\d?\d? [^0-9*#+pwn] $ */
+        /*      0          1 2 3 45  6 7  8                 */
+
+        int state = 0;
+        for (int i = 0 ; i < len ; i++ ) {
+            char c = a.charAt(i);
+
+            switch (state) {
+                case 0:
+                    if      (c == '+') state = 1;
+                    else if (c == '0') state = 2;
+                    else if (isNonSeparator(c)) return false;
+                break;
+
+                case 2:
+                    if      (c == '0') state = 3;
+                    else if (c == '1') state = 4;
+                    else if (isNonSeparator(c)) return false;
+                break;
+
+                case 4:
+                    if      (c == '1') state = 5;
+                    else if (isNonSeparator(c)) return false;
+                break;
+
+                case 1:
+                case 3:
+                case 5:
+                    if      (isISODigit(c)) state = 6;
+                    else if (isNonSeparator(c)) return false;
+                break;
+
+                case 6:
+                case 7:
+                    if      (isISODigit(c)) state++;
+                    else if (isNonSeparator(c)) return false;
+                break;
+
+                default:
+                    if (isNonSeparator(c)) return false;
+            }
+        }
+
+        return state == 6 || state == 7 || state == 8;
+    }
+
+    /** all of 'a' up to len must match non-US trunk prefix ('0') */
+    private static boolean
+    matchTrunkPrefix(String a, int len) {
+        boolean found;
+
+        found = false;
+
+        for (int i = 0 ; i < len ; i++) {
+            char c = a.charAt(i);
+
+            if (c == '0' && !found) {
+                found = true;
+            } else if (isNonSeparator(c)) {
+                return false;
+            }
+        }
+
+        return found;
+    }
+
+    //===== End of utility methods used only in compareLoosely() =====
+
+    //===== Beggining of utility methods used only in compareStrictly() ====
+
+    /*
+     * If true, the number is country calling code.
+     */
+    private static final boolean COUNTLY_CALLING_CALL[] = {
+        true, true, false, false, false, false, false, true, false, false,
+        false, false, false, false, false, false, false, false, false, false,
+        true, false, false, false, false, false, false, true, true, false,
+        true, true, true, true, true, false, true, false, false, true,
+        true, false, false, true, true, true, true, true, true, true,
+        false, true, true, true, true, true, true, true, true, false,
+        true, true, true, true, true, true, true, false, false, false,
+        false, false, false, false, false, false, false, false, false, false,
+        false, true, true, true, true, false, true, false, false, true,
+        true, true, true, true, true, true, false, false, true, false,
+    };
+    private static final int CCC_LENGTH = COUNTLY_CALLING_CALL.length;
+
+    /**
+     * @return true when input is valid Country Calling Code.
+     */
+    private static boolean isCountryCallingCode(int countryCallingCodeCandidate) {
+        return countryCallingCodeCandidate > 0 && countryCallingCodeCandidate < CCC_LENGTH &&
+                COUNTLY_CALLING_CALL[countryCallingCodeCandidate];
+    }
+
+    /**
+     * Returns interger corresponding to the input if input "ch" is
+     * ISO-LATIN characters 0-9.
+     * Returns -1 otherwise
+     */
+    private static int tryGetISODigit(char ch) {
+        if ('0' <= ch && ch <= '9') {
+            return ch - '0';
+        } else {
+            return -1;
+        }
+    }
+
+    private static class CountryCallingCodeAndNewIndex {
+        public final int countryCallingCode;
+        public final int newIndex;
+        public CountryCallingCodeAndNewIndex(int countryCode, int newIndex) {
+            this.countryCallingCode = countryCode;
+            this.newIndex = newIndex;
+        }
+    }
+
+    /*
+     * Note that this function does not strictly care the country calling code with
+     * 3 length (like Morocco: +212), assuming it is enough to use the first two
+     * digit to compare two phone numbers.
+     */
+    private static CountryCallingCodeAndNewIndex tryGetCountryCallingCodeAndNewIndex(
+        String str, boolean acceptThailandCase) {
+        // Rough regexp:
+        //  ^[^0-9*#+]*((\+|0(0|11)\d\d?|166) [^0-9*#+] $
+        //         0        1 2 3 45  6 7  89
+        //
+        // In all the states, this function ignores separator characters.
+        // "166" is the special case for the call from Thailand to the US. Uguu!
+        int state = 0;
+        int ccc = 0;
+        final int length = str.length();
+        for (int i = 0 ; i < length ; i++ ) {
+            char ch = str.charAt(i);
+            switch (state) {
+                case 0:
+                    if      (ch == '+') state = 1;
+                    else if (ch == '0') state = 2;
+                    else if (ch == '1') {
+                        if (acceptThailandCase) {
+                            state = 8;
+                        } else {
+                            return null;
+                        }
+                    } else if (isDialable(ch)) {
+                        return null;
+                    }
+                break;
+
+                case 2:
+                    if      (ch == '0') state = 3;
+                    else if (ch == '1') state = 4;
+                    else if (isDialable(ch)) {
+                        return null;
+                    }
+                break;
+
+                case 4:
+                    if      (ch == '1') state = 5;
+                    else if (isDialable(ch)) {
+                        return null;
+                    }
+                break;
+
+                case 1:
+                case 3:
+                case 5:
+                case 6:
+                case 7:
+                    {
+                        int ret = tryGetISODigit(ch);
+                        if (ret > 0) {
+                            ccc = ccc * 10 + ret;
+                            if (ccc >= 100 || isCountryCallingCode(ccc)) {
+                                return new CountryCallingCodeAndNewIndex(ccc, i + 1);
+                            }
+                            if (state == 1 || state == 3 || state == 5) {
+                                state = 6;
+                            } else {
+                                state++;
+                            }
+                        } else if (isDialable(ch)) {
+                            return null;
+                        }
+                    }
+                    break;
+                case 8:
+                    if (ch == '6') state = 9;
+                    else if (isDialable(ch)) {
+                        return null;
+                    }
+                    break;
+                case 9:
+                    if (ch == '6') {
+                        return new CountryCallingCodeAndNewIndex(66, i + 1);
+                    } else {
+                        return null;
+                    }
+                default:
+                    return null;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Currently this function simply ignore the first digit assuming it is
+     * trunk prefix. Actually trunk prefix is different in each country.
+     *
+     * e.g.
+     * "+79161234567" equals "89161234567" (Russian trunk digit is 8)
+     * "+33123456789" equals "0123456789" (French trunk digit is 0)
+     *
+     */
+    private static int tryGetTrunkPrefixOmittedIndex(String str, int currentIndex) {
+        int length = str.length();
+        for (int i = currentIndex ; i < length ; i++) {
+            final char ch = str.charAt(i);
+            if (tryGetISODigit(ch) >= 0) {
+                return i + 1;
+            } else if (isDialable(ch)) {
+                return -1;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Return true if the prefix of "str" is "ignorable". Here, "ignorable" means
+     * that "str" has only one digit and separater characters. The one digit is
+     * assumed to be trunk prefix.
+     */
+    private static boolean checkPrefixIsIgnorable(final String str,
+            int forwardIndex, int backwardIndex) {
+        boolean trunk_prefix_was_read = false;
+        while (backwardIndex >= forwardIndex) {
+            if (tryGetISODigit(str.charAt(backwardIndex)) >= 0) {
+                if (trunk_prefix_was_read) {
+                    // More than one digit appeared, meaning that "a" and "b"
+                    // is different.
+                    return false;
+                } else {
+                    // Ignore just one digit, assuming it is trunk prefix.
+                    trunk_prefix_was_read = true;
+                }
+            } else if (isDialable(str.charAt(backwardIndex))) {
+                // Trunk prefix is a digit, not "*", "#"...
+                return false;
+            }
+            backwardIndex--;
+        }
+
+        return true;
+    }
+
+    //==== End of utility methods used only in compareStrictly() =====
 }
diff --git a/telephony/java/com/android/internal/telephony/BaseCommands.java b/telephony/java/com/android/internal/telephony/BaseCommands.java
index 3edca66..52f25f6 100644
--- a/telephony/java/com/android/internal/telephony/BaseCommands.java
+++ b/telephony/java/com/android/internal/telephony/BaseCommands.java
@@ -64,6 +64,7 @@
     protected RegistrantList mLineControlInfoRegistrants = new RegistrantList();
     protected RegistrantList mT53ClirInfoRegistrants = new RegistrantList();
     protected RegistrantList mT53AudCntrlInfoRegistrants = new RegistrantList();
+    protected RegistrantList mRingbackToneRegistrants = new RegistrantList();
 
     protected Registrant mSMSRegistrant;
     protected Registrant mNITZTimeRegistrant;
@@ -569,6 +570,15 @@
         mT53AudCntrlInfoRegistrants.remove(h);
     }
 
+    public void registerForRingbackTone(Handler h, int what, Object obj) {
+        Registrant r = new Registrant (h, what, obj);
+        mRingbackToneRegistrants.add(r);
+    }
+
+    public void unregisterForRingbackTone(Handler h) {
+        mRingbackToneRegistrants.remove(h);
+    }
+
     //***** Protected Methods
     /**
      * Store new RadioState and send notification based on the changes
diff --git a/telephony/java/com/android/internal/telephony/CommandsInterface.java b/telephony/java/com/android/internal/telephony/CommandsInterface.java
index 63bdc2c..9d83556 100644
--- a/telephony/java/com/android/internal/telephony/CommandsInterface.java
+++ b/telephony/java/com/android/internal/telephony/CommandsInterface.java
@@ -525,6 +525,17 @@
      void registerForCdmaOtaProvision(Handler h,int what, Object obj);
      void unregisterForCdmaOtaProvision(Handler h);
 
+     /**
+      * Registers the handler when out-band ringback tone is needed.<p>
+      *
+      *  Messages received from this:
+      *  Message.obj will be an AsyncResult
+      *  AsyncResult.userObj = obj
+      *  AsyncResult.result = boolean. <p>
+      */
+     void registerForRingbackTone(Handler h, int what, Object obj);
+     void unregisterForRingbackTone(Handler h);
+
     /**
      * Supply the ICC PIN to the ICC card
      *
diff --git a/telephony/java/com/android/internal/telephony/Connection.java b/telephony/java/com/android/internal/telephony/Connection.java
index e6fd0a0..a48900a 100644
--- a/telephony/java/com/android/internal/telephony/Connection.java
+++ b/telephony/java/com/android/internal/telephony/Connection.java
@@ -15,6 +15,7 @@
  */
 
 package com.android.internal.telephony;
+import android.util.Log;
 
 /**
  * {@hide}
@@ -27,6 +28,7 @@
     public static int PRESENTATION_UNKNOWN = 3;    // no specified or unknown by network
     public static int PRESENTATION_PAYPHONE = 4;   // show pay phone info
 
+    private static String LOG_TAG = "TelephonyConnection";
 
     public enum DisconnectCause {
         NOT_DISCONNECTED,               /* has not yet disconnected */
@@ -269,4 +271,25 @@
      */
     public abstract int getNumberPresentation();
 
+    /**
+     * Build a human representation of a connection instance, suitable for debugging.
+     * Don't log personal stuff unless in debug mode.
+     * @return a string representing the internal state of this connection.
+     */
+    public String toString() {
+        StringBuilder str = new StringBuilder(128);
+
+        if (Log.isLoggable(LOG_TAG, Log.DEBUG)) {
+            str.append("addr: " + getAddress())
+                    .append(" pres.: " + getNumberPresentation())
+                    .append(" dial: " + getOrigDialString())
+                    .append(" postdial: " + getRemainingPostDialString())
+                    .append(" cnap name: " + getCnapName())
+                    .append("(" + getCnapNamePresentation() + ")");
+        }
+        str.append(" incoming: " + isIncoming())
+                .append(" state: " + getState())
+                .append(" post dial state: " + getPostDialState());
+        return str.toString();
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java
index f32837f..fffd128 100644
--- a/telephony/java/com/android/internal/telephony/Phone.java
+++ b/telephony/java/com/android/internal/telephony/Phone.java
@@ -379,6 +379,23 @@
 
     void unregisterForIncomingRing(Handler h);
 
+    /**
+     * Notifies when out-band ringback tone is needed.<p>
+     *
+     *  Messages received from this:
+     *  Message.obj will be an AsyncResult
+     *  AsyncResult.userObj = obj
+     *  AsyncResult.result = boolean, true to start play ringback tone
+     *                       and false to stop. <p>
+     */
+    void registerForRingbackTone(Handler h, int what, Object obj);
+
+    /**
+     * Unregisters for ringback tone notification.
+     */
+
+    void unregisterForRingbackTone(Handler h);
+
 
     /**
      * Notifies when a voice connection has disconnected, either due to local
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index e340f85..1c62a82 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -482,6 +482,16 @@
         mServiceStateRegistrants.remove(h);
     }
 
+    // Inherited documentation suffices.
+    public void registerForRingbackTone(Handler h, int what, Object obj) {
+        mCM.registerForRingbackTone(h,what,obj);
+    }
+
+    // Inherited documentation suffices.
+    public void unregisterForRingbackTone(Handler h) {
+        mCM.unregisterForRingbackTone(h);
+    }
+
     /**
      * Subclasses of Phone probably want to replace this with a
      * version scoped to their packages
diff --git a/telephony/java/com/android/internal/telephony/PhoneProxy.java b/telephony/java/com/android/internal/telephony/PhoneProxy.java
index 711a48c..c4f663a 100644
--- a/telephony/java/com/android/internal/telephony/PhoneProxy.java
+++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java
@@ -331,6 +331,14 @@
         mActivePhone.unregisterForEcmTimerReset(h);
     }
 
+    public void registerForRingbackTone(Handler h, int what, Object obj) {
+        mActivePhone.registerForRingbackTone(h,what,obj);
+    }
+
+    public void unregisterForRingbackTone(Handler h) {
+        mActivePhone.unregisterForRingbackTone(h);
+    }
+
     public boolean getIccRecordsLoaded() {
         return mActivePhone.getIccRecordsLoaded();
     }
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index cd6340e..d1b446b 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -2313,6 +2313,7 @@
             case RIL_UNSOL_CDMA_OTA_PROVISION_STATUS: ret = responseInts(p); break;
             case RIL_UNSOL_CDMA_INFO_REC: ret = responseCdmaInformationRecord(p); break;
             case RIL_UNSOL_OEM_HOOK_RAW: ret = responseRaw(p); break;
+            case RIL_UNSOL_RINGBACK_TONE: ret = responseInts(p); break;
 
             default:
                 throw new RuntimeException("Unrecognized unsol response: " + response);
@@ -2597,6 +2598,14 @@
                     mUnsolOemHookRawRegistrant.notifyRegistrant(new AsyncResult(null, ret, null));
                 }
                 break;
+
+            case RIL_UNSOL_RINGBACK_TONE:
+                if (RILJ_LOGD) unsljLogvRet(response, ret);
+                if (mRingbackToneRegistrants != null) {
+                    boolean playtone = (((int[])ret)[0] == 1);
+                    mRingbackToneRegistrants.notifyRegistrants(
+                                        new AsyncResult (null, playtone, null));
+                }
         }
     }
 
@@ -3209,6 +3218,7 @@
             case RIL_UNSOL_CDMA_OTA_PROVISION_STATUS: return "UNSOL_CDMA_OTA_PROVISION_STATUS";
             case RIL_UNSOL_CDMA_INFO_REC: return "UNSOL_CDMA_INFO_REC";
             case RIL_UNSOL_OEM_HOOK_RAW: return "UNSOL_OEM_HOOK_RAW";
+            case RIL_UNSOL_RINGBACK_TONE: return "UNSOL_RINGBACK_TONG";
             default: return "<unknown reponse>";
         }
     }
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 90a82f9..3e9d8ad 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -258,4 +258,5 @@
     int RIL_UNSOL_CDMA_OTA_PROVISION_STATUS = 1026;
     int RIL_UNSOL_CDMA_INFO_REC = 1027;
     int RIL_UNSOL_OEM_HOOK_RAW = 1028;
+    int RIL_UNSOL_RINGBACK_TONE = 1029;
 }
diff --git a/telephony/java/com/android/internal/telephony/SmsMessageBase.java b/telephony/java/com/android/internal/telephony/SmsMessageBase.java
index 3f0213b..3c2f2ed 100644
--- a/telephony/java/com/android/internal/telephony/SmsMessageBase.java
+++ b/telephony/java/com/android/internal/telephony/SmsMessageBase.java
@@ -383,7 +383,7 @@
          * 2. [x@y][ ]/[body]
          */
          String[] parts = messageBody.split("( /)|( )", 2);
-         if (parts.length < 1) return;
+         if (parts.length < 2) return;
          emailFrom = parts[0];
          emailBody = parts[1];
          isEmail = true;
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
index 5bf1a0f..9fe2038 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
@@ -437,7 +437,7 @@
                     new AsyncResult(null, null, null));
         }
         if (Phone.DEBUG_PHONE) {
-            log("update phone state, old= , new= , " + oldState + state);
+            log("update phone state, old=" + oldState + " new="+ state);
         }
         if (state != oldState) {
             phone.notifyPhoneStateChanged();
@@ -522,37 +522,44 @@
                     }
                 } else {
                     if (Phone.DEBUG_PHONE) {
-                        log("pending Mo= , dc= " + pendingMO + dc);
+                        log("pendingMo=" + pendingMO + ", dc=" + dc);
                     }
                     // find if the MT call is a new ring or unknown connection
                     newRinging = checkMtFindNewRinging(dc,i);
                     if (newRinging == null) {
                         unknownConnectionAppeared = true;
                     }
+                    checkAndEnableDataCallAfterEmergencyCallDropped();
                 }
                 hasNonHangupStateChanged = true;
             } else if (conn != null && dc == null) {
+                // This case means the RIL has no more active call anymore and
+                // we need to clean up the foregroundCall and ringingCall.
+                // Loop through foreground call connections as
+                // it contains the known logical connections.
                 int count = foregroundCall.connections.size();
-                if (count == 0) {
-                    // Handle an unanswered MO/MT call, there is no
-                    // foregroundCall connections at this time.
-                    droppedDuringPoll.add(conn);
-                } else {
-                    // Loop through foreground call connections as
-                    // it contains the known logical connections.
-                    for (int n = 0; n < count; n++) {
-                        CdmaConnection cn = (CdmaConnection)foregroundCall.connections.get(n);
-                        droppedDuringPoll.add(cn);
-                    }
+                for (int n = 0; n < count; n++) {
+                    if (Phone.DEBUG_PHONE) log("adding fgCall cn " + n + " to droppedDuringPoll");
+                    CdmaConnection cn = (CdmaConnection)foregroundCall.connections.get(n);
+                    droppedDuringPoll.add(cn);
+                }
+                count = ringingCall.connections.size();
+                // Loop through ringing call connections as
+                // it may contain the known logical connections.
+                for (int n = 0; n < count; n++) {
+                    if (Phone.DEBUG_PHONE) log("adding rgCall cn " + n + " to droppedDuringPoll");
+                    CdmaConnection cn = (CdmaConnection)ringingCall.connections.get(n);
+                    droppedDuringPoll.add(cn);
                 }
                 foregroundCall.setGeneric(false);
+                ringingCall.setGeneric(false);
 
                 // Re-start Ecm timer when the connected emergency call ends
                 if (mIsEcmTimerCanceled) {
                     handleEcmTimer(phone.RESTART_ECM_TIMER);
-                } else {
-                    mIsInEmergencyCall = false;
                 }
+                // If emergency call is not going through while dialing
+                checkAndEnableDataCallAfterEmergencyCallDropped();
 
                 // Dropped connections are removed from the CallTracker
                 // list but kept in the Call list
@@ -568,6 +575,7 @@
                         if (newRinging == null) {
                             unknownConnectionAppeared = true;
                         }
+                        checkAndEnableDataCallAfterEmergencyCallDropped();
                     } else {
                         // Call info stored in conn is not consistent with the call info from dc.
                         // We should follow the rule of MT calls taking precedence over MO calls
@@ -1030,10 +1038,30 @@
      */
     private void disableDataCallInEmergencyCall(String dialString) {
         if (PhoneNumberUtils.isEmergencyNumber(dialString)) {
+            if (Phone.DEBUG_PHONE) log("disableDataCallInEmergencyCall");
             phone.disableDataConnectivity();
             mIsInEmergencyCall = true;
         }
     }
+
+    /**
+     * Check and enable data call after an emergency call is dropped if it's
+     * not in ECM
+     */
+    private void checkAndEnableDataCallAfterEmergencyCallDropped() {
+        if (mIsInEmergencyCall) {
+            String inEcm=SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE, "false");
+            if (Phone.DEBUG_PHONE) {
+                log("checkAndEnableDataCallAfterEmergencyCallDropped,inEcm=" + inEcm);
+            }
+            if (inEcm.compareTo("false") == 0) {
+                // Re-initiate data connection
+                phone.mDataConnection.setDataEnabled(true);
+            }
+            mIsInEmergencyCall = false;
+        }
+    }
+
     /**
      * Check the MT call to see if it's a new ring or
      * a unknown connection.
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java
index 0c94e6a..bc04e02 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaConnection.java
@@ -221,10 +221,6 @@
         return isIncoming == c.isMT && equalsHandlesNulls(address, cAddress);
     }
 
-    public String
-    toString() {
-        return (isIncoming ? "incoming" : "outgoing");
-    }
 
     public String getOrigDialString(){
         return dialString;
@@ -492,6 +488,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 +507,7 @@
             cnapName = dc.name;
         }
 
-        log("--dssds----"+cnapName);
+        if (Phone.DEBUG_PHONE) log("--dssds----"+cnapName);
         cnapNamePresentation = dc.namePresentation;
         numberPresentation = dc.numberPresentation;
 
@@ -529,9 +527,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 +856,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 +881,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 +905,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/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index 9ac78eb..a410f0e 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -538,12 +538,15 @@
                 if (!mPendingRadioPowerOffAfterDataOff) {
                     DataConnectionTracker.State currentState = dcTracker.getState();
                     if (currentState != DataConnectionTracker.State.CONNECTED
-                            && currentState != DataConnectionTracker.State.DISCONNECTING) {
+                            && currentState != DataConnectionTracker.State.DISCONNECTING
+                            && currentState != DataConnectionTracker.State.INITING) {
                         if (DBG) log("Data disconnected, turn off radio right away.");
                         cm.setRadioPower(false, null);
                     }
-                    else if (sendEmptyMessageDelayed(EVENT_SET_RADIO_POWER_OFF, 5000)) {
-                        if (DBG) log("Wait 5 sec for data to be disconnected, then turn off radio.");
+                    else if (sendEmptyMessageDelayed(EVENT_SET_RADIO_POWER_OFF, 30000)) {
+                        if (DBG) {
+                            log("Wait up to 30 sec for data to disconnect, then turn off radio.");
+                        }
                         mPendingRadioPowerOffAfterDataOff = true;
                     } else {
                         Log.w(LOG_TAG, "Cannot send delayed Msg, turn off radio right away.");
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java b/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java
index 2091fb6..445be39 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmConnection.java
@@ -180,11 +180,6 @@
         return isIncoming == c.isMT && equalsHandlesNulls(address, cAddress);
     }
 
-    public String
-    toString() {
-        return (isIncoming ? "incoming" : "outgoing");
-    }
-
     public String getAddress() {
         return address;
     }
diff --git a/test-runner/android/test/mock/MockContext.java b/test-runner/android/test/mock/MockContext.java
index 5368526..57b22f8 100644
--- a/test-runner/android/test/mock/MockContext.java
+++ b/test-runner/android/test/mock/MockContext.java
@@ -264,6 +264,13 @@
     }
 
     @Override
+    public void sendStickyOrderedBroadcast(Intent intent,
+            BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData,
+           Bundle initialExtras) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
     public void removeStickyBroadcast(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/tests/AndroidTests/src/com/android/unit_tests/DatabaseGeneralTest.java b/tests/AndroidTests/src/com/android/unit_tests/DatabaseGeneralTest.java
index 0991e8c..853f10a 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/DatabaseGeneralTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/DatabaseGeneralTest.java
@@ -204,16 +204,18 @@
         assertEquals("+" + PHONE_NUMBER, number);
         c.close();
     }
-
-
-    private void phoneNumberCompare(String phone1, String phone2, boolean equal)
-        throws Exception {
+    
+    private void phoneNumberCompare(String phone1, String phone2, boolean equal, 
+            boolean useStrictComparation) {
         String[] temporalPhoneNumbers = new String[2];
         temporalPhoneNumbers[0] = phone1;
         temporalPhoneNumbers[1] = phone2;
 
         Cursor cursor = mDatabase.rawQuery(
-                "SELECT CASE WHEN PHONE_NUMBERS_EQUAL(?, ?) THEN 'equal' ELSE 'not equal' END",
+                String.format(
+                        "SELECT CASE WHEN PHONE_NUMBERS_EQUAL(?, ?, %d) " +
+                        "THEN 'equal' ELSE 'not equal' END",
+                        (useStrictComparation ? 1 : 0)),
                 temporalPhoneNumbers);
         try {
             assertNotNull(cursor);
@@ -233,11 +235,23 @@
     }
 
     private void assertPhoneNumberEqual(String phone1, String phone2) throws Exception {
-        phoneNumberCompare(phone1, phone2, true);
+        assertPhoneNumberEqual(phone1, phone2, true);
+        assertPhoneNumberEqual(phone1, phone2, false);
+    }
+    
+    private void assertPhoneNumberEqual(String phone1, String phone2, boolean useStrict)
+            throws Exception {
+        phoneNumberCompare(phone1, phone2, true, useStrict);
     }
 
     private void assertPhoneNumberNotEqual(String phone1, String phone2) throws Exception {
-        phoneNumberCompare(phone1, phone2, false);
+        assertPhoneNumberNotEqual(phone1, phone2, true);
+        assertPhoneNumberNotEqual(phone1, phone2, false);
+    }
+    
+    private void assertPhoneNumberNotEqual(String phone1, String phone2, boolean useStrict)
+            throws Exception {
+        phoneNumberCompare(phone1, phone2, false, useStrict);
     }
 
     /**
@@ -252,7 +266,8 @@
         assertPhoneNumberNotEqual("123123", "923123");
         assertPhoneNumberNotEqual("123123", "123129");
         assertPhoneNumberNotEqual("123123", "1231234");
-        assertPhoneNumberNotEqual("123123", "0123123");
+        assertPhoneNumberEqual("123123", "0123123", false);
+        assertPhoneNumberNotEqual("123123", "0123123", true);
         assertPhoneNumberEqual("650-253-0000", "6502530000");
         assertPhoneNumberEqual("650-253-0000", "650 253 0000");
         assertPhoneNumberEqual("650 253 0000", "6502530000");
@@ -291,11 +306,13 @@
         assertPhoneNumberEqual("+593-2-1234-123", "21234123");
 
         // Two continuous 0 at the beginning of the phone string should not be
-        // treated as trunk prefix.
-        assertPhoneNumberNotEqual("008001231234", "8001231234");
+        // treated as trunk prefix in the strict comparation.
+        assertPhoneNumberEqual("008001231234", "8001231234", false);
+        assertPhoneNumberNotEqual("008001231234", "8001231234", true);
 
-        // Confirm that the bug found before does not re-appear.
-        assertPhoneNumberNotEqual("080-1234-5678", "+819012345678");
+        // Confirm that the bug found before does not re-appear in the strict compalation
+        assertPhoneNumberEqual("080-1234-5678", "+819012345678", false);
+        assertPhoneNumberNotEqual("080-1234-5678", "+819012345678", true);
     }
 
     @MediumTest
diff --git a/tests/BrowserPowerTest/src/com/android/browserpowertest/PowerMeasurement.java b/tests/BrowserPowerTest/src/com/android/browserpowertest/PowerMeasurement.java
index 74ac865f..861e37b 100644
--- a/tests/BrowserPowerTest/src/com/android/browserpowertest/PowerMeasurement.java
+++ b/tests/BrowserPowerTest/src/com/android/browserpowertest/PowerMeasurement.java
@@ -12,7 +12,8 @@
 
     private static final String LOGTAG = "PowerMeasurement";
     private static final String PKG_NAME = "com.android.browserpowertest";
-    private static final String TESTING_URL = "http://www.espn.com";
+    private static final String TESTING_URL =
+        "http://75.17.48.204:10088/nyt/index.html";
     private static final int TIME_OUT = 2 * 60 * 1000;
     private static final int DELAY = 0;
 
@@ -46,6 +47,24 @@
                 pageErrorFlag);
         Log.v(LOGTAG, "Page is loaded in " + activity.getPageLoadTime() + " ms.");
 
+        // Force to clean up the cache dir so that it get back to the clean
+        // state
+        Runtime fileRemoval = Runtime.getRuntime();
+        String cmdBecomeSu = "su";
+        boolean clearCacheSuccess = false;
+        try{
+            Process runsum = fileRemoval.exec(cmdBecomeSu);
+            int exitVal = runsum.waitFor();
+            String rmfile = "rm -r /data/data/com.android.browserpowertest/cache";
+            Process removal = fileRemoval.exec(rmfile);
+            exitVal = removal.waitFor();
+            if (exitVal == 0) {
+                clearCacheSuccess = true;
+            }
+        } catch ( Exception e){
+            assertTrue("Fails to clear the cahche", false);   
+        }
+        assertTrue("Fails to clear the cahche", clearCacheSuccess);
         activity.finish();
     }
 }
diff --git a/tests/CoreTests/com/android/internal/telephony/PhoneNumberUtilsTest.java b/tests/CoreTests/com/android/internal/telephony/PhoneNumberUtilsTest.java
index 7426d33..20ea4d7 100644
--- a/tests/CoreTests/com/android/internal/telephony/PhoneNumberUtilsTest.java
+++ b/tests/CoreTests/com/android/internal/telephony/PhoneNumberUtilsTest.java
@@ -257,19 +257,19 @@
 
     @SmallTest
     public void testToCallerIDIndexable() throws Exception {
-        assertEquals("14145", PhoneNumberUtils.toCallerIDMinMatch("17005554141"));
-        assertEquals("14145", PhoneNumberUtils.toCallerIDMinMatch("1-700-555-4141"));
-        assertEquals("14145", PhoneNumberUtils.toCallerIDMinMatch("1-700-555-4141,1234"));
-        assertEquals("14145", PhoneNumberUtils.toCallerIDMinMatch("1-700-555-4141;1234"));
+        assertEquals("1414555", PhoneNumberUtils.toCallerIDMinMatch("17005554141"));
+        assertEquals("1414555", PhoneNumberUtils.toCallerIDMinMatch("1-700-555-4141"));
+        assertEquals("1414555", PhoneNumberUtils.toCallerIDMinMatch("1-700-555-4141,1234"));
+        assertEquals("1414555", PhoneNumberUtils.toCallerIDMinMatch("1-700-555-4141;1234"));
 
         //this seems wrong, or at least useless
-        assertEquals("NN145", PhoneNumberUtils.toCallerIDMinMatch("1-700-555-41NN"));
+        assertEquals("NN14555", PhoneNumberUtils.toCallerIDMinMatch("1-700-555-41NN"));
 
         //<shrug> -- these are all not useful, but not terribly wrong
         assertEquals("", PhoneNumberUtils.toCallerIDMinMatch(""));
         assertEquals("0032", PhoneNumberUtils.toCallerIDMinMatch("2300"));
         assertEquals("0032+", PhoneNumberUtils.toCallerIDMinMatch("+2300"));
-        assertEquals("#130#", PhoneNumberUtils.toCallerIDMinMatch("*#031#"));
+        assertEquals("#130#*", PhoneNumberUtils.toCallerIDMinMatch("*#031#"));
     }
 
     @SmallTest
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index f2cdf75..4742341 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -712,7 +712,8 @@
                                 LARGE_SCREEN_ATTR, NULL, 1);
                     } else if (tag == "uses-feature") {
                         String8 name = getAttribute(tree, NAME_ATTR, &error);
-                        if (error == "") {
+
+                        if (name != "" && error == "") {
                             int req = getIntegerAttribute(tree,
                                     REQUIRED_ATTR, NULL, 1);
                             if (name == "android.hardware.camera") {
@@ -729,7 +730,7 @@
                         }
                     } else if (tag == "uses-permission") {
                         String8 name = getAttribute(tree, NAME_ATTR, &error);
-                        if (error == "") {
+                        if (name != "" && error == "") {
                             if (name == "android.permission.CAMERA") {
                                 hasCameraPermission = true;
                             }
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 4e7e925..1e9f573 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
@@ -1099,6 +1099,13 @@
     }
 
     @Override
+    public void sendStickyOrderedBroadcast(Intent intent,
+            BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData,
+           Bundle initialExtras) {
+        // TODO Auto-generated method stub
+    }
+    
+    @Override
     public void setTheme(int arg0) {
         // TODO Auto-generated method stub
 
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 954930e..01bc919 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -71,7 +71,7 @@
     /** {@hide} */
     public EnterpriseField phase2 = new EnterpriseField("phase2");
     /** {@hide} */
-    public EnterpriseField identity = new EnterpriseField("anonymous_identity");
+    public EnterpriseField identity = new EnterpriseField("identity");
     /** {@hide} */
     public EnterpriseField anonymous_identity = new EnterpriseField("anonymous_identity");
     /** {@hide} */
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index e3d8bf4..5638480 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -907,6 +907,7 @@
                             }
                         }
                     } else if (newState == SupplicantState.DISCONNECTED) {
+                        mHaveIpAddress = false;
                         if (isDriverStopped() || mDisconnectExpected) {
                             handleDisconnectedState(DetailedState.DISCONNECTED);
                         } else {
@@ -1007,20 +1008,17 @@
                     setNotificationVisible(false, 0, false, 0);
                     boolean wasDisconnectPending = mDisconnectPending;
                     cancelDisconnect();
-                    if (!TextUtils.equals(mWifiInfo.getSSID(), mLastSsid)) {
-                        /*
-                         * The connection is fully configured as far as link-level
-                         * connectivity is concerned, but we may still need to obtain
-                         * an IP address. But do this only if we are connecting to
-                         * a different network than we were connected to previously.
-                         */
-                        if (wasDisconnectPending) {
-                            DetailedState saveState = getNetworkInfo().getDetailedState();
-                            handleDisconnectedState(DetailedState.DISCONNECTED);
-                            setDetailedStateInternal(saveState);
-                        }
-                        configureInterface();
+                    /*
+                     * The connection is fully configured as far as link-level
+                     * connectivity is concerned, but we may still need to obtain
+                     * an IP address.
+                     */
+                    if (wasDisconnectPending) {
+                        DetailedState saveState = getNetworkInfo().getDetailedState();
+                        handleDisconnectedState(DetailedState.DISCONNECTED);
+                        setDetailedStateInternal(saveState);
                     }
+                    configureInterface();
                     mLastBssid = result.BSSID;
                     mLastSsid = mWifiInfo.getSSID();
                     mLastNetworkId = result.networkId;