Merge change 9430

* changes:
  Update docs.
diff --git a/api/current.xml b/api/current.xml
index 1f53be9..b0b9ce65 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -117837,6 +117837,746 @@
 >
 </field>
 </class>
+<class name="SmsManager"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="divideMessage"
+ return="java.util.ArrayList&lt;java.lang.String&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="text" type="java.lang.String">
+</parameter>
+</method>
+<method name="getDefault"
+ return="android.telephony.SmsManager"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="sendDataMessage"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="destinationAddress" type="java.lang.String">
+</parameter>
+<parameter name="scAddress" type="java.lang.String">
+</parameter>
+<parameter name="destinationPort" type="short">
+</parameter>
+<parameter name="data" type="byte[]">
+</parameter>
+<parameter name="sentIntent" type="android.app.PendingIntent">
+</parameter>
+<parameter name="deliveryIntent" type="android.app.PendingIntent">
+</parameter>
+</method>
+<method name="sendMultipartTextMessage"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="destinationAddress" type="java.lang.String">
+</parameter>
+<parameter name="scAddress" type="java.lang.String">
+</parameter>
+<parameter name="parts" type="java.util.ArrayList&lt;java.lang.String&gt;">
+</parameter>
+<parameter name="sentIntents" type="java.util.ArrayList&lt;android.app.PendingIntent&gt;">
+</parameter>
+<parameter name="deliveryIntents" type="java.util.ArrayList&lt;android.app.PendingIntent&gt;">
+</parameter>
+</method>
+<method name="sendTextMessage"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="destinationAddress" type="java.lang.String">
+</parameter>
+<parameter name="scAddress" type="java.lang.String">
+</parameter>
+<parameter name="text" type="java.lang.String">
+</parameter>
+<parameter name="sentIntent" type="android.app.PendingIntent">
+</parameter>
+<parameter name="deliveryIntent" type="android.app.PendingIntent">
+</parameter>
+</method>
+<field name="RESULT_ERROR_GENERIC_FAILURE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="RESULT_ERROR_NO_SERVICE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="RESULT_ERROR_NULL_PDU"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="RESULT_ERROR_RADIO_OFF"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="STATUS_ON_ICC_FREE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="STATUS_ON_ICC_READ"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="STATUS_ON_ICC_SENT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="5"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="STATUS_ON_ICC_UNREAD"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="STATUS_ON_ICC_UNSENT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="7"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="SmsMessage"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="calculateLength"
+ return="int[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="msgBody" type="java.lang.CharSequence">
+</parameter>
+<parameter name="use7bitOnly" type="boolean">
+</parameter>
+</method>
+<method name="calculateLength"
+ return="int[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="messageBody" type="java.lang.String">
+</parameter>
+<parameter name="use7bitOnly" type="boolean">
+</parameter>
+</method>
+<method name="createFromPdu"
+ return="android.telephony.SmsMessage"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pdu" type="byte[]">
+</parameter>
+</method>
+<method name="getDisplayMessageBody"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDisplayOriginatingAddress"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getEmailBody"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getEmailFrom"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getIndexOnIcc"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getIndexOnSim"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+</method>
+<method name="getMessageBody"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getMessageClass"
+ return="android.telephony.SmsMessage.MessageClass"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getOriginatingAddress"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getPdu"
+ return="byte[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getProtocolIdentifier"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getPseudoSubject"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getServiceCenterAddress"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getStatus"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getStatusOnIcc"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getStatusOnSim"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+</method>
+<method name="getSubmitPdu"
+ return="android.telephony.SmsMessage.SubmitPdu"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="scAddress" type="java.lang.String">
+</parameter>
+<parameter name="destinationAddress" type="java.lang.String">
+</parameter>
+<parameter name="message" type="java.lang.String">
+</parameter>
+<parameter name="statusReportRequested" type="boolean">
+</parameter>
+</method>
+<method name="getSubmitPdu"
+ return="android.telephony.SmsMessage.SubmitPdu"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="scAddress" type="java.lang.String">
+</parameter>
+<parameter name="destinationAddress" type="java.lang.String">
+</parameter>
+<parameter name="destinationPort" type="short">
+</parameter>
+<parameter name="data" type="byte[]">
+</parameter>
+<parameter name="statusReportRequested" type="boolean">
+</parameter>
+</method>
+<method name="getTPLayerLengthForPDU"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pdu" type="java.lang.String">
+</parameter>
+</method>
+<method name="getTimestampMillis"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getUserData"
+ return="byte[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isCphsMwiMessage"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isEmail"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isMWIClearMessage"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isMWISetMessage"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isMwiDontStore"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isReplace"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isReplyPathPresent"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isStatusReportMessage"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="ENCODING_16BIT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ENCODING_7BIT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ENCODING_8BIT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ENCODING_UNKNOWN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MAX_USER_DATA_BYTES"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="140"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MAX_USER_DATA_BYTES_WITH_HEADER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="134"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MAX_USER_DATA_SEPTETS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="160"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MAX_USER_DATA_SEPTETS_WITH_HEADER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="153"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="SmsMessage.MessageClass"
+ extends="java.lang.Enum"
+ abstract="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="valueOf"
+ return="android.telephony.SmsMessage.MessageClass"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="name" type="java.lang.String">
+</parameter>
+</method>
+<method name="values"
+ return="android.telephony.SmsMessage.MessageClass[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
+<class name="SmsMessage.SubmitPdu"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<field name="encodedMessage"
+ type="byte[]"
+ transient="false"
+ volatile="false"
+ value="null"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="encodedScAddress"
+ type="byte[]"
+ transient="false"
+ volatile="false"
+ value="null"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
 <class name="TelephonyManager"
  extends="java.lang.Object"
  abstract="false"
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index f101007..008fa36 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -152,11 +152,13 @@
     eglChooseConfig(display, attribs, &config, 1, &numConfigs);
 
     surface = eglCreateWindowSurface(display, config, s.get(), NULL);
-
     context = eglCreateContext(display, config, NULL, NULL);
     eglQuerySurface(display, surface, EGL_WIDTH, &w);
     eglQuerySurface(display, surface, EGL_HEIGHT, &h);
-    eglMakeCurrent(display, surface, surface, context);
+    
+    if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)
+        return NO_INIT;
+    
     mDisplay = display;
     mContext = context;
     mSurface = surface;
diff --git a/cmds/keystore/keymgmt.c b/cmds/keystore/keymgmt.c
index c45b53c..9a1f845 100644
--- a/cmds/keystore/keymgmt.c
+++ b/cmds/keystore/keymgmt.c
@@ -228,6 +228,11 @@
     char keyfile[KEYFILE_LEN];
 
     if (state != UNLOCKED) return -state;
+    if ((strlen(namespace) >= MAX_KEY_NAME_LENGTH) ||
+        (strlen(keyname) >= MAX_KEY_NAME_LENGTH)) {
+        LOGE("keyname is too long.");
+        return -1;
+    }
     sprintf(keyfile, KEYFILE_NAME, namespace, keyname);
     return unlink(keyfile);
 }
@@ -243,12 +248,12 @@
         LOGE("Can not store key with current state %d\n", state);
         return -state;
     }
-    sprintf(keyfile, KEYFILE_NAME, namespace, keyname);
-    // flatten the args
-    if (strlen(keyname) >= MAX_KEY_NAME_LENGTH) {
+    if ((strlen(namespace) >= MAX_KEY_NAME_LENGTH) ||
+        (strlen(keyname) >= MAX_KEY_NAME_LENGTH)) {
         LOGE("keyname is too long.");
         return -1;
     }
+    sprintf(keyfile, KEYFILE_NAME, namespace, keyname);
     strcpy(blob.keyname, keyname);
     blob.value_size = size;
     if (size > MAX_KEY_VALUE_LENGTH) {
@@ -271,6 +276,11 @@
         LOGE("Can not retrieve key value with current state %d\n", state);
         return -state;
     }
+    if ((strlen(namespace) >= MAX_KEY_NAME_LENGTH) ||
+        (strlen(keyname) >= MAX_KEY_NAME_LENGTH)) {
+        LOGE("keyname is too long.");
+        return -1;
+    }
     sprintf(keyfile, KEYFILE_NAME, namespace, keyname);
     ret = load_n_decrypt(keyname, keyfile, &decryptKey, &blob);
     if (!ret) {
@@ -299,6 +309,13 @@
         LOGE("cannot open keystore dir or namespace is null\n");
         return -1;
     }
+
+    if (strlen(namespace) >= MAX_KEY_NAME_LENGTH) {
+        LOGE("namespace is too long.");
+        return -1;
+    }
+
+    reply[0] = 0;
     while ((de = readdir(d))) {
         char *prefix, *name, *keyfile = de->d_name;
         char *context = NULL;
@@ -367,6 +384,7 @@
 
 int reset_keystore()
 {
+    int ret = 0;
     DIR *d;
     struct dirent *de;
 
@@ -374,18 +392,24 @@
         LOGE("cannot open keystore dir\n");
         return -1;
     }
-    while ((de = readdir(d))) unlink(de->d_name);
+    while ((de = readdir(d))) {
+        if (unlink(de->d_name) != 0) ret = -1;
+    }
     closedir(d);
     state = UNINITIALIZED;
-    LOGI("keystore is reset.");
-    return 0;
+    if (ret == 0) {
+        LOGI("keystore is reset.");
+    } else {
+        LOGI("keystore can not be cleaned up entirely.");
+    }
+    return ret;
 }
 
 int init_keystore(const char *dir)
 {
     int fd;
 
-    if (!dir) mkdir(dir, 0770);
+    if (dir) mkdir(dir, 0770);
     if (!dir || chdir(dir)) {
         LOGE("Can not open/create the keystore directory %s\n",
              dir ? dir : "(null)");
diff --git a/cmds/keystore/tests/Android.mk b/cmds/keystore/tests/Android.mk
new file mode 100644
index 0000000..33541cc
--- /dev/null
+++ b/cmds/keystore/tests/Android.mk
@@ -0,0 +1,28 @@
+# 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.
+#
+# define the KEYSTORE_TESTS environment variable to build the test programs
+ifdef KEYSTORE_TESTS
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES:= netkeystore_test.c ../keymgmt.c
+LOCAL_SHARED_LIBRARIES := libcutils libssl
+LOCAL_MODULE:= netkeystore_test
+LOCAL_MODULE_TAGS := optional
+LOCAL_C_INCLUDES := external/openssl/include \
+								frameworks/base/cmds/keystore
+EXTRA_CFLAGS := -g -O0 -DGTEST_OS_LINUX -DGTEST_HAS_STD_STRING
+include $(BUILD_EXECUTABLE)
+
+endif  #KEYSTORE_TESTS
diff --git a/cmds/keystore/tests/netkeystore_test.c b/cmds/keystore/tests/netkeystore_test.c
new file mode 100644
index 0000000..e7e686b
--- /dev/null
+++ b/cmds/keystore/tests/netkeystore_test.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "common.h"
+#include "keymgmt.h"
+
+typedef int FUNC_PTR();
+typedef struct {
+    const char *name;
+    FUNC_PTR *func;
+} TESTFUNC;
+
+#define FUNC_NAME(x) { #x, test_##x }
+#define FUNC_BODY(x) int test_##x()
+
+#define TEST_PASSWD        "12345678"
+#define TEST_NPASSWD    "11111111"
+#define TEST_DIR        "/data/local/tmp/keystore"
+#define READONLY_DIR    "/proc/keystore"
+#define TEST_NAMESPACE    "test"
+#define TEST_KEYNAME    "key"
+#define TEST_KEYNAME2    "key2"
+#define TEST_KEYVALUE    "ANDROID"
+
+void setup()
+{
+    if (init_keystore(TEST_DIR) != 0) {
+        fprintf(stderr, "Can not create the test directory %s\n", TEST_DIR);
+        exit(-1);
+    }
+}
+
+void teardown()
+{
+    reset_keystore();
+    rmdir(TEST_DIR);
+}
+
+FUNC_BODY(init_keystore)
+{
+    if (init_keystore(READONLY_DIR) == 0) return -1;
+
+    return EXIT_SUCCESS;
+}
+
+FUNC_BODY(reset_keystore)
+{
+    chdir("/procx");
+    if (reset_keystore() == 0) return -1;
+    chdir(TEST_DIR);
+    return EXIT_SUCCESS;
+}
+
+FUNC_BODY(get_state)
+{
+    if (get_state() != UNINITIALIZED) return -1;
+    passwd(TEST_PASSWD);
+    if (get_state() != UNLOCKED) return -1;
+    lock();
+    if (get_state() != LOCKED) return -1;
+    reset_keystore();
+    if (get_state() != UNINITIALIZED) return -1;
+    return EXIT_SUCCESS;
+}
+
+FUNC_BODY(passwd)
+{
+    char buf[512];
+
+    if (passwd(" 23432dsfsdf") == 0) return -1;
+    if (passwd("dsfsdf") == 0) return -1;
+    passwd(TEST_PASSWD);
+    lock();
+    if (unlock("55555555") == 0) return -1;
+    if (unlock(TEST_PASSWD) != 0) return -1;
+
+    // change the password
+    sprintf(buf, "%s %s", "klfdjdsklfjg", "abcdefghi");
+    if (passwd(buf) == 0) return -1;
+
+    sprintf(buf, "%s %s", TEST_PASSWD, TEST_NPASSWD);
+    if (passwd(buf) != 0) return -1;
+    lock();
+
+    if (unlock(TEST_PASSWD) == 0) return -1;
+    if (unlock(TEST_NPASSWD) != 0) return -1;
+
+    return EXIT_SUCCESS;
+}
+
+FUNC_BODY(lock)
+{
+    if (lock() == 0) return -1;
+    passwd(TEST_PASSWD);
+    if (lock() != 0) return -1;
+    if (lock() != 0) return -1;
+    return EXIT_SUCCESS;
+}
+
+FUNC_BODY(unlock)
+{
+    int i = MAX_RETRY_COUNT;
+    passwd(TEST_PASSWD);
+    lock();
+    while (i > 1) {
+        if (unlock(TEST_NPASSWD) != --i) return -1;
+    }
+    if (unlock(TEST_NPASSWD) != -1) return -1;
+    return EXIT_SUCCESS;
+}
+
+FUNC_BODY(put_key)
+{
+    int i = 0;
+    char keyname[512];
+
+    if (put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE,
+                strlen(TEST_KEYVALUE)) == 0) return -1;
+    passwd(TEST_PASSWD);
+    if (put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE,
+                strlen(TEST_KEYVALUE)) != 0) return -1;
+
+    for(i = 0; i < 500; i++) keyname[i] = 'K';
+    keyname[i] = 0;
+    if (put_key(TEST_NAMESPACE, keyname, (unsigned char *)TEST_KEYVALUE,
+                strlen(TEST_KEYVALUE)) == 0) return -1;
+    if (put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE,
+                MAX_KEY_VALUE_LENGTH + 1) == 0) return -1;
+    return EXIT_SUCCESS;
+}
+
+FUNC_BODY(get_key)
+{
+    int size;
+    unsigned char data[MAX_KEY_VALUE_LENGTH];
+
+    if (get_key(TEST_NAMESPACE, TEST_KEYNAME, data, &size) == 0) return -1;
+
+    passwd(TEST_PASSWD);
+    put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE,
+            strlen(TEST_KEYVALUE));
+    if (get_key(TEST_NAMESPACE, TEST_KEYNAME, data, &size) != 0) return -1;
+    if (memcmp(data, TEST_KEYVALUE, size) != 0) return -1;
+
+    return EXIT_SUCCESS;
+}
+
+FUNC_BODY(remove_key)
+{
+    if (remove_key(TEST_NAMESPACE, TEST_KEYNAME) == 0) return -1;
+
+    passwd(TEST_PASSWD);
+    if (remove_key(TEST_NAMESPACE, TEST_KEYNAME) == 0) return -1;
+
+    put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE,
+            strlen(TEST_KEYVALUE));
+    if (remove_key(TEST_NAMESPACE, TEST_KEYNAME) != 0) return -1;
+
+    return EXIT_SUCCESS;
+}
+
+FUNC_BODY(list_keys)
+{
+    int i;
+    char buf[128];
+    char reply[BUFFER_MAX];
+
+    for(i = 0; i < 100; i++) buf[i] = 'K';
+    buf[i] = 0;
+
+    if (list_keys(TEST_NAMESPACE, reply) == 0) return -1;
+
+    passwd(TEST_PASSWD);
+    if (list_keys(buf, reply) == 0) return -1;
+
+    if (list_keys(TEST_NAMESPACE, reply) != 0) return -1;
+    if (strcmp(reply, "") != 0) return -1;
+
+    put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE,
+            strlen(TEST_KEYVALUE));
+    if (list_keys(TEST_NAMESPACE, reply) != 0) return -1;
+    if (strcmp(reply, TEST_KEYNAME) != 0) return -1;
+
+    put_key(TEST_NAMESPACE, TEST_KEYNAME2, (unsigned char *)TEST_KEYVALUE,
+            strlen(TEST_KEYVALUE));
+
+    if (list_keys(TEST_NAMESPACE, reply) != 0) return -1;
+    sprintf(buf, "%s %s", TEST_KEYNAME2, TEST_KEYNAME);
+    if (strcmp(reply, buf) != 0) return -1;
+
+    return EXIT_SUCCESS;
+}
+
+TESTFUNC all_tests[] = {
+    FUNC_NAME(init_keystore),
+    FUNC_NAME(reset_keystore),
+    FUNC_NAME(get_state),
+    FUNC_NAME(passwd),
+    FUNC_NAME(lock),
+    FUNC_NAME(unlock),
+    FUNC_NAME(put_key),
+    FUNC_NAME(get_key),
+    FUNC_NAME(remove_key),
+    FUNC_NAME(list_keys),
+};
+
+int main(int argc, char **argv) {
+    int i, ret;
+    for (i = 0 ; i < (int)(sizeof(all_tests)/sizeof(TESTFUNC)) ; ++i) {
+        setup();
+        if ((ret = all_tests[i].func()) != EXIT_SUCCESS) {
+            fprintf(stderr, "ERROR in function %s\n", all_tests[i].name);
+            return ret;
+        } else {
+            fprintf(stderr, "function %s PASSED!\n", all_tests[i].name);
+        }
+        teardown();
+    }
+    return EXIT_SUCCESS;
+}
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 4dd2433..18e4a528 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -903,6 +903,12 @@
                     getContext().startActivity(mVoiceWebSearchIntent);
                 } else if (mSearchable.getVoiceSearchLaunchRecognizer()) {
                     Intent appSearchIntent = createVoiceAppSearchIntent(mVoiceAppSearchIntent);
+                    
+                    // Stop the existing search before starting voice search, or else we'll end
+                    // up showing the search dialog again once we return to the app.
+                    ((SearchManager) getContext().getSystemService(Context.SEARCH_SERVICE)).
+                            stopSearch();
+                    
                     getContext().startActivity(appSearchIntent);
                 }
             } catch (ActivityNotFoundException e) {
@@ -1238,11 +1244,11 @@
         // ensure the icons will work for global search
         cv.put(SearchManager.SUGGEST_COLUMN_ICON_1,
                         wrapIconForPackage(
-                                source,
+                                mSearchable.getSuggestPackage(),
                                 getColumnString(c, SearchManager.SUGGEST_COLUMN_ICON_1)));
         cv.put(SearchManager.SUGGEST_COLUMN_ICON_2,
                         wrapIconForPackage(
-                                source,
+                                mSearchable.getSuggestPackage(),
                                 getColumnString(c, SearchManager.SUGGEST_COLUMN_ICON_2)));
 
         // the rest can be passed through directly
@@ -1281,11 +1287,11 @@
      * Wraps an icon for a particular package.  If the icon is a resource id, it is converted into
      * an android.resource:// URI.
      *
-     * @param source The source of the icon
+     * @param packageName The source of the icon
      * @param icon The icon retrieved from a suggestion column
      * @return An icon string appropriate for the package.
      */
-    private String wrapIconForPackage(ComponentName source, String icon) {
+    private String wrapIconForPackage(String packageName, String icon) {
         if (icon == null || icon.length() == 0 || "0".equals(icon)) {
             // SearchManager specifies that null or zero can be returned to indicate
             // no icon. We also allow empty string.
@@ -1293,7 +1299,6 @@
         } else if (!Character.isDigit(icon.charAt(0))){
             return icon;
         } else {
-            String packageName = source.getPackageName();
             return new Uri.Builder()
                     .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
                     .authority(packageName)
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index f8316a5..1ec7fb38 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -30,14 +30,13 @@
      * The following 128 bit values are calculated as:
      *  uuid * 2^96 + BASE_UUID
      */
-    public static final UUID AudioSink = UUID.fromString("0000110A-0000-1000-8000-00805F9B34FB");
-    public static final UUID AudioSource = UUID.fromString("0000110B-0000-1000-8000-00805F9B34FB");
+    public static final UUID AudioSink = UUID.fromString("0000110B-0000-1000-8000-00805F9B34FB");
+    public static final UUID AudioSource = UUID.fromString("0000110A-0000-1000-8000-00805F9B34FB");
     public static final UUID AdvAudioDist = UUID.fromString("0000110D-0000-1000-8000-00805F9B34FB");
     public static final UUID HSP       = UUID.fromString("00001108-0000-1000-8000-00805F9B34FB");
-    public static final UUID HeadsetHS = UUID.fromString("00001131-0000-1000-8000-00805F9B34FB");
-    public static final UUID Handsfree  = UUID.fromString("0000111e-0000-1000-8000-00805F9B34FB");
-    public static final UUID HandsfreeAudioGateway
-                                          = UUID.fromString("0000111f-0000-1000-8000-00805F9B34FB");
+    public static final UUID Handsfree  = UUID.fromString("0000111E-0000-1000-8000-00805F9B34FB");
+    public static final UUID AvrcpController =
+                                          UUID.fromString("0000110E-0000-1000-8000-00805F9B34FB");
 
     public static boolean isAudioSource(UUID uuid) {
         return uuid.equals(AudioSource);
@@ -56,7 +55,10 @@
     }
 
     public static boolean isHeadset(UUID uuid) {
-        return uuid.equals(HSP) || uuid.equals(HeadsetHS);
+        return uuid.equals(HSP);
+    }
+
+    public static boolean isAvrcpController(UUID uuid) {
+        return uuid.equals(AvrcpController);
     }
 }
-
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 5c7b01f..8ebe093 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -637,12 +637,13 @@
      *  mRetData. */
     private native final int loadResourceBagValue(int ident, int bagEntryId, TypedValue outValue,
                                                boolean resolve);
-    /*package*/ static final int STYLE_NUM_ENTRIES = 5;
+    /*package*/ static final int STYLE_NUM_ENTRIES = 6;
     /*package*/ static final int STYLE_TYPE = 0;
     /*package*/ static final int STYLE_DATA = 1;
     /*package*/ static final int STYLE_ASSET_COOKIE = 2;
     /*package*/ static final int STYLE_RESOURCE_ID = 3;
     /*package*/ static final int STYLE_CHANGING_CONFIGURATIONS = 4;
+    /*package*/ static final int STYLE_DENSITY = 5;
     /*package*/ native static final boolean applyStyle(int theme,
             int defStyleAttr, int defStyleRes, int xmlParser,
             int[] inAttrs, int[] outValues, int[] outIndices);
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index 3a32c03..016ee7f 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -654,6 +654,7 @@
         outValue.assetCookie = data[index+AssetManager.STYLE_ASSET_COOKIE];
         outValue.resourceId = data[index+AssetManager.STYLE_RESOURCE_ID];
         outValue.changingConfigurations = data[index+AssetManager.STYLE_CHANGING_CONFIGURATIONS];
+        outValue.density = data[index+AssetManager.STYLE_DENSITY];
         if (type == TypedValue.TYPE_STRING) {
             outValue.string = loadStringValueAt(index);
         }
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index dc84d1f..d982777 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -402,13 +402,14 @@
 
         boolean authorized = false;
         UUID uuid = UUID.fromString(deviceUuid);
-        if (mBluetoothService.isEnabled() && BluetoothUuid.isAudioSink(uuid)) {
+        if (mBluetoothService.isEnabled() &&
+                (BluetoothUuid.isAudioSink(uuid) || BluetoothUuid.isAvrcpController(uuid))) {
             BluetoothA2dp a2dp = new BluetoothA2dp(mContext);
             authorized = a2dp.getSinkPriority(address) > BluetoothA2dp.PRIORITY_OFF;
             if (authorized) {
-                Log.i(TAG, "Allowing incoming A2DP connection from " + address);
+                Log.i(TAG, "Allowing incoming A2DP / AVRCP connection from " + address);
             } else {
-                Log.i(TAG, "Rejecting incoming A2DP connection from " + address);
+                Log.i(TAG, "Rejecting incoming A2DP / AVRCP connection from " + address);
             }
         } else {
             Log.i(TAG, "Rejecting incoming " + deviceUuid + " connection from " + address);
diff --git a/core/java/android/server/search/SearchableInfo.java b/core/java/android/server/search/SearchableInfo.java
index 045b0c2..69ef98c 100644
--- a/core/java/android/server/search/SearchableInfo.java
+++ b/core/java/android/server/search/SearchableInfo.java
@@ -103,6 +103,14 @@
     }
 
     /**
+     * Gets the name of the package where the suggestion provider lives,
+     * or {@code null}.
+     */
+    public String getSuggestPackage() {
+        return mSuggestProviderPackage;
+    }
+
+    /**
      * Gets the component name of the searchable activity.
      */
     public ComponentName getSearchActivity() {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 7ed2712..829f68e 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2983,6 +2983,8 @@
      * @param enabled True if this view is enabled, false otherwise.
      */
     public void setEnabled(boolean enabled) {
+        if (enabled == isEnabled()) return;
+
         setFlags(enabled ? ENABLED : DISABLED, ENABLED_MASK);
 
         /*
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 884950f..0d44b4e 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -21,7 +21,6 @@
 
 import android.graphics.Canvas;
 import android.graphics.PixelFormat;
-import android.graphics.Point;
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.graphics.Region;
@@ -1220,6 +1219,8 @@
                         if (mTranslator != null) {
                             mTranslator.translateCanvas(canvas);
                         }
+                        canvas.setScreenDensity(scalingRequired
+                                ? DisplayMetrics.DENSITY_DEVICE : 0);
                         mView.draw(canvas);
                         if (Config.DEBUG && ViewDebug.consistencyCheckEnabled) {
                             mView.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_DRAWING);
@@ -1328,6 +1329,8 @@
                     if (mTranslator != null) {
                         mTranslator.translateCanvas(canvas);
                     }
+                    canvas.setScreenDensity(scalingRequired
+                            ? DisplayMetrics.DENSITY_DEVICE : 0);
                     mView.draw(canvas);
                 } finally {
                     mAttachInfo.mIgnoreDirtyState = false;
diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java
index 7bc154b..f22adb7 100644
--- a/core/java/android/webkit/WebTextView.java
+++ b/core/java/android/webkit/WebTextView.java
@@ -81,6 +81,10 @@
     // True if the most recent drag event has caused either the TextView to
     // scroll or the web page to scroll.  Gets reset after a touch down.
     private boolean         mScrolled;
+    // Gets set to true when the the IME jumps to the next textfield.  When this
+    // happens, the next time the user hits a key it is okay for the focus
+    // pointer to not match the WebTextView's node pointer
+    private boolean         mOkayForFocusNotToMatch;
     // Array to store the final character added in onTextChanged, so that its
     // KeyEvents may be determined.
     private char[]          mCharacter = new char[1];
@@ -99,7 +103,6 @@
         super(context);
         mWebView = webView;
         mMaxLength = -1;
-        setImeOptions(EditorInfo.IME_ACTION_NONE);
     }
 
     @Override
@@ -125,8 +128,8 @@
                 isArrowKey = true;
                 break;
         }
-
-        if (!isArrowKey && mWebView.nativeFocusNodePointer() != mNodePointer) {
+        if (!isArrowKey && !mOkayForFocusNotToMatch
+                && mWebView.nativeFocusNodePointer() != mNodePointer) {
             mWebView.nativeClearCursor();
             // Do not call remove() here, which hides the soft keyboard.  If
             // the soft keyboard is being displayed, the user will still want
@@ -135,6 +138,9 @@
             mWebView.requestFocus();
             return mWebView.dispatchKeyEvent(event);
         }
+        // After a jump to next textfield and the first key press, the cursor
+        // and focus will once again match, so reset this value.
+        mOkayForFocusNotToMatch = false;
 
         Spannable text = (Spannable) getText();
         int oldLength = text.length();
@@ -305,6 +311,36 @@
     }
 
     @Override
+    public void onEditorAction(int actionCode) {
+        switch (actionCode) {
+        case EditorInfo.IME_ACTION_NEXT:
+            mWebView.nativeMoveCursorToNextTextInput();
+            // Preemptively rebuild the WebTextView, so that the action will
+            // be set properly.
+            mWebView.rebuildWebTextView();
+            // Since the cursor will no longer be in the same place as the
+            // focus, set the focus controller back to inactive
+            mWebView.setFocusControllerInactive();
+            mOkayForFocusNotToMatch = true;
+            break;
+        case EditorInfo.IME_ACTION_DONE:
+            super.onEditorAction(actionCode);
+            break;
+        case EditorInfo.IME_ACTION_GO:
+            // Send an enter and hide the soft keyboard
+            InputMethodManager.getInstance(mContext)
+                    .hideSoftInputFromWindow(getWindowToken(), 0);
+            sendDomEvent(new KeyEvent(KeyEvent.ACTION_DOWN,
+                    KeyEvent.KEYCODE_ENTER));
+            sendDomEvent(new KeyEvent(KeyEvent.ACTION_UP,
+                    KeyEvent.KEYCODE_ENTER));
+
+        default:
+            break;
+        }
+    }
+
+    @Override
     protected void onSelectionChanged(int selStart, int selEnd) {
         if (mWebView != null) {
             if (DebugFlags.WEB_TEXT_VIEW) {
@@ -659,10 +695,26 @@
     public void setSingleLine(boolean single) {
         int inputType = EditorInfo.TYPE_CLASS_TEXT
                 | EditorInfo.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT;
-        if (!single) {
+        if (single) {
+            int action = mWebView.nativeTextFieldAction();
+            switch (action) {
+            // Keep in sync with CachedRoot::ImeAction
+            case 0: // NEXT
+                setImeOptions(EditorInfo.IME_ACTION_NEXT);
+                break;
+            case 1: // GO
+                setImeOptions(EditorInfo.IME_ACTION_GO);
+                break;
+            case -1: // FAILURE
+            case 2: // DONE
+                setImeOptions(EditorInfo.IME_ACTION_DONE);
+                break;
+            }
+        } else {
             inputType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE
                     | EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES
                     | EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT;
+            setImeOptions(EditorInfo.IME_ACTION_NONE);
         }
         mSingle = single;
         setHorizontallyScrolling(single);
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 05a7806..3b81eed 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2292,13 +2292,13 @@
 
     // Scale from content to view coordinates, and pin.
     // Also called by jni webview.cpp
-    private void setContentScrollBy(int cx, int cy, boolean animate) {
+    private boolean setContentScrollBy(int cx, int cy, boolean animate) {
         if (mDrawHistory) {
             // disallow WebView to change the scroll position as History Picture
             // is used in the view system.
             // TODO: as we switchOutDrawHistory when trackball or navigation
             // keys are hit, this should be safe. Right?
-            return;
+            return false;
         }
         cx = contentToView(cx);
         cy = contentToView(cy);
@@ -2315,11 +2315,9 @@
             // FIXME: Why do we only scroll horizontally if there is no
             // vertical scroll?
 //                Log.d(LOGTAG, "setContentScrollBy cy=" + cy);
-            if (cy == 0 && cx != 0) {
-                pinScrollBy(cx, 0, animate, 0);
-            }
+            return cy == 0 && cx != 0 && pinScrollBy(cx, 0, animate, 0);
         } else {
-            pinScrollBy(cx, cy, animate, 0);
+            return pinScrollBy(cx, cy, animate, 0);
         }
     }
 
@@ -3123,7 +3121,7 @@
      * mWebTextView to have the appropriate properties, such as password,
      * multiline, and what text it contains.  It also removes it if necessary.
      */
-    private void rebuildWebTextView() {
+    /* package */ void rebuildWebTextView() {
         // If the WebView does not have focus, do nothing until it gains focus.
         if (!hasFocus() && (null == mWebTextView || !mWebTextView.hasFocus())
                 || (mTouchMode >= FIRST_SCROLL_ZOOM
@@ -3385,7 +3383,8 @@
         } else if (nativeCursorIsTextInput()) {
             // This message will put the node in focus, for the DOM's notion
             // of focus, and make the focuscontroller active
-            mWebViewCore.sendMessage(EventHub.CLICK);
+            mWebViewCore.sendMessage(EventHub.CLICK, nativeCursorFramePointer(),
+                    nativeCursorNodePointer());
             // This will bring up the WebTextView and put it in focus, for
             // our view system's notion of focus
             rebuildWebTextView();
@@ -3626,7 +3625,7 @@
      * not draw the blinking cursor.  It gets set to "active" to draw the cursor
      * in WebViewCore.cpp, when the WebCore thread receives key events/clicks.
      */
-    private void setFocusControllerInactive() {
+    /* package */ void setFocusControllerInactive() {
         // Do not need to also check whether mWebViewCore is null, because
         // mNativeClass is only set if mWebViewCore is non null
         if (mNativeClass == 0) return;
@@ -3813,6 +3812,8 @@
                 } else {
                     mTouchMode = TOUCH_INIT_MODE;
                     mPreventDrag = mForwardTouchEvents;
+                    mWebViewCore.sendMessage(
+                            EventHub.UPDATE_FRAME_CACHE_IF_LOADING);
                     if (mLogEvent && eventTime - mLastTouchUpTime < 1000) {
                         EventLog.writeEvent(EVENT_LOG_DOUBLE_TAP_DURATION,
                                 (eventTime - mLastTouchUpTime), eventTime);
@@ -3983,6 +3984,7 @@
                 switch (mTouchMode) {
                     case TOUCH_DOUBLE_TAP_MODE: // double tap
                         mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS);
+                        mTouchMode = TOUCH_DONE_MODE;
                         doDoubleTap();
                         break;
                     case TOUCH_INIT_MODE: // tap
@@ -4680,7 +4682,7 @@
             // mLastTouchX and mLastTouchY are the point in the current viewport
             int contentX = viewToContent((int) mLastTouchX + mScrollX);
             int contentY = viewToContent((int) mLastTouchY + mScrollY);
-            int left = nativeGetBlockLeftEdge(contentX, contentY);
+            int left = nativeGetBlockLeftEdge(contentX, contentY, mActualScale);
             if (left != NO_LEFTEDGE) {
                 // add a 5pt padding to the left edge. Re-calculate the zoom
                 // center so that the new scroll x will be on the left edge.
@@ -5627,6 +5629,7 @@
     private native void     nativeHideCursor();
     private native String   nativeImageURI(int x, int y);
     private native void     nativeInstrumentReport();
+    /* package */ native void nativeMoveCursorToNextTextInput();
     // return true if the page has been scrolled
     private native boolean  nativeMotionUp(int x, int y, int slop);
     // returns false if it handled the key
@@ -5644,6 +5647,8 @@
     private native void     nativeSetFindIsDown();
     private native void     nativeSetFollowedLink(boolean followed);
     private native void     nativeSetHeightCanMeasure(boolean measure);
+    // Returns a value corresponding to CachedFrame::ImeAction
+    /* package */ native int  nativeTextFieldAction();
     private native int      nativeTextGeneration();
     // Never call this version except by updateCachedTextfield(String) -
     // we always want to pass in our generation number.
@@ -5652,5 +5657,5 @@
     private native void     nativeUpdatePluginReceivesEvents();
     // return NO_LEFTEDGE means failure.
     private static final int NO_LEFTEDGE = -1;
-    private native int      nativeGetBlockLeftEdge(int x, int y);
+    private native int      nativeGetBlockLeftEdge(int x, int y, float scale);
 }
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 8ec8174..2f9e153 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -648,6 +648,7 @@
     }
 
         static final String[] HandlerDebugString = {
+            "UPDATE_FRAME_CACHE_IF_LOADING", // = 98
             "SCROLL_TEXT_INPUT", // = 99
             "LOAD_URL", // = 100;
             "STOP_LOADING", // = 101;
@@ -699,6 +700,7 @@
 
     class EventHub {
         // Message Ids
+        static final int UPDATE_FRAME_CACHE_IF_LOADING = 98;
         static final int SCROLL_TEXT_INPUT = 99;
         static final int LOAD_URL = 100;
         static final int STOP_LOADING = 101;
@@ -805,10 +807,11 @@
                 @Override
                 public void handleMessage(Message msg) {
                     if (DebugFlags.WEB_VIEW_CORE) {
-                        Log.v(LOGTAG, (msg.what < SCROLL_TEXT_INPUT || msg.what
+                        Log.v(LOGTAG, (msg.what < UPDATE_FRAME_CACHE_IF_LOADING
+                                || msg.what
                                 > FREE_MEMORY ? Integer.toString(msg.what)
                                 : HandlerDebugString[msg.what
-                                        - SCROLL_TEXT_INPUT])
+                                        - UPDATE_FRAME_CACHE_IF_LOADING])
                                 + " arg1=" + msg.arg1 + " arg2=" + msg.arg2
                                 + " obj=" + msg.obj);
                     }
@@ -825,6 +828,10 @@
                             mNativeClass = 0;
                             break;
 
+                        case UPDATE_FRAME_CACHE_IF_LOADING:
+                            nativeUpdateFrameCacheIfLoading();
+                            break;
+
                         case SCROLL_TEXT_INPUT:
                             nativeScrollFocusedTextInput(msg.arg1, msg.arg2);
                             break;
@@ -1938,6 +1945,8 @@
                 WebView.CLEAR_TEXT_ENTRY).sendToTarget();
     }
 
+    private native void nativeUpdateFrameCacheIfLoading();
+
     /**
      * Scroll the focused textfield to (x, y) in document space
      */
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 6a9bcfb..b8f0a7e 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -463,6 +463,7 @@
         if (matrix == null && !mMatrix.isIdentity() ||
                 matrix != null && !mMatrix.equals(matrix)) {
             mMatrix.set(matrix);
+            configureBounds();
             invalidate();
         }
     }
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index c16a75e..dc72008 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -464,13 +464,22 @@
                                           SkCanvas* canvas, SkBitmap* bitmap,
                                           jfloat left, jfloat top,
                                           SkPaint* paint, jint canvasDensity,
-                                          jint bitmapDensity) {
+                                          jint screenDensity, jint bitmapDensity) {
         SkScalar left_ = SkFloatToScalar(left);
         SkScalar top_ = SkFloatToScalar(top);
 
         if (canvasDensity == bitmapDensity || canvasDensity == 0
                 || bitmapDensity == 0) {
-            canvas->drawBitmap(*bitmap, left_, top_, paint);
+            if (screenDensity != 0 && screenDensity != bitmapDensity) {
+                SkPaint filteredPaint;
+                if (paint) {
+                    filteredPaint = *paint;
+                }
+                filteredPaint.setFilterBitmap(true);
+                canvas->drawBitmap(*bitmap, left_, top_, &filteredPaint);
+            } else {
+                canvas->drawBitmap(*bitmap, left_, top_, paint);
+            }
         } else {
             canvas->save();
             SkScalar scale = SkFloatToScalar(canvasDensity / (float)bitmapDensity);
@@ -490,30 +499,45 @@
     }
 
     static void doDrawBitmap(JNIEnv* env, SkCanvas* canvas, SkBitmap* bitmap,
-                        jobject srcIRect, const SkRect& dst, SkPaint* paint) {
+                        jobject srcIRect, const SkRect& dst, SkPaint* paint,
+                        jint screenDensity, jint bitmapDensity) {
         SkIRect    src, *srcPtr = NULL;
 
         if (NULL != srcIRect) {
             GraphicsJNI::jrect_to_irect(env, srcIRect, &src);
             srcPtr = &src;
         }
-        canvas->drawBitmapRect(*bitmap, srcPtr, dst, paint);
+        
+        if (screenDensity != 0 && screenDensity != bitmapDensity) {
+            SkPaint filteredPaint;
+            if (paint) {
+                filteredPaint = *paint;
+            }
+            filteredPaint.setFilterBitmap(true);
+            canvas->drawBitmapRect(*bitmap, srcPtr, dst, &filteredPaint);
+        } else {
+            canvas->drawBitmapRect(*bitmap, srcPtr, dst, paint);
+        }
     }
 
     static void drawBitmapRF(JNIEnv* env, jobject, SkCanvas* canvas,
                              SkBitmap* bitmap, jobject srcIRect,
-                             jobject dstRectF, SkPaint* paint) {
+                             jobject dstRectF, SkPaint* paint,
+                             jint screenDensity, jint bitmapDensity) {
         SkRect      dst;
         GraphicsJNI::jrectf_to_rect(env, dstRectF, &dst);
-        doDrawBitmap(env, canvas, bitmap, srcIRect, dst, paint);
+        doDrawBitmap(env, canvas, bitmap, srcIRect, dst, paint,
+                screenDensity, bitmapDensity);
     }
     
     static void drawBitmapRR(JNIEnv* env, jobject, SkCanvas* canvas,
                              SkBitmap* bitmap, jobject srcIRect,
-                             jobject dstRect, SkPaint* paint) {
+                             jobject dstRect, SkPaint* paint,
+                             jint screenDensity, jint bitmapDensity) {
         SkRect      dst;
         GraphicsJNI::jrect_to_rect(env, dstRect, &dst);
-        doDrawBitmap(env, canvas, bitmap, srcIRect, dst, paint);
+        doDrawBitmap(env, canvas, bitmap, srcIRect, dst, paint,
+                screenDensity, bitmapDensity);
     }
     
     static void drawBitmapArray(JNIEnv* env, jobject, SkCanvas* canvas,
@@ -907,11 +931,11 @@
     {"native_drawRoundRect","(ILandroid/graphics/RectF;FFI)V",
         (void*) SkCanvasGlue::drawRoundRect},
     {"native_drawPath","(III)V", (void*) SkCanvasGlue::drawPath},
-    {"native_drawBitmap","(IIFFIII)V",
+    {"native_drawBitmap","(IIFFIIII)V",
         (void*) SkCanvasGlue::drawBitmap__BitmapFFPaint},
-    {"native_drawBitmap","(IILandroid/graphics/Rect;Landroid/graphics/RectF;I)V",
+    {"native_drawBitmap","(IILandroid/graphics/Rect;Landroid/graphics/RectF;III)V",
         (void*) SkCanvasGlue::drawBitmapRF},
-    {"native_drawBitmap","(IILandroid/graphics/Rect;Landroid/graphics/Rect;I)V",
+    {"native_drawBitmap","(IILandroid/graphics/Rect;Landroid/graphics/Rect;III)V",
         (void*) SkCanvasGlue::drawBitmapRR},
     {"native_drawBitmap", "(I[IIIFFIIZI)V",
     (void*)SkCanvasGlue::drawBitmapArray},
diff --git a/core/jni/android/graphics/MaskFilter.cpp b/core/jni/android/graphics/MaskFilter.cpp
index e6048cd..0f8dff1 100644
--- a/core/jni/android/graphics/MaskFilter.cpp
+++ b/core/jni/android/graphics/MaskFilter.cpp
@@ -4,15 +4,23 @@
 
 #include <jni.h>
 
+static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) {
+    if (NULL == ptr) {
+        doThrowIAE(env);
+    }
+}
+
 class SkMaskFilterGlue {
 public:
     static void destructor(JNIEnv* env, jobject, SkMaskFilter* filter) {
-        SkASSERT(filter);
-        filter->unref();
+        filter->safeUnref();
     }
 
     static SkMaskFilter* createBlur(JNIEnv* env, jobject, float radius, int blurStyle) {
-        return SkBlurMaskFilter::Create(SkFloatToScalar(radius), (SkBlurMaskFilter::BlurStyle)blurStyle);
+        SkMaskFilter* filter = SkBlurMaskFilter::Create(SkFloatToScalar(radius),
+                                        (SkBlurMaskFilter::BlurStyle)blurStyle);
+        ThrowIAE_IfNull(env, filter);
+        return filter;
     }
  
     static SkMaskFilter* createEmboss(JNIEnv* env, jobject, jfloatArray dirArray, float ambient, float specular, float radius) {
@@ -24,8 +32,12 @@
             direction[i] = SkFloatToScalar(values[i]);
         }
 
-        return SkBlurMaskFilter::CreateEmboss(direction, SkFloatToScalar(ambient),
-                                              SkFloatToScalar(specular), SkFloatToScalar(radius));
+        SkMaskFilter* filter =  SkBlurMaskFilter::CreateEmboss(direction,
+                                                      SkFloatToScalar(ambient),
+                                                      SkFloatToScalar(specular),
+                                                      SkFloatToScalar(radius));
+        ThrowIAE_IfNull(env, filter);
+        return filter;
     }
 };
 
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index b28eb90..b09c62b 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -43,25 +43,23 @@
 
 static void Shader_destructor(JNIEnv* env, jobject, SkShader* shader)
 {
-    SkASSERT(shader != NULL);
-    shader->unref();
+    shader->safeUnref();
 }
 
 static bool Shader_getLocalMatrix(JNIEnv* env, jobject, const SkShader* shader, SkMatrix* matrix)
 {
-    SkASSERT(shader != NULL);    
-    return shader->getLocalMatrix(matrix);
+    return shader ? shader->getLocalMatrix(matrix) : false;
 }
  
 static void Shader_setLocalMatrix(JNIEnv* env, jobject, SkShader* shader, const SkMatrix* matrix)
 {
-    SkASSERT(shader != NULL);
-    
-    if (NULL == matrix) {
-        shader->resetLocalMatrix();
-    }
-    else {
-        shader->setLocalMatrix(*matrix);
+    if (shader) {
+        if (NULL == matrix) {
+            shader->resetLocalMatrix();
+        }
+        else {
+            shader->setLocalMatrix(*matrix);
+        }
     }
 }
 
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 59f4067..66b2506 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -74,12 +74,13 @@
 }
 
 enum {
-    STYLE_NUM_ENTRIES = 5,
+    STYLE_NUM_ENTRIES = 6,
     STYLE_TYPE = 0,
     STYLE_DATA = 1,
     STYLE_ASSET_COOKIE = 2,
     STYLE_RESOURCE_ID = 3,
-    STYLE_CHANGING_CONFIGURATIONS = 4
+    STYLE_CHANGING_CONFIGURATIONS = 4,
+    STYLE_DENSITY = 5
 };
 
 static jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table,
@@ -896,6 +897,7 @@
     ResTable::Theme* theme = (ResTable::Theme*)themeToken;
     const ResTable& res = theme->getResTable();
     ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
+    ResTable_config config;
     Res_value value;
 
     const jsize NI = env->GetArrayLength(attrs);
@@ -995,6 +997,7 @@
         value.dataType = Res_value::TYPE_NULL;
         value.data = 0;
         typeSetFlags = 0;
+        config.density = 0;
 
         // Skip through XML attributes until the end or the next possible match.
         while (ix < NX && curIdent > curXmlAttr) {
@@ -1042,7 +1045,8 @@
         if (value.dataType != Res_value::TYPE_NULL) {
             // Take care of resolving the found resource to its final value.
             //printf("Resolving attribute reference\n");
-            ssize_t newBlock = theme->resolveAttributeReference(&value, block, &resid, &typeSetFlags);
+            ssize_t newBlock = theme->resolveAttributeReference(&value, block,
+                    &resid, &typeSetFlags, &config);
             if (newBlock >= 0) block = newBlock;
         } else {
             // If we still don't have a value for this attribute, try to find
@@ -1051,7 +1055,8 @@
             ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
             if (newBlock >= 0) {
                 //printf("Resolving resource reference\n");
-                newBlock = res.resolveReference(&value, block, &resid, &typeSetFlags);
+                newBlock = res.resolveReference(&value, block, &resid,
+                        &typeSetFlags, &config);
                 if (newBlock >= 0) block = newBlock;
             }
         }
@@ -1070,6 +1075,7 @@
             block != kXmlBlock ? (jint)res.getTableCookie(block) : (jint)-1;
         dest[STYLE_RESOURCE_ID] = resid;
         dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
+        dest[STYLE_DENSITY] = config.density;
         
         if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
             indicesIdx++;
@@ -1108,6 +1114,7 @@
     }
     const ResTable& res(am->getResources());
     ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
+    ResTable_config config;
     Res_value value;
     
     const jsize NI = env->GetArrayLength(attrs);
@@ -1160,6 +1167,7 @@
         value.dataType = Res_value::TYPE_NULL;
         value.data = 0;
         typeSetFlags = 0;
+        config.density = 0;
         
         // Skip through XML attributes until the end or the next possible match.
         while (ix < NX && curIdent > curXmlAttr) {
@@ -1179,7 +1187,8 @@
         if (value.dataType != Res_value::TYPE_NULL) {
             // Take care of resolving the found resource to its final value.
             //printf("Resolving attribute reference\n");
-            ssize_t newBlock = res.resolveReference(&value, block, &resid, &typeSetFlags);
+            ssize_t newBlock = res.resolveReference(&value, block, &resid,
+                    &typeSetFlags, &config);
             if (newBlock >= 0) block = newBlock;
         }
         
@@ -1197,6 +1206,7 @@
             block != kXmlBlock ? (jint)res.getTableCookie(block) : (jint)-1;
         dest[STYLE_RESOURCE_ID] = resid;
         dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
+        dest[STYLE_DENSITY] = config.density;
         
         if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
             indicesIdx++;
@@ -1250,6 +1260,7 @@
         return JNI_FALSE;
     }
     const ResTable& res(am->getResources());
+    ResTable_config config;
     Res_value value;
     ssize_t block;
     
@@ -1276,13 +1287,15 @@
     while (i < NV && arrayEnt < endArrayEnt) {
         block = arrayEnt->stringBlock;
         typeSetFlags = arrayTypeSetFlags;
+        config.density = 0;
         value = arrayEnt->map.value;
                 
         uint32_t resid = 0;
         if (value.dataType != Res_value::TYPE_NULL) {
             // Take care of resolving the found resource to its final value.
             //printf("Resolving attribute reference\n");
-            ssize_t newBlock = res.resolveReference(&value, block, &resid, &typeSetFlags);
+            ssize_t newBlock = res.resolveReference(&value, block, &resid,
+                    &typeSetFlags, &config);
             if (newBlock >= 0) block = newBlock;
         }
 
@@ -1299,6 +1312,7 @@
         dest[STYLE_ASSET_COOKIE] = (jint)res.getTableCookie(block);
         dest[STYLE_RESOURCE_ID] = resid;
         dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
+        dest[STYLE_DENSITY] = config.density;
         dest += STYLE_NUM_ENTRIES;
         i+= STYLE_NUM_ENTRIES;
         arrayEnt++;
diff --git a/core/res/res/layout/preference_dialog.xml b/core/res/res/layout/preference_dialog.xml
new file mode 100644
index 0000000..5cf0f6e
--- /dev/null
+++ b/core/res/res/layout/preference_dialog.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2006 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.
+-->
+
+<!-- Layout used by DialogPreference widgets. This is inflated inside 
+        android.R.layout.preference. -->
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_marginRight="4dip"
+    android:layout_gravity="center_vertical"
+    android:background="@drawable/btn_circle"
+    android:src="@drawable/ic_btn_round_more" />
+
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 549b668..558d91e 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -916,12 +916,12 @@
         you.</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_readPhoneState">read phone state</string>
+    <string name="permlab_readPhoneState">read phone state and identity</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_readPhoneState">Allows the application to access the phone
         features of the device.  An application with this permission can determine the phone
-        number of this phone, whether a call is active, the number that call is connected to
-        and the like.</string>
+        number and serial number of this phone, whether a call is active, the number that call
+        is connected to and the like.</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_wakeLock">prevent phone from sleeping</string>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 6df8b0a..4aa4210 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -659,12 +659,12 @@
     </style>
     
     <style name="Preference.PreferenceScreen">
-        <item name="android:widgetLayout">@android:layout/preferences</item>
     </style>
 
     <style name="Preference.DialogPreference">
         <item name="android:positiveButtonText">@android:string/ok</item>
         <item name="android:negativeButtonText">@android:string/cancel</item>
+        <item name="android:widgetLayout">@android:layout/preference_dialog</item>
     </style>
     
     <style name="Preference.DialogPreference.YesNoPreference">
@@ -680,6 +680,7 @@
         <item name="android:ringtoneType">ringtone</item>
         <item name="android:showSilent">true</item>
         <item name="android:showDefault">true</item>
+        <item name="android:widgetLayout">@android:layout/preference_dialog</item>
     </style>
 
     <!-- Other Misc Styles -->
diff --git a/docs/html/guide/appendix/api-levels.jd b/docs/html/guide/appendix/api-levels.jd
new file mode 100644
index 0000000..9af0918
--- /dev/null
+++ b/docs/html/guide/appendix/api-levels.jd
@@ -0,0 +1,79 @@
+page.title=Android API Levels
+@jd:body
+
+
+<p>The Android <em>API Level</em> is an integer that indicates a set of APIs available in an Android SDK
+and on a version of the Android platform. Each version of the Android platform supports a specific set
+of APIs, which are always backward-compatible. For example, Android 1.5 supports all APIs available in
+Android 1.0, but the reverse is not true. If an application uses APIs
+available in Android 1.5 that are not available in 1.0, then the application should never be installed
+on an Android 1.0 device, because it will fail due to missing APIs. The API Level ensures this does not happen
+by comparing the minimum API Level required by the applicaiton to the API Level available on the device.</p>
+
+<p>When a new version of Android adds APIs, a new API Level is added to the platform. The new APIs
+are available only to applications that declare a minimum API Level that is equal-to or greater-than 
+the API Level in which the APIs were introduced. The API Level required by an application is declared with the
+<code>&lt;uses-sdk></code> element inside the Android manifest, like this:</p>
+
+<pre>&lt;uses-sdk android:minSdkVersion="3" /></pre>
+
+<p>The value for <code>minSdkVersion</code> is the minimum API Level required by the application.
+If this is not declared, then it is assumed that the application is compatible with all versions and defaults to 
+API Level 1. In which case, if the application actually uses APIs introduced with an API Level greater than 1, then
+the application will fail in unpredictable ways when installed on a device that only supports API Level 1 
+(such as an Android 1.0 device).  
+See the <code><a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html">&lt;uses-sdk></a></code> 
+documentation for more about declaring the API Level in your manifest.</p>
+
+<p>For example, the {@link android.appwidget} package was introduced with API Level 3. If your application
+has set <code>minSdkVersion</code> to 1 or 2, then your application cannot use this package, 
+even if the device running your application uses a version of Android that supports it.
+In order to use the {@link android.appwidget} package, your application must set <code>minSdkVersion</code> 
+to 3 or higher. When the <code>minSdkVersion</code> is set to 3, the application will no longer be able to install 
+on a device running a platform version with an API Level less than 3.</p>
+
+<p>Despite the name of the manifest attribute (<code>minSdkVersion</code>), the API Level is not directly 
+associated with a specific SDK. For example, the SDK for Android 1.0 uses
+API Level 1 and the SDK for Android 1.1 uses API Level 2. So it may seem that the API Level increases consistently.
+However, it's possible that a subsequent platform
+releases will not introduce new APIs, and thus, the API Level will remain the same. In addition, there are often
+multiple SDK releases for a single platform version (there were three SDK releases for Android 1.5), and
+there's no guarantee that the API Level will remain the same between these. It's possible (but unlikely) that
+a second or third SDK for a given version of the platform will provide new APIs and add a new API Level.
+When you install a new SDK, be sure to read the SDK Contents on the install page, which specifies the API 
+Level for each platform available in the SDK. Also see the comparison of 
+<a href="#VersionsVsApiLevels">Platform Versions vs. API Levels</a>, below.</p>
+
+<p class="note"><strong>Note:</strong> During "preview" SDK releases, there may not yet be an official platform version
+or API Level number specified. In these cases, a string value equal to the
+current codename will be a valid value for <code>minSdkVersion</code>, instead of an integer. This codename value
+will only be valid while using the preview SDK. When the final SDK is released, you must update your manifest to use
+the official API Level integer.</p>
+
+<h2 id="VersionsVsApiLevels">Platform Versions vs. API Levels</h2>
+
+<p>The following table specifies the <em>maximum</em> API Level supported by each version of the Android platform.</p>
+
+<table>
+  <tr><th>Platform Version</th><th>API Level</th></tr>
+  <tr><td>Android 1.0</td><td>1</td></tr>
+  <tr><td>Android 1.1</td><td>2</td></tr>
+  <tr><td>Android 1.5</td><td>3</td></tr>
+  <tr><td>Android Donut</td><td>Donut</td></tr>
+</table>
+
+
+<h2 id="ViewingTheApiReference">Viewing the API Reference Based on API Level</h2>
+
+<p>The Android API reference includes information that specififies the minimum API Level required for each 
+package, class, and member. You can see this information on the right side of each header or label.</p>
+
+<p>By default, the reference documentation shows all APIs available with the latest SDK release.
+This means that the reference assumes you're using the latest API Level and will show you everything available
+with it. If you're developing applications for a version of Android that does not support the latest API Level, 
+then you can filter the reference to reveal only the packages, classes, and members available for that API Level.
+When viewing the reference, use the "Filter by API Level" selection box (below the search bar) to pick the API Level
+you'd like to view.</p>
+
+
+
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index bc2e42e..345f810 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -50,6 +50,9 @@
 
     // Package-scoped for quick access.
     /*package*/ int mDensity = Bitmap.DENSITY_NONE;
+
+    // Used to determine when compatibility scaling is in effect.
+    private int mScreenDensity = Bitmap.DENSITY_NONE;
     
     // Used by native code
     @SuppressWarnings({"UnusedDeclaration"})
@@ -219,6 +222,11 @@
         mDensity = density;
     }
 
+    /** @hide */
+    public void setScreenDensity(int density) {
+        mScreenDensity = density;
+    }
+    
     // the SAVE_FLAG constants must match their native equivalents
 
     /** restore the current matrix when restore() is called */
@@ -971,7 +979,8 @@
     public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
         throwIfRecycled(bitmap);
         native_drawBitmap(mNativeCanvas, bitmap.ni(), left, top,
-                paint != null ? paint.mNativePaint : 0, mDensity, bitmap.mDensity);
+                paint != null ? paint.mNativePaint : 0, mDensity, mScreenDensity,
+                bitmap.mDensity);
     }
 
     /**
@@ -1002,7 +1011,8 @@
         }
         throwIfRecycled(bitmap);
         native_drawBitmap(mNativeCanvas, bitmap.ni(), src, dst,
-                          paint != null ? paint.mNativePaint : 0);
+                          paint != null ? paint.mNativePaint : 0,
+                          mScreenDensity, bitmap.mDensity);
     }
 
     /**
@@ -1033,7 +1043,8 @@
         }
         throwIfRecycled(bitmap);
         native_drawBitmap(mNativeCanvas, bitmap.ni(), src, dst,
-                          paint != null ? paint.mNativePaint : 0);
+                          paint != null ? paint.mNativePaint : 0,
+                          mScreenDensity, bitmap.mDensity);
     }
     
     /**
@@ -1513,13 +1524,19 @@
     private native void native_drawBitmap(int nativeCanvas, int bitmap,
                                                  float left, float top,
                                                  int nativePaintOrZero,
-                                                 int canvasDensity, int bitmapDensity);
+                                                 int canvasDensity,
+                                                 int screenDensity,
+                                                 int bitmapDensity);
     private native void native_drawBitmap(int nativeCanvas, int bitmap,
                                                  Rect src, RectF dst,
-                                                 int nativePaintOrZero);
+                                                 int nativePaintOrZero,
+                                                 int screenDensity,
+                                                 int bitmapDensity);
     private static native void native_drawBitmap(int nativeCanvas, int bitmap,
                                                  Rect src, Rect dst,
-                                                 int nativePaintOrZero);
+                                                 int nativePaintOrZero,
+                                                 int screenDensity,
+                                                 int bitmapDensity);
     private static native void native_drawBitmap(int nativeCanvas, int[] colors,
                                                 int offset, int stride, float x,
                                                  float y, int width, int height,
diff --git a/graphics/java/android/renderscript/BaseObj.java b/graphics/java/android/renderscript/BaseObj.java
new file mode 100644
index 0000000..f70aee5
--- /dev/null
+++ b/graphics/java/android/renderscript/BaseObj.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.renderscript;
+
+import android.util.Log;
+
+/**
+ * @hide
+ *
+ **/
+class BaseObj {
+
+    BaseObj(RenderScript rs) {
+        mRS = rs;
+        mID = 0;
+    }
+
+    public int getID() {
+        return mID;
+    }
+
+    int mID;
+    String mName;
+    RenderScript mRS;
+
+    public void setName(String s) throws IllegalStateException, IllegalArgumentException
+    {
+        if(s.length() < 1) {
+            throw new IllegalArgumentException("setName does not accept a zero length string.");
+        }
+        if(mName != null) {
+            throw new IllegalArgumentException("setName object already has a name.");
+        }
+
+        try {
+            byte[] bytes = s.getBytes("UTF-8");
+            mRS.nAssignName(mID, bytes);
+            mName = s;
+        } catch (java.io.UnsupportedEncodingException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    protected void finalize() throws Throwable
+    {
+        if (mID != 0) {
+            Log.v(RenderScript.LOG_TAG,
+                  "Element finalized without having released the RS reference.");
+        }
+        super.finalize();
+    }
+}
+
diff --git a/graphics/java/android/renderscript/Element.java b/graphics/java/android/renderscript/Element.java
new file mode 100644
index 0000000..8e0a7a1
--- /dev/null
+++ b/graphics/java/android/renderscript/Element.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.renderscript;
+
+
+/**
+ * @hide
+ *
+ **/
+public class Element extends BaseObj {
+    final int mPredefinedID;
+    final boolean mIsPredefined;
+
+    public static final Element USER_U8 = new Element(0);
+    public static final Element USER_I8 = new Element(1);
+    public static final Element USER_U16 = new Element(2);
+    public static final Element USER_I16 = new Element(3);
+    public static final Element USER_U32 = new Element(4);
+    public static final Element USER_I32 = new Element(5);
+    public static final Element USER_FLOAT = new Element(6);
+
+    public static final Element A_8 = new Element(7);
+    public static final Element RGB_565 = new Element(8);
+    public static final Element RGB_888 = new Element(11);
+    public static final Element RGBA_5551 = new Element(9);
+    public static final Element RGBA_4444 = new Element(10);
+    public static final Element RGBA_8888 = new Element(12);
+
+    public static final Element INDEX_16 = new Element(13);
+    public static final Element INDEX_32 = new Element(14);
+    public static final Element XY_F32 = new Element(15);
+    public static final Element XYZ_F32 = new Element(16);
+    public static final Element ST_XY_F32 = new Element(17);
+    public static final Element ST_XYZ_F32 = new Element(18);
+    public static final Element NORM_XYZ_F32 = new Element(19);
+    public static final Element NORM_ST_XYZ_F32 = new Element(20);
+
+    void initPredef(RenderScript rs) {
+        mID = rs.nElementGetPredefined(mPredefinedID);
+    }
+
+    static void init(RenderScript rs) {
+        USER_U8.initPredef(rs);
+        USER_I8.initPredef(rs);
+        USER_U16.initPredef(rs);
+        USER_I16.initPredef(rs);
+        USER_U32.initPredef(rs);
+        USER_I32.initPredef(rs);
+        USER_FLOAT.initPredef(rs);
+
+        A_8.initPredef(rs);
+        RGB_565.initPredef(rs);
+        RGB_888.initPredef(rs);
+        RGBA_5551.initPredef(rs);
+        RGBA_4444.initPredef(rs);
+        RGBA_8888.initPredef(rs);
+
+        INDEX_16.initPredef(rs);
+        INDEX_32.initPredef(rs);
+        XY_F32.initPredef(rs);
+        XYZ_F32.initPredef(rs);
+        ST_XY_F32.initPredef(rs);
+        ST_XYZ_F32.initPredef(rs);
+        NORM_XYZ_F32.initPredef(rs);
+        NORM_ST_XYZ_F32.initPredef(rs);
+    }
+
+
+    public enum DataType {
+        FLOAT (0),
+        UNSIGNED (1),
+        SIGNED (2);
+
+        int mID;
+        DataType(int id) {
+            mID = id;
+        }
+    }
+
+    public enum DataKind {
+        USER (0),
+        RED (1),
+        GREEN (2),
+        BLUE (3),
+        ALPHA (4),
+        LUMINANCE (5),
+        INTENSITY (6),
+        X (7),
+        Y (8),
+        Z (9),
+        W (10),
+        S (11),
+        T (12),
+        Q (13),
+        R (14),
+        NX (15),
+        NY (16),
+        NZ (17),
+        INDEX (18);
+
+        int mID;
+        DataKind(int id) {
+            mID = id;
+        }
+    }
+
+
+    Element(int predef) {
+        super(null);
+        mID = 0;
+        mPredefinedID = predef;
+        mIsPredefined = true;
+    }
+
+    Element(int id, RenderScript rs) {
+        super(rs);
+        mID = id;
+        mPredefinedID = 0;
+        mIsPredefined = false;
+    }
+
+    public void destroy() throws IllegalStateException {
+        if(mIsPredefined) {
+            throw new IllegalStateException("Attempting to destroy a predefined Element.");
+        }
+        mRS.nElementDestroy(mID);
+        mID = 0;
+    }
+
+
+
+
+    public static class Builder {
+        RenderScript mRS;
+        boolean mActive = true;
+
+        Builder(RenderScript rs) {
+            mRS = rs;
+        }
+
+        void begin() throws IllegalStateException {
+            if (mActive) {
+                throw new IllegalStateException("Element builder already active.");
+            }
+            mRS.nElementBegin();
+            mActive = true;
+        }
+
+        public Builder add(Element e) throws IllegalArgumentException, IllegalStateException {
+            if(!mActive) {
+                throw new IllegalStateException("Element builder not active.");
+            }
+            if(!e.mIsPredefined) {
+                throw new IllegalArgumentException("add requires a predefined Element.");
+            }
+            mRS.nElementAddPredefined(e.mID);
+            return this;
+        }
+
+        public Builder add(Element.DataType dt, Element.DataKind dk, boolean isNormalized, int bits)
+            throws IllegalStateException {
+            if(!mActive) {
+                throw new IllegalStateException("Element builder not active.");
+            }
+            int norm = 0;
+            if (isNormalized) {
+                norm = 1;
+            }
+            mRS.nElementAdd(dt.mID, dk.mID, norm, bits);
+            return this;
+        }
+
+        public void abort() throws IllegalStateException {
+            if(!mActive) {
+                throw new IllegalStateException("Element builder not active.");
+            }
+            mActive = false;
+        }
+
+        public Element create() throws IllegalStateException {
+            if(!mActive) {
+                throw new IllegalStateException("Element builder not active.");
+            }
+            int id = mRS.nElementCreate();
+            mActive = false;
+            return new Element(id, mRS);
+        }
+    }
+
+}
+
diff --git a/graphics/java/android/renderscript/ProgramVertexAlloc.java b/graphics/java/android/renderscript/ProgramVertexAlloc.java
index 82bcc30..424e0ad 100644
--- a/graphics/java/android/renderscript/ProgramVertexAlloc.java
+++ b/graphics/java/android/renderscript/ProgramVertexAlloc.java
@@ -40,10 +40,7 @@
         mProjection = new Matrix();
         mTexture = new Matrix();
 
-        mAlloc = rs.allocationCreatePredefSized(
-            RenderScript.ElementPredefined.USER_FLOAT, 
-            48);
-
+        mAlloc = rs.allocationCreateSized(Element.USER_FLOAT, 48);
         mAlloc.subData1D(MODELVIEW_OFFSET, 16, mModel.mMat);
         mAlloc.subData1D(PROJECTION_OFFSET, 16, mProjection.mMat);
         mAlloc.subData1D(TEXTURE_OFFSET, 16, mTexture.mMat);
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index 1770a7a..3d4f333 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -14,30 +14,21 @@
  * limitations under the License.
  */
 
-/**
- * @hide
- *
- **/
 package android.renderscript;
 
-import java.io.InputStream;
 import java.io.IOException;
+import java.io.InputStream;
+
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.util.Config;
+import android.util.Log;
+import android.view.Surface;
 
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
 import android.graphics.Color;
 
-import android.os.Bundle;
-import android.content.res.Resources;
-import android.util.Log;
-import android.util.Config;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.Window;
-import android.view.View;
-import android.view.Surface;
 
 /**
  * @hide
@@ -71,124 +62,125 @@
         mBitmapOptions.inScaled = false;
     }
 
-    native private int  nDeviceCreate();
-    native private void nDeviceDestroy(int dev);
-    native private int  nContextCreate(int dev, Surface sur, int ver);
-    native private void nContextDestroy(int con);
+    native int  nDeviceCreate();
+    native void nDeviceDestroy(int dev);
+    native int  nContextCreate(int dev, Surface sur, int ver);
+    native void nContextDestroy(int con);
 
     //void rsContextBindSampler (uint32_t slot, RsSampler sampler);
     //void rsContextBindRootScript (RsScript sampler);
-    native private void nContextBindRootScript(int script);
-    native private void nContextBindSampler(int sampler, int slot);
-    native private void nContextBindProgramFragmentStore(int pfs);
-    native private void nContextBindProgramFragment(int pf);
-    native private void nContextBindProgramVertex(int pf);
+    native void nContextBindRootScript(int script);
+    native void nContextBindSampler(int sampler, int slot);
+    native void nContextBindProgramFragmentStore(int pfs);
+    native void nContextBindProgramFragment(int pf);
+    native void nContextBindProgramVertex(int pf);
 
-    native private void nAssignName(int obj, byte[] name);
-    native private int  nFileOpen(byte[] name);
+    native void nAssignName(int obj, byte[] name);
+    native int  nFileOpen(byte[] name);
 
-    native private void nElementBegin();
-    native private void nElementAddPredefined(int predef);
-    native private void nElementAdd(int kind, int type, int norm, int bits);
-    native private int  nElementCreate();
-    native private int  nElementGetPredefined(int predef);
-    native private void nElementDestroy(int obj);
+    native void nElementBegin();
+    native void nElementAddPredefined(int predef);
+    native void nElementAdd(int kind, int type, int norm, int bits);
+    native int  nElementCreate();
+    native int  nElementGetPredefined(int predef);
+    native void nElementDestroy(int obj);
 
-    native private void nTypeBegin(int elementID);
-    native private void nTypeAdd(int dim, int val);
-    native private int  nTypeCreate();
-    native private void nTypeDestroy(int id);
+    native void nTypeBegin(int elementID);
+    native void nTypeAdd(int dim, int val);
+    native int  nTypeCreate();
+    native void nTypeDestroy(int id);
 
-    native private int  nAllocationCreateTyped(int type);
-    native private int  nAllocationCreatePredefSized(int predef, int count);
-    native private int  nAllocationCreateSized(int elem, int count);
-    native private int  nAllocationCreateFromBitmap(int dstFmt, boolean genMips, Bitmap bmp);
-    native private int  nAllocationCreateFromBitmapBoxed(int dstFmt, boolean genMips, Bitmap bmp);
+    native int  nAllocationCreateTyped(int type);
+    native int  nAllocationCreatePredefSized(int predef, 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 private void nAllocationUploadToTexture(int alloc, int baseMioLevel);
-    native private void nAllocationDestroy(int alloc);
-    native private void nAllocationData(int id, int[] d);
-    native private void nAllocationData(int id, float[] d);
-    native private void nAllocationSubData1D(int id, int off, int count, int[] d);
-    native private void nAllocationSubData1D(int id, int off, int count, float[] d);
-    native private void nAllocationSubData2D(int id, int xoff, int yoff, int w, int h, int[] d);
-    native private void nAllocationSubData2D(int id, int xoff, int yoff, int w, int h, float[] d);
+    native void nAllocationUploadToTexture(int alloc, int baseMioLevel);
+    native void nAllocationDestroy(int alloc);
+    native void nAllocationData(int id, int[] d);
+    native void nAllocationData(int id, float[] d);
+    native void nAllocationSubData1D(int id, int off, int count, int[] d);
+    native void nAllocationSubData1D(int id, int off, int count, float[] d);
+    native void nAllocationSubData2D(int id, int xoff, int yoff, int w, int h, int[] d);
+    native void nAllocationSubData2D(int id, int xoff, int yoff, int w, int h, float[] d);
 
-    native private void nTriangleMeshDestroy(int id);
-    native private void nTriangleMeshBegin(int vertex, int index);
-    native private void nTriangleMeshAddVertex_XY (float x, float y);
-    native private void nTriangleMeshAddVertex_XYZ (float x, float y, float z);
-    native private void nTriangleMeshAddVertex_XY_ST (float x, float y, float s, float t);
-    native private void nTriangleMeshAddVertex_XYZ_ST (float x, float y, float z, float s, float t);
-    native private void nTriangleMeshAddVertex_XYZ_ST_NORM (float x, float y, float z, float s, float t, float nx, float ny, float nz);
-    native private void nTriangleMeshAddTriangle(int i1, int i2, int i3);
-    native private int  nTriangleMeshCreate();
+    native void nTriangleMeshDestroy(int id);
+    native void nTriangleMeshBegin(int vertex, int index);
+    native void nTriangleMeshAddVertex_XY (float x, float y);
+    native void nTriangleMeshAddVertex_XYZ (float x, float y, float z);
+    native void nTriangleMeshAddVertex_XY_ST (float x, float y, float s, float t);
+    native void nTriangleMeshAddVertex_XYZ_ST (float x, float y, float z, float s, float t);
+    native void nTriangleMeshAddVertex_XYZ_ST_NORM (float x, float y, float z, float s, float t, float nx, float ny, float nz);
+    native void nTriangleMeshAddTriangle(int i1, int i2, int i3);
+    native int  nTriangleMeshCreate();
 
-    native private void nAdapter1DDestroy(int id);
-    native private void nAdapter1DBindAllocation(int ad, int alloc);
-    native private void nAdapter1DSetConstraint(int ad, int dim, int value);
-    native private void nAdapter1DData(int ad, int[] d);
-    native private void nAdapter1DSubData(int ad, int off, int count, int[] d);
-    native private void nAdapter1DData(int ad, float[] d);
-    native private void nAdapter1DSubData(int ad, int off, int count, float[] d);
-    native private int  nAdapter1DCreate();
+    native void nAdapter1DDestroy(int id);
+    native void nAdapter1DBindAllocation(int ad, int alloc);
+    native void nAdapter1DSetConstraint(int ad, int dim, int value);
+    native void nAdapter1DData(int ad, int[] d);
+    native void nAdapter1DSubData(int ad, int off, int count, int[] d);
+    native void nAdapter1DData(int ad, float[] d);
+    native void nAdapter1DSubData(int ad, int off, int count, float[] d);
+    native int  nAdapter1DCreate();
 
-    native private void nScriptDestroy(int script);
-    native private void nScriptBindAllocation(int vtm, int alloc, int slot);
-    native private void nScriptCBegin();
-    native private void nScriptCSetClearColor(float r, float g, float b, float a);
-    native private void nScriptCSetClearDepth(float depth);
-    native private void nScriptCSetClearStencil(int stencil);
-    native private void nScriptCAddType(int type);
-    native private void nScriptCSetRoot(boolean isRoot);
-    native private void nScriptCSetScript(byte[] script, int offset, int length);
-    native private int  nScriptCCreate();
+    native void nScriptDestroy(int script);
+    native void nScriptBindAllocation(int vtm, int alloc, int slot);
+    native void nScriptCBegin();
+    native void nScriptCSetClearColor(float r, float g, float b, float a);
+    native void nScriptCSetClearDepth(float depth);
+    native void nScriptCSetClearStencil(int stencil);
+    native void nScriptCSetTimeZone(byte[] timeZone);
+    native void nScriptCAddType(int type);
+    native void nScriptCSetRoot(boolean isRoot);
+    native void nScriptCSetScript(byte[] script, int offset, int length);
+    native int  nScriptCCreate();
 
-    native private void nSamplerDestroy(int sampler);
-    native private void nSamplerBegin();
-    native private void nSamplerSet(int param, int value);
-    native private int  nSamplerCreate();
+    native void nSamplerDestroy(int sampler);
+    native void nSamplerBegin();
+    native void nSamplerSet(int param, int value);
+    native int  nSamplerCreate();
 
-    native private void nProgramFragmentStoreBegin(int in, int out);
-    native private void nProgramFragmentStoreDepthFunc(int func);
-    native private void nProgramFragmentStoreDepthMask(boolean enable);
-    native private void nProgramFragmentStoreColorMask(boolean r, boolean g, boolean b, boolean a);
-    native private void nProgramFragmentStoreBlendFunc(int src, int dst);
-    native private void nProgramFragmentStoreDither(boolean enable);
-    native private int  nProgramFragmentStoreCreate();
-    native private void nProgramFragmentStoreDestroy(int pgm);
+    native void nProgramFragmentStoreBegin(int in, int out);
+    native void nProgramFragmentStoreDepthFunc(int func);
+    native void nProgramFragmentStoreDepthMask(boolean enable);
+    native void nProgramFragmentStoreColorMask(boolean r, boolean g, boolean b, boolean a);
+    native void nProgramFragmentStoreBlendFunc(int src, int dst);
+    native void nProgramFragmentStoreDither(boolean enable);
+    native int  nProgramFragmentStoreCreate();
+    native void nProgramFragmentStoreDestroy(int pgm);
 
-    native private void nProgramFragmentBegin(int in, int out);
-    native private void nProgramFragmentBindTexture(int vpf, int slot, int a);
-    native private void nProgramFragmentBindSampler(int vpf, int slot, int s);
-    native private void nProgramFragmentSetType(int slot, int vt);
-    native private void nProgramFragmentSetEnvMode(int slot, int env);
-    native private void nProgramFragmentSetTexEnable(int slot, boolean enable);
-    native private int  nProgramFragmentCreate();
-    native private void nProgramFragmentDestroy(int pgm);
+    native void nProgramFragmentBegin(int in, int out);
+    native void nProgramFragmentBindTexture(int vpf, int slot, int a);
+    native void nProgramFragmentBindSampler(int vpf, int slot, int s);
+    native void nProgramFragmentSetType(int slot, int vt);
+    native void nProgramFragmentSetEnvMode(int slot, int env);
+    native void nProgramFragmentSetTexEnable(int slot, boolean enable);
+    native int  nProgramFragmentCreate();
+    native void nProgramFragmentDestroy(int pgm);
 
-    native private void nProgramVertexDestroy(int pv);
-    native private void nProgramVertexBindAllocation(int pv, int slot, int mID);
-    native private void nProgramVertexBegin(int inID, int outID);
-    native private void nProgramVertexSetType(int slot, int mID);
-    native private void nProgramVertexSetTextureMatrixEnable(boolean enable);
-    native private void nProgramVertexAddLight(int id);
-    native private int  nProgramVertexCreate();
+    native void nProgramVertexDestroy(int pv);
+    native void nProgramVertexBindAllocation(int pv, int slot, int mID);
+    native void nProgramVertexBegin(int inID, int outID);
+    native void nProgramVertexSetType(int slot, int mID);
+    native void nProgramVertexSetTextureMatrixEnable(boolean enable);
+    native void nProgramVertexAddLight(int id);
+    native int  nProgramVertexCreate();
 
-    native private void nLightBegin();
-    native private void nLightSetIsMono(boolean isMono);
-    native private void nLightSetIsLocal(boolean isLocal);
-    native private int  nLightCreate();
-    native private void nLightDestroy(int l);
-    native private void nLightSetColor(int l, float r, float g, float b);
-    native private void nLightSetPosition(int l, float x, float y, float z);
+    native void nLightBegin();
+    native void nLightSetIsMono(boolean isMono);
+    native void nLightSetIsLocal(boolean isLocal);
+    native int  nLightCreate();
+    native void nLightDestroy(int l);
+    native void nLightSetColor(int l, float r, float g, float b);
+    native void nLightSetPosition(int l, float x, float y, float z);
 
 
     private int     mDev;
     private int     mContext;
     private Surface mSurface;
 
-
+    private static boolean mElementsInitialized = false;
 
     ///////////////////////////////////////////////////////////////////////////////////
     //
@@ -197,120 +189,25 @@
         mSurface = sur;
         mDev = nDeviceCreate();
         mContext = nContextCreate(mDev, mSurface, 0);
-    }
 
-    private class BaseObj {
-        BaseObj() {
-            mID = 0;
-        }
-
-        public int getID() {
-            return mID;
-        }
-
-        int mID;
-        String mName;
-
-        public void setName(String s) throws IllegalStateException, IllegalArgumentException
-        {
-            if(s.length() < 1) {
-                throw new IllegalArgumentException("setName does not accept a zero length string.");
-            }
-            if(mName != null) {
-                throw new IllegalArgumentException("setName object already has a name.");
-            }
-
-            try {
-                byte[] bytes = s.getBytes("UTF-8");
-                nAssignName(mID, bytes);
-                mName = s;
-            } catch (java.io.UnsupportedEncodingException e) {
-                throw new RuntimeException(e);
-            }
-        }
-
-        protected void finalize() throws Throwable
-        {
-            if (mID != 0) {
-                Log.v(LOG_TAG,
-                      "Element finalized without having released the RS reference.");
-            }
-            super.finalize();
+        // TODO: This should be protected by a lock
+        if(!mElementsInitialized) {
+            Element.init(this);
+            mElementsInitialized = true;
         }
     }
 
-
     //////////////////////////////////////////////////////////////////////////////////
     // Element
 
-    public enum ElementPredefined {
-        USER_U8 (0),
-        USER_I8 (1),
-        USER_U16 (2),
-        USER_I16 (3),
-        USER_U32 (4),
-        USER_I32 (5),
-        USER_FLOAT (6),
-
-        A_8                (7),
-        RGB_565            (8),
-        RGB_888            (11),
-        RGBA_5551          (9),
-        RGBA_4444          (10),
-        RGBA_8888          (12),
-
-        INDEX_16           (13),
-        INDEX_32           (14),
-        XY_F32             (15),
-        XYZ_F32            (16),
-        ST_XY_F32          (17),
-        ST_XYZ_F32         (18),
-        NORM_XYZ_F32       (19),
-        NORM_ST_XYZ_F32    (20);
-
-        int mID;
-        ElementPredefined(int id) {
-            mID = id;
-        }
+    Element.Builder mElementBuilder = new Element.Builder(this);
+    public Element.Builder elementBuilderCreate() throws IllegalStateException {
+        mElementBuilder.begin();
+        return mElementBuilder;
     }
 
-    public enum DataType {
-        FLOAT (0),
-        UNSIGNED (1),
-        SIGNED (2);
 
-        int mID;
-        DataType(int id) {
-            mID = id;
-        }
-    }
 
-    public enum DataKind {
-        USER (0),
-        RED (1),
-        GREEN (2),
-        BLUE (3),
-        ALPHA (4),
-        LUMINANCE (5),
-        INTENSITY (6),
-        X (7),
-        Y (8),
-        Z (9),
-        W (10),
-        S (11),
-        T (12),
-        Q (13),
-        R (14),
-        NX (15),
-        NY (16),
-        NZ (17),
-        INDEX (18);
-
-        int mID;
-        DataKind(int id) {
-            mID = id;
-        }
-    }
 
     public enum DepthFunc {
         ALWAYS (0),
@@ -397,46 +294,6 @@
         }
     }
 
-
-
-    public class Element extends BaseObj {
-        Element(int id) {
-            mID = id;
-        }
-
-        public void estroy() {
-            nElementDestroy(mID);
-            mID = 0;
-        }
-    }
-
-    public void elementBegin() {
-        nElementBegin();
-    }
-
-    public void elementAddPredefined(ElementPredefined e) {
-        nElementAddPredefined(e.mID);
-    }
-
-    public void elementAdd(DataType dt, DataKind dk, boolean isNormalized, int bits) {
-        int norm = 0;
-        if (isNormalized) {
-            norm = 1;
-        }
-        nElementAdd(dt.mID, dk.mID, norm, bits);
-    }
-
-    public Element elementCreate() {
-        int id = nElementCreate();
-        return new Element(id);
-    }
-
-    public Element elementGetPredefined(ElementPredefined predef) {
-        int id = nElementGetPredefined(predef.mID);
-        return new Element(id);
-    }
-
-
     //////////////////////////////////////////////////////////////////////////////////
     // Type
 
@@ -456,6 +313,7 @@
 
     public class Type extends BaseObj {
         Type(int id) {
+            super(RenderScript.this);
             mID = id;
         }
 
@@ -484,6 +342,7 @@
 
     public class Allocation extends BaseObj {
         Allocation(int id) {
+            super(RenderScript.this);
             mID = id;
         }
 
@@ -526,34 +385,48 @@
         return new Allocation(id);
     }
 
-    public Allocation allocationCreatePredefSized(ElementPredefined e, int count) {
-        int id = nAllocationCreatePredefSized(e.mID, count);
-        return new Allocation(id);
-    }
-
     public Allocation allocationCreateSized(Element e, int count) {
-        int id = nAllocationCreateSized(e.mID, count);
+        int id;
+        if(e.mIsPredefined) {
+            id = nAllocationCreatePredefSized(e.mPredefinedID, count);
+        } else {
+            id = nAllocationCreateSized(e.mID, count);
+        }
         return new Allocation(id);
     }
 
-    public Allocation allocationCreateFromBitmap(Bitmap b, ElementPredefined dstFmt, boolean genMips) {
-        int id = nAllocationCreateFromBitmap(dstFmt.mID, genMips, b);
+    public Allocation allocationCreateFromBitmap(Bitmap b, Element dstFmt, boolean genMips)
+        throws IllegalArgumentException {
+        if(!dstFmt.mIsPredefined) {
+            throw new IllegalStateException("Attempting to allocate a bitmap with a non-static element.");
+        }
+
+        int id = nAllocationCreateFromBitmap(dstFmt.mPredefinedID, genMips, b);
         return new Allocation(id);
     }
 
-    public Allocation allocationCreateFromBitmapBoxed(Bitmap b, ElementPredefined dstFmt, boolean genMips) {
-        int id = nAllocationCreateFromBitmapBoxed(dstFmt.mID, genMips, b);
+    public Allocation allocationCreateFromBitmapBoxed(Bitmap b, Element dstFmt, boolean genMips)
+        throws IllegalArgumentException {
+        if(!dstFmt.mIsPredefined) {
+            throw new IllegalStateException("Attempting to allocate a bitmap with a non-static element.");
+        }
+
+        int id = nAllocationCreateFromBitmapBoxed(dstFmt.mPredefinedID, genMips, b);
         return new Allocation(id);
     }
 
-    public Allocation allocationCreateFromBitmapResource(Resources res, int id, ElementPredefined internalElement, boolean genMips) {
+    public Allocation allocationCreateFromBitmapResource(Resources res, int id, Element dstFmt, boolean genMips)
+        throws IllegalArgumentException {
+
         Bitmap b = BitmapFactory.decodeResource(res, id, mBitmapOptions);
-        return allocationCreateFromBitmap(b, internalElement, genMips);
+        return allocationCreateFromBitmap(b, dstFmt, genMips);
     }
 
-    public Allocation allocationCreateFromBitmapResourceBoxed(Resources res, int id, ElementPredefined internalElement, boolean genMips) {
+    public Allocation allocationCreateFromBitmapResourceBoxed(Resources res, int id, Element dstFmt, boolean genMips)
+        throws IllegalArgumentException {
+
         Bitmap b = BitmapFactory.decodeResource(res, id, mBitmapOptions);
-        return allocationCreateFromBitmapBoxed(b, internalElement, genMips);
+        return allocationCreateFromBitmapBoxed(b, dstFmt, genMips);
     }
 
 
@@ -562,6 +435,7 @@
 
     public class Adapter1D extends BaseObj {
         Adapter1D(int id) {
+            super(RenderScript.this);
             mID = id;
         }
 
@@ -606,6 +480,7 @@
 
     public class TriangleMesh extends BaseObj {
         TriangleMesh(int id) {
+            super(RenderScript.this);
             mID = id;
         }
 
@@ -616,6 +491,7 @@
     }
 
     public void triangleMeshBegin(Element vertex, Element index) {
+        Log.e("rs", "vtx " + vertex.toString() + "  " + vertex.mID + "  " + vertex.mPredefinedID);
         nTriangleMeshBegin(vertex.mID, index.mID);
     }
 
@@ -653,6 +529,7 @@
 
     public class Script extends BaseObj {
         Script(int id) {
+            super(RenderScript.this);
             mID = id;
         }
 
@@ -670,6 +547,15 @@
         nScriptCBegin();
     }
 
+    public void scriptCSetTimeZone(String timeZone) {
+        try {
+            byte[] bytes = timeZone.getBytes("UTF-8");
+            nScriptCSetTimeZone(bytes);
+        } catch (java.io.UnsupportedEncodingException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
     public void scriptCSetClearColor(float r, float g, float b, float a) {
         nScriptCSetClearColor(r, g, b, a);
     }
@@ -742,6 +628,7 @@
 
     public class ProgramVertex extends BaseObj {
         ProgramVertex(int id) {
+            super(RenderScript.this);
             mID = id;
         }
 
@@ -790,6 +677,7 @@
 
     public class ProgramFragmentStore extends BaseObj {
         ProgramFragmentStore(int id) {
+            super(RenderScript.this);
             mID = id;
         }
 
@@ -841,6 +729,7 @@
 
     public class ProgramFragment extends BaseObj {
         ProgramFragment(int id) {
+            super(RenderScript.this);
             mID = id;
         }
 
@@ -896,6 +785,7 @@
 
     public class Sampler extends BaseObj {
         Sampler(int id) {
+            super(RenderScript.this);
             mID = id;
         }
 
@@ -923,6 +813,7 @@
 
     public class Light extends BaseObj {
         Light(int id) {
+            super(RenderScript.this);
             mID = id;
         }
 
@@ -962,6 +853,7 @@
 
     public class File extends BaseObj {
         File(int id) {
+            super(RenderScript.this);
             mID = id;
         }
 
@@ -1025,3 +917,4 @@
 
 }
 
+
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index 6f781a0..a02abca 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -586,7 +586,7 @@
 nScriptCSetClearDepth(JNIEnv *_env, jobject _this, jfloat d)
 {
     RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
-    LOG_API("nScriptCSetClearColor, con(%p), depth(%f)", con, d);
+    LOG_API("nScriptCSetClearDepth, con(%p), depth(%f)", con, d);
     rsScriptCSetClearDepth(d);
 }
 
@@ -599,6 +599,23 @@
 }
 
 static void
+nScriptCSetTimeZone(JNIEnv *_env, jobject _this, jbyteArray timeZone)
+{
+    RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+    LOG_API("nScriptCSetTimeZone, con(%p), timeZone(%s)", con, timeZone);
+
+    jint length = _env->GetArrayLength(timeZone);
+    jbyte* timeZone_ptr;
+    timeZone_ptr = (jbyte *) _env->GetPrimitiveArrayCritical(timeZone, (jboolean *)0);
+
+    rsScriptCSetTimeZone((const char *)timeZone_ptr, length);
+
+    if (timeZone_ptr) {
+        _env->ReleasePrimitiveArrayCritical(timeZone, timeZone_ptr, 0);
+    }
+}
+
+static void
 nScriptCAddType(JNIEnv *_env, jobject _this, jint type)
 {
     RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
@@ -1052,6 +1069,7 @@
 {"nScriptCSetClearColor",          "(FFFF)V",                              (void*)nScriptCSetClearColor },
 {"nScriptCSetClearDepth",          "(F)V",                                 (void*)nScriptCSetClearDepth },
 {"nScriptCSetClearStencil",        "(I)V",                                 (void*)nScriptCSetClearStencil },
+{"nScriptCSetTimeZone",            "([B)V",                                (void*)nScriptCSetTimeZone },
 {"nScriptCAddType",                "(I)V",                                 (void*)nScriptCAddType },
 {"nScriptCSetRoot",                "(Z)V",                                 (void*)nScriptCSetRoot },
 {"nScriptCSetScript",              "([BII)V",                              (void*)nScriptCSetScript },
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
index 5c61c50..0010d84 100644
--- a/include/media/IOMX.h
+++ b/include/media/IOMX.h
@@ -23,6 +23,7 @@
 #include <utils/String8.h>
 
 #include <OMX_Core.h>
+#include <OMX_Video.h>
 
 #define IOMX_USES_SOCKETS       0
 
@@ -30,6 +31,8 @@
 
 class IMemory;
 class IOMXObserver;
+class IOMXRenderer;
+class ISurface;
 
 class IOMX : public IInterface {
 public:
@@ -87,6 +90,13 @@
             OMX_U32 range_offset, OMX_U32 range_length,
             OMX_U32 flags, OMX_TICKS timestamp) = 0;
 #endif
+
+    virtual sp<IOMXRenderer> createRenderer(
+            const sp<ISurface> &surface,
+            const char *componentName,
+            OMX_COLOR_FORMATTYPE colorFormat,
+            size_t encodedWidth, size_t encodedHeight,
+            size_t displayWidth, size_t displayHeight) = 0;
 };
 
 struct omx_message {
@@ -155,6 +165,13 @@
     virtual void on_message(const omx_message &msg) = 0;
 };
 
+class IOMXRenderer : public IInterface {
+public:
+    DECLARE_META_INTERFACE(OMXRenderer);
+
+    virtual void render(IOMX::buffer_id buffer) = 0;
+};
+
 ////////////////////////////////////////////////////////////////////////////////
 
 class BnOMX : public BnInterface<IOMX> {
@@ -171,6 +188,13 @@
             uint32_t flags = 0);
 };
 
+class BnOMXRenderer : public BnInterface<IOMXRenderer> {
+public:
+    virtual status_t onTransact(
+            uint32_t code, const Parcel &data, Parcel *reply,
+            uint32_t flags = 0);
+};
+
 }  // namespace android
 
 #endif  // ANDROID_IOMX_H_
diff --git a/include/media/stagefright/MediaPlayerImpl.h b/include/media/stagefright/MediaPlayerImpl.h
index c48400c..e96e5e8 100644
--- a/include/media/stagefright/MediaPlayerImpl.h
+++ b/include/media/stagefright/MediaPlayerImpl.h
@@ -28,6 +28,7 @@
 namespace android {
 
 class AudioPlayer;
+class IOMXRenderer;
 class ISurface;
 class MediaExtractor;
 class MediaBuffer;
@@ -37,7 +38,6 @@
 class OMXDecoder;
 class Surface;
 class TimeSource;
-class VideoRenderer;
 
 class MediaPlayerImpl {
 public:
@@ -93,7 +93,7 @@
 
     sp<Surface> mSurface;
     sp<ISurface> mISurface;
-    VideoRenderer *mRenderer;
+    sp<IOMXRenderer> mVideoRenderer;
 
     sp<MediaPlayerBase::AudioSink> mAudioSink;
 
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index 04805dab..2d5b8d8 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -44,6 +44,7 @@
     kKeyColorFormat      = 'colf',
     kKeyPlatformPrivate  = 'priv',
     kKeyDecoderComponent = 'decC',
+    kKeyBufferID         = 'bfID',
 };
 
 enum {
diff --git a/include/media/stagefright/SurfaceRenderer.h b/include/media/stagefright/SurfaceRenderer.h
deleted file mode 100644
index 298ab50..0000000
--- a/include/media/stagefright/SurfaceRenderer.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef SURFACE_RENDERER_H_
-
-#define SURFACE_RENDERER_H_
-
-#include <media/stagefright/VideoRenderer.h>
-#include <utils/RefBase.h>
-
-namespace android {
-
-class Surface;
-
-class SurfaceRenderer : public VideoRenderer {
-public:
-    SurfaceRenderer(
-            const sp<Surface> &surface,
-            size_t displayWidth, size_t displayHeight,
-            size_t decodedWidth, size_t decodedHeight);
-
-    virtual ~SurfaceRenderer();
-
-    virtual void render(
-            const void *data, size_t size, void *platformPrivate);
-
-private:
-    sp<Surface> mSurface;
-    size_t mDisplayWidth, mDisplayHeight;
-    size_t mDecodedWidth, mDecodedHeight;
-
-    SurfaceRenderer(const SurfaceRenderer &);
-    SurfaceRenderer &operator=(const SurfaceRenderer &);
-};
-
-}  // namespace android
-
-#endif  // SURFACE_RENDERER_H_
diff --git a/include/ui/FramebufferNativeWindow.h b/include/ui/FramebufferNativeWindow.h
index e72357a..cb9bf94 100644
--- a/include/ui/FramebufferNativeWindow.h
+++ b/include/ui/FramebufferNativeWindow.h
@@ -62,6 +62,7 @@
     static int dequeueBuffer(android_native_window_t* window, android_native_buffer_t** buffer);
     static int lockBuffer(android_native_window_t* window, android_native_buffer_t* buffer);
     static int queueBuffer(android_native_window_t* window, android_native_buffer_t* buffer);
+    static int query(android_native_window_t* window, int what, int* value);
     
     framebuffer_device_t* fbDev;
     alloc_device_t* grDev;
diff --git a/include/ui/Surface.h b/include/ui/Surface.h
index 8c4f63d..5665c1f 100644
--- a/include/ui/Surface.h
+++ b/include/ui/Surface.h
@@ -36,6 +36,7 @@
 
 class BufferMapper;
 class Rect;
+class MediaPlayerImpl;
 class Surface;
 class SurfaceComposerClient;
 struct per_client_cblk_t;
@@ -115,6 +116,8 @@
     sp<ISurface>                mSurface;
     SurfaceID                   mToken;
     uint32_t                    mIdentity;
+    uint32_t                    mWidth;
+    uint32_t                    mHeight;
     PixelFormat                 mFormat;
     uint32_t                    mFlags;
     mutable Mutex               mLock;
@@ -178,6 +181,7 @@
     // mediaplayer needs access to ISurface for display
     friend class MediaPlayer;
     friend class Test;
+    friend class MediaPlayerImpl;
     const sp<ISurface>& getISurface() const { return mSurface; }
 
     status_t getBufferLocked(int index);
@@ -192,10 +196,12 @@
     static int dequeueBuffer(android_native_window_t* window, android_native_buffer_t** buffer);
     static int lockBuffer(android_native_window_t* window, android_native_buffer_t* buffer);
     static int queueBuffer(android_native_window_t* window, android_native_buffer_t* buffer);
+    static int query(android_native_window_t* window, int what, int* value);
 
     int dequeueBuffer(android_native_buffer_t** buffer);
     int lockBuffer(android_native_buffer_t* buffer);
     int queueBuffer(android_native_buffer_t* buffer);
+    int query(int what, int* value);
 
     status_t dequeueBuffer(sp<SurfaceBuffer>* buffer);
     status_t lockBuffer(const sp<SurfaceBuffer>& buffer);
@@ -209,6 +215,8 @@
     sp<SurfaceBuffer>           mLockedBuffer;
     SurfaceID                   mToken;
     uint32_t                    mIdentity;
+    uint32_t                    mWidth;
+    uint32_t                    mHeight;
     PixelFormat                 mFormat;
     uint32_t                    mFlags;
     mutable Region              mDirtyRegion;
diff --git a/include/ui/egl/android_natives.h b/include/ui/egl/android_natives.h
index 0398ea7..a3a1316 100644
--- a/include/ui/egl/android_natives.h
+++ b/include/ui/egl/android_natives.h
@@ -60,6 +60,12 @@
 
 // ---------------------------------------------------------------------------
 
+/* attributes queriable with query() */
+enum {
+    NATIVE_WINDOW_WIDTH     = 0,
+    NATIVE_WINDOW_HEIGHT    = 1
+};
+
 struct android_native_window_t 
 {
 #ifdef __cplusplus
@@ -129,8 +135,15 @@
     int     (*queueBuffer)(struct android_native_window_t* window,
                 struct android_native_buffer_t* buffer);
 
+    /*
+     * hook used to retrieve information about the native window.
+     * 
+     * Returns 0 on success or -errno on error.
+     */
+    int     (*query)(struct android_native_window_t* window,
+            int what, int* value);
     
-    void* reserved_proc[5];
+    void* reserved_proc[4];
 };
 
 // ---------------------------------------------------------------------------
diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h
index edd0cae6..e524e2a 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/utils/ResourceTypes.h
@@ -1655,7 +1655,8 @@
     ssize_t resolveReference(Res_value* inOutValue,
                              ssize_t blockIndex,
                              uint32_t* outLastRef = NULL,
-                             uint32_t* inoutTypeSpecFlags = NULL) const;
+                             uint32_t* inoutTypeSpecFlags = NULL,
+                             ResTable_config* outConfig = NULL) const;
 
     enum {
         TMP_BUFFER_SIZE = 16
@@ -1729,7 +1730,8 @@
          */
         ssize_t resolveAttributeReference(Res_value* inOutValue,
                 ssize_t blockIndex, uint32_t* outLastRef = NULL,
-                uint32_t* inoutTypeSpecFlags = NULL) const;
+                uint32_t* inoutTypeSpecFlags = NULL,
+                ResTable_config* inoutConfig = NULL) const;
 
         void dumpToLog() const;
         
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index f40e4bd..785a3c5 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -661,7 +661,7 @@
 
 status_t Parcel::writeNativeHandle(const native_handle* handle)
 {
-    if (handle->version != sizeof(native_handle))
+    if (!handle || handle->version != sizeof(native_handle))
         return BAD_TYPE;
 
     status_t err;
diff --git a/libs/rs/java/Film/src/com/android/film/FilmRS.java b/libs/rs/java/Film/src/com/android/film/FilmRS.java
index 12a14e3..0e5b1bd 100644
--- a/libs/rs/java/Film/src/com/android/film/FilmRS.java
+++ b/libs/rs/java/Film/src/com/android/film/FilmRS.java
@@ -21,22 +21,12 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.Handler;
-import android.os.Message;
+import android.util.Log;
+
 import android.renderscript.Matrix;
 import android.renderscript.ProgramVertexAlloc;
 import android.renderscript.RenderScript;
-import android.renderscript.RenderScript.ElementPredefined;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.Surface;
-import android.view.SurfaceHolder;
-import android.view.SurfaceView;
+import android.renderscript.Element;
 
 public class FilmRS {
     private final int POS_TRANSLATE = 0;
@@ -76,8 +66,8 @@
     private RenderScript mRS;
     private RenderScript.Script mScriptStrip;
     private RenderScript.Script mScriptImage;
-    private RenderScript.Element mElementVertex;
-    private RenderScript.Element mElementIndex;
+    private Element mElementVertex;
+    private Element mElementIndex;
     private RenderScript.Sampler mSampler;
     private RenderScript.ProgramFragmentStore mPFSBackground;
     private RenderScript.ProgramFragmentStore mPFSImages;
@@ -166,13 +156,10 @@
     private void loadImages() {
         mBufferIDs = new int[13];
         mImages = new RenderScript.Allocation[13];
-        mAllocIDs = mRS.allocationCreatePredefSized(
-            RenderScript.ElementPredefined.USER_FLOAT,
-            mBufferIDs.length);
+        mAllocIDs = mRS.allocationCreateSized(
+            Element.USER_FLOAT, mBufferIDs.length);
 
-        RenderScript.ElementPredefined ie = 
-            RenderScript.ElementPredefined.RGB_565;
-
+        Element ie = Element.RGB_565;
         mImages[0] = mRS.allocationCreateFromBitmapResourceBoxed(mRes, R.drawable.p01, ie, true);
         mImages[1] = mRS.allocationCreateFromBitmapResourceBoxed(mRes, R.drawable.p02, ie, true);
         mImages[2] = mRS.allocationCreateFromBitmapResourceBoxed(mRes, R.drawable.p03, ie, true);
@@ -197,9 +184,8 @@
     private void initState()
     {
         mBufferState = new int[10];
-        mAllocState = mRS.allocationCreatePredefSized(
-            RenderScript.ElementPredefined.USER_FLOAT,
-            mBufferState.length);
+        mAllocState = mRS.allocationCreateSized(
+            Element.USER_FLOAT, mBufferState.length);
 
         mBufferState[STATE_TRIANGLE_OFFSET_COUNT] = mFSM.mTriangleOffsetsCount;
         mBufferState[STATE_LAST_FOCUS] = -1;
@@ -208,10 +194,8 @@
     }
 
     private void initRS() {
-        mElementVertex = mRS.elementGetPredefined(
-            RenderScript.ElementPredefined.NORM_ST_XYZ_F32);
-        mElementIndex = mRS.elementGetPredefined(
-            RenderScript.ElementPredefined.INDEX_16);
+        mElementVertex = Element.NORM_ST_XYZ_F32;
+        mElementIndex = Element.INDEX_16;
 
         mRS.triangleMeshBegin(mElementVertex, mElementIndex);
         mFSM = new FilmStripMesh();
@@ -231,9 +215,8 @@
         mRS.scriptCSetRoot(true);
         mScriptStrip = mRS.scriptCCreate();
 
-        mAllocPos = mRS.allocationCreatePredefSized(
-            RenderScript.ElementPredefined.USER_FLOAT,
-            mBufferPos.length);
+        mAllocPos = mRS.allocationCreateSized(
+            Element.USER_FLOAT, mBufferPos.length);
 
         loadImages();
         initState();
@@ -250,15 +233,13 @@
         mScriptStrip.bindAllocation(mPVA.mAlloc, 3);
 
 
-        mAllocOffsets = mRS.allocationCreatePredefSized(
-            RenderScript.ElementPredefined.USER_I32,
-            mFSM.mTriangleOffsets.length);
+        mAllocOffsets = mRS.allocationCreateSized(
+            Element.USER_I32, mFSM.mTriangleOffsets.length);
         mAllocOffsets.data(mFSM.mTriangleOffsets);
         mScriptStrip.bindAllocation(mAllocOffsets, 4);
 
-        mAllocOffsetsTex = mRS.allocationCreatePredefSized(
-            RenderScript.ElementPredefined.USER_FLOAT,
-            mFSM.mTriangleOffsetsTex.length);
+        mAllocOffsetsTex = mRS.allocationCreateSized(
+            Element.USER_FLOAT, mFSM.mTriangleOffsetsTex.length);
         mAllocOffsetsTex.data(mFSM.mTriangleOffsetsTex);
         mScriptStrip.bindAllocation(mAllocOffsetsTex, 5);
 
diff --git a/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java b/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java
index c8e9a1e..654d6cf 100644
--- a/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java
+++ b/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java
@@ -23,9 +23,11 @@
 import android.graphics.Bitmap;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
+import android.util.Log;
+
 import android.renderscript.RenderScript;
 import android.renderscript.ProgramVertexAlloc;
-import android.util.Log;
+import android.renderscript.Element;
 
 public class FountainRS {
 
@@ -65,10 +67,10 @@
     private void initRS() {
         int partCount = 1024;
 
-        mIntAlloc = mRS.allocationCreatePredefSized(RenderScript.ElementPredefined.USER_I32, 10);
-        mPartAlloc = mRS.allocationCreatePredefSized(RenderScript.ElementPredefined.USER_I32, partCount * 3 * 3);
+        mIntAlloc = mRS.allocationCreateSized(Element.USER_I32, 10);
+        mPartAlloc = mRS.allocationCreateSized(Element.USER_I32, partCount * 3 * 3);
         mPartAlloc.setName("PartBuffer");
-        mVertAlloc = mRS.allocationCreatePredefSized(RenderScript.ElementPredefined.USER_I32, partCount * 5 + 1);
+        mVertAlloc = mRS.allocationCreateSized(Element.USER_I32, partCount * 5 + 1);
 
         mRS.programFragmentStoreBegin(null, null);
         mRS.programFragmentStoreBlendFunc(RenderScript.BlendSrcFunc.SRC_ALPHA, RenderScript.BlendDstFunc.ONE);
diff --git a/libs/rs/java/Grass/Android.mk b/libs/rs/java/Grass/Android.mk
new file mode 100644
index 0000000..ce5294e
--- /dev/null
+++ b/libs/rs/java/Grass/Android.mk
@@ -0,0 +1,25 @@
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+#LOCAL_STATIC_JAVA_LIBRARIES := android.renderscript
+
+LOCAL_PACKAGE_NAME := GrassRS
+
+include $(BUILD_PACKAGE)
diff --git a/libs/rs/java/Grass/AndroidManifest.xml b/libs/rs/java/Grass/AndroidManifest.xml
new file mode 100644
index 0000000..a40f378
--- /dev/null
+++ b/libs/rs/java/Grass/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.grass.rs">
+
+    <application android:label="GrassRS">
+
+        <activity
+            android:name="Grass"
+            android:theme="@android:style/Theme.NoTitleBar">
+
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+
+        </activity>
+
+    </application>
+
+</manifest>
diff --git a/libs/rs/java/Grass/res/drawable-hdpi/night.jpg b/libs/rs/java/Grass/res/drawable-hdpi/night.jpg
new file mode 100644
index 0000000..9989abf
--- /dev/null
+++ b/libs/rs/java/Grass/res/drawable-hdpi/night.jpg
Binary files differ
diff --git a/libs/rs/java/Grass/res/drawable-hdpi/sky.jpg b/libs/rs/java/Grass/res/drawable-hdpi/sky.jpg
new file mode 100644
index 0000000..a12fe20
--- /dev/null
+++ b/libs/rs/java/Grass/res/drawable-hdpi/sky.jpg
Binary files differ
diff --git a/libs/rs/java/Grass/res/drawable-hdpi/sunrise.jpg b/libs/rs/java/Grass/res/drawable-hdpi/sunrise.jpg
new file mode 100644
index 0000000..db016b2
--- /dev/null
+++ b/libs/rs/java/Grass/res/drawable-hdpi/sunrise.jpg
Binary files differ
diff --git a/libs/rs/java/Grass/res/drawable-hdpi/sunset.jpg b/libs/rs/java/Grass/res/drawable-hdpi/sunset.jpg
new file mode 100644
index 0000000..49bb0c6
--- /dev/null
+++ b/libs/rs/java/Grass/res/drawable-hdpi/sunset.jpg
Binary files differ
diff --git a/libs/rs/java/Grass/res/raw/grass.c b/libs/rs/java/Grass/res/raw/grass.c
new file mode 100644
index 0000000..b1b89f0
--- /dev/null
+++ b/libs/rs/java/Grass/res/raw/grass.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+#pragma version(1)
+#pragma stateVertex(default)
+#pragma stateFragment(PFBackground)
+#pragma stateFragmentStore(PFSBackground)
+
+#define WVGA_PORTRAIT_WIDTH 480.0f
+#define WVGA_PORTRAIT_HEIGHT 762.0f
+
+#define RSID_STATE 0
+#define RSID_FRAMECOUNT 0
+
+#define RSID_SKY_TEXTURES 1
+#define RSID_SKY_TEXTURE_NIGHT 0
+#define RSID_SKY_TEXTURE_SUNRISE 1
+#define RSID_SKY_TEXTURE_NOON 2
+#define RSID_SKY_TEXTURE_SUNSET 3
+
+#define MIDNIGHT 0.0f
+#define MORNING 0.375f
+#define AFTERNOON 0.6f
+#define DUSK 0.8f
+
+#define SECONDS_IN_DAY 24.0f * 3600.0f
+
+#define REAL_TIME 0
+
+float time(int frameCount) {
+    if (REAL_TIME) {
+        return (hour() * 3600.0f + minute() * 60.0f + second()) / SECONDS_IN_DAY;
+    }
+    return (frameCount % 180) / 180.0f;
+}
+
+void alpha(float a) {
+    color(1.0f, 1.0f, 1.0f, a);
+}
+
+float norm(float a, float start, float end) {
+    return (a - start) / (end - start);
+}
+
+void drawNight() {
+    bindTexture(NAMED_PFBackground, 0, loadI32(RSID_SKY_TEXTURES, RSID_SKY_TEXTURE_NIGHT));
+    // NOTE: Hacky way to draw the night sky
+    drawRect(WVGA_PORTRAIT_WIDTH - 512.0f, -32.0f, WVGA_PORTRAIT_WIDTH, 1024.0f - 32.0f, 0.0f);
+}
+
+void drawSunrise() {
+    bindTexture(NAMED_PFBackground, 0, loadI32(RSID_SKY_TEXTURES, RSID_SKY_TEXTURE_SUNRISE));
+    drawRect(0.0f, 0.0f, WVGA_PORTRAIT_WIDTH, WVGA_PORTRAIT_HEIGHT, 0.0f);
+}
+
+void drawNoon() {
+    bindTexture(NAMED_PFBackground, 0, loadI32(RSID_SKY_TEXTURES, RSID_SKY_TEXTURE_NOON));
+    drawRect(0.0f, 0.0f, WVGA_PORTRAIT_WIDTH, WVGA_PORTRAIT_HEIGHT, 0.0f);
+}
+
+void drawSunset() {
+    bindTexture(NAMED_PFBackground, 0, loadI32(RSID_SKY_TEXTURES, RSID_SKY_TEXTURE_SUNSET));
+    drawRect(0.0f, 0.0f, WVGA_PORTRAIT_WIDTH, WVGA_PORTRAIT_HEIGHT, 0.0f);
+}
+
+int main(int launchID) {
+    int frameCount = loadI32(RSID_STATE, RSID_FRAMECOUNT);
+    float now = time(frameCount);
+    alpha(1.0f);
+
+    if (now >= MIDNIGHT && now < MORNING) {
+        drawNight();
+        alpha(norm(now, MIDNIGHT, MORNING));
+        drawSunrise();
+    }
+    
+    if (now >= MORNING && now < AFTERNOON) {
+        drawSunrise();
+        alpha(norm(now, MORNING, AFTERNOON));
+        drawNoon();
+    }
+
+    if (now >= AFTERNOON && now < DUSK) {
+        drawNoon();
+        alpha(norm(now, AFTERNOON, DUSK));
+        drawSunset();
+    }
+    
+    if (now >= DUSK) {
+        drawSunset();
+        alpha(norm(now, DUSK, 1.0f));
+        drawNight();
+    }
+
+    frameCount++;
+    storeI32(RSID_STATE, RSID_FRAMECOUNT, frameCount);
+
+    return 1;
+}
diff --git a/libs/rs/java/Grass/src/com/android/grass/rs/Grass.java b/libs/rs/java/Grass/src/com/android/grass/rs/Grass.java
new file mode 100644
index 0000000..260fcee
--- /dev/null
+++ b/libs/rs/java/Grass/src/com/android/grass/rs/Grass.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.grass.rs;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class Grass extends Activity {
+    private GrassView mView;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        mView = new GrassView(this);
+        setContentView(mView);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        mView.onResume();
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        mView.onPause();
+
+        Runtime.getRuntime().exit(0);
+    }
+}
diff --git a/libs/rs/java/Grass/src/com/android/grass/rs/GrassRS.java b/libs/rs/java/Grass/src/com/android/grass/rs/GrassRS.java
new file mode 100644
index 0000000..f5737da
--- /dev/null
+++ b/libs/rs/java/Grass/src/com/android/grass/rs/GrassRS.java
@@ -0,0 +1,152 @@
+/*
+ * 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.grass.rs;
+
+import android.content.res.Resources;
+import static android.renderscript.RenderScript.SamplerParam.*;
+import static android.renderscript.RenderScript.SamplerValue.*;
+import static android.renderscript.RenderScript.EnvMode.*;
+import static android.renderscript.RenderScript.DepthFunc.*;
+import static android.renderscript.RenderScript.BlendSrcFunc;
+import static android.renderscript.RenderScript.BlendDstFunc;
+
+import android.renderscript.RenderScript;
+import android.renderscript.Element;
+
+import java.util.TimeZone;
+
+class GrassRS {
+    private static final int RSID_STATE = 0;
+    private static final int RSID_SKY_TEXTURES = 1;
+    private static final int SKY_TEXTURES_COUNT = 4;
+
+    private Resources mResources;
+    private RenderScript mRS;
+
+    @SuppressWarnings({"FieldCanBeLocal"})
+    private RenderScript.Script mScript;
+    @SuppressWarnings({"FieldCanBeLocal"})
+    private RenderScript.Sampler mSampler;
+    @SuppressWarnings({"FieldCanBeLocal"})
+    private RenderScript.ProgramFragment mPfBackground;
+    @SuppressWarnings({"FieldCanBeLocal"})
+    private RenderScript.ProgramFragmentStore mPfsBackground;
+
+    @SuppressWarnings({"FieldCanBeLocal"})
+    private RenderScript.Allocation mSkyTexturesIDs;
+    @SuppressWarnings({"FieldCanBeLocal"})
+    private RenderScript.Allocation[] mSkyTextures;
+    @SuppressWarnings({"FieldCanBeLocal"})
+    private int[] mSkyBufferIDs;
+    @SuppressWarnings({"FieldCanBeLocal"})
+    private RenderScript.Allocation mState;
+
+    public GrassRS() {
+    }
+
+    public void init(RenderScript rs, Resources res) {
+        mRS = rs;
+        mResources = res;
+        initRS();
+    }
+
+    private void initRS() {
+        createProgramVertex();
+        createProgramFragmentStore();
+        createProgramFragment();
+        createScriptStructures();
+        
+        mRS.scriptCBegin();
+        mRS.scriptCSetClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+        mRS.scriptCSetScript(mResources, R.raw.grass);
+        mRS.scriptCSetTimeZone(TimeZone.getDefault().getID());
+        mRS.scriptCSetRoot(true);
+
+        mScript = mRS.scriptCCreate();
+
+        loadSkyTextures();        
+        mScript.bindAllocation(mState, RSID_STATE);
+        mScript.bindAllocation(mSkyTexturesIDs, RSID_SKY_TEXTURES);
+
+        mRS.contextBindRootScript(mScript);        
+    }
+
+    private void createScriptStructures() {
+        mState = mRS.allocationCreateSized(Element.USER_I32, 1);    
+        mState.data(new int[1]);
+    }
+
+    private void loadSkyTextures() {
+        mSkyBufferIDs = new int[SKY_TEXTURES_COUNT];
+        mSkyTextures = new RenderScript.Allocation[SKY_TEXTURES_COUNT];
+        mSkyTexturesIDs = mRS.allocationCreateSized(
+                Element.USER_FLOAT, SKY_TEXTURES_COUNT);
+
+        final RenderScript.Allocation[] textures = mSkyTextures;
+        textures[0] = loadTexture(R.drawable.night, "night");
+        textures[1] = loadTexture(R.drawable.sunrise, "sunrise");
+        textures[2] = loadTexture(R.drawable.sky, "sky");
+        textures[3] = loadTexture(R.drawable.sunset, "sunset");
+
+        final int[] bufferIds = mSkyBufferIDs;
+        final int count = textures.length;
+
+        for (int i = 0; i < count; i++) {
+            final RenderScript.Allocation texture = textures[i];
+            texture.uploadToTexture(0);
+            bufferIds[i] = texture.getID();
+        }
+
+        mSkyTexturesIDs.data(bufferIds);
+    }
+
+    private RenderScript.Allocation loadTexture(int id, String name) {
+        RenderScript.Allocation allocation = mRS.allocationCreateFromBitmapResource(mResources, id,
+                Element.RGB_565, false);
+        allocation.setName(name);
+        return allocation;
+    }
+
+    private void createProgramFragment() {
+        mRS.samplerBegin();
+        mRS.samplerSet(FILTER_MIN, LINEAR);
+        mRS.samplerSet(FILTER_MAG, LINEAR);
+        mRS.samplerSet(WRAP_MODE_S, CLAMP);
+        mRS.samplerSet(WRAP_MODE_T, CLAMP);
+        mSampler = mRS.samplerCreate();
+
+        mRS.programFragmentBegin(null, null);
+        mRS.programFragmentSetTexEnable(0, true);
+        mRS.programFragmentSetTexEnvMode(0, REPLACE);
+        mPfBackground = mRS.programFragmentCreate();
+        mPfBackground.setName("PFBackground");
+        mPfBackground.bindSampler(mSampler, 0);
+    }
+
+    private void createProgramFragmentStore() {
+        mRS.programFragmentStoreBegin(null, null);
+        mRS.programFragmentStoreDepthFunc(ALWAYS);
+        mRS.programFragmentStoreBlendFunc(BlendSrcFunc.SRC_ALPHA, BlendDstFunc.ONE_MINUS_SRC_ALPHA);
+        mRS.programFragmentStoreDitherEnable(true);
+        mRS.programFragmentStoreDepthMask(false);
+        mPfsBackground = mRS.programFragmentStoreCreate();
+        mPfsBackground.setName("PFSBackground");
+    }
+
+    private void createProgramVertex() {
+    }
+}
diff --git a/libs/rs/java/Grass/src/com/android/grass/rs/GrassView.java b/libs/rs/java/Grass/src/com/android/grass/rs/GrassView.java
new file mode 100644
index 0000000..a641e1e
--- /dev/null
+++ b/libs/rs/java/Grass/src/com/android/grass/rs/GrassView.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.grass.rs;
+
+import android.content.Context;
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+import android.view.SurfaceHolder;
+
+class GrassView extends RSSurfaceView {
+    public GrassView(Context context) {
+        super(context);
+    }
+
+    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
+        super.surfaceChanged(holder, format, w, h);
+
+        RenderScript RS = createRenderScript();
+        GrassRS render = new GrassRS();
+        render.init(RS, getResources());
+    }
+}
diff --git a/libs/rs/java/Rollo/res/raw/rollo.c b/libs/rs/java/Rollo/res/raw/rollo.c
index 8763a34..a527588 100644
--- a/libs/rs/java/Rollo/res/raw/rollo.c
+++ b/libs/rs/java/Rollo/res/raw/rollo.c
@@ -90,9 +90,6 @@
             float ty1 = ((y * 3.1f) - 5.f) * scale;
             float ty2 = ty1 + scale * 1.8f;
             bindTexture(NAMED_PF, 0, loadI32(1, index));
-            //if (done && (index != selectedID)) {
-                //color(0.4f, 0.4f, 0.4f, 1.0f);
-            //}
             drawQuad(tx1, ty1, tz1,
                      tx2, ty1, tz2,
                      tx2, ty2, tz2,
diff --git a/libs/rs/java/Rollo/src/com/android/rollo/RolloMesh.java b/libs/rs/java/Rollo/src/com/android/rollo/RolloMesh.java
deleted file mode 100644
index d7252fb..0000000
--- a/libs/rs/java/Rollo/src/com/android/rollo/RolloMesh.java
+++ /dev/null
@@ -1,90 +0,0 @@
- /*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-package com.android.rollo;
-
-import java.io.Writer;
-import java.lang.Math;
-
-import android.renderscript.RenderScript;
-
-
-class RolloMesh {
-    static public final float mCardHeight = 1.2f;
-    static public final float mCardWidth = 1.8f;
-    static public final float mTabHeight = 0.2f;
-    static public final float mTabs = 3;
-    static public final float mTabGap = 0.1f;
-
-    static RenderScript.TriangleMesh createCard(RenderScript rs) {
-        RenderScript.Element vtx = rs.elementGetPredefined(
-            RenderScript.ElementPredefined.ST_XYZ_F32);
-        RenderScript.Element idx = rs.elementGetPredefined(
-            RenderScript.ElementPredefined.INDEX_16);
-
-        float w = mCardWidth / 2;
-        float h = mCardHeight;
-        float z = 0;
-
-        rs.triangleMeshBegin(vtx, idx);
-        rs.triangleMeshAddVertex_XYZ_ST(-w, 0, z,  0, 0);
-        rs.triangleMeshAddVertex_XYZ_ST(-w, h, z,  0, 1);
-        rs.triangleMeshAddVertex_XYZ_ST( w, h, z,  1, 1);
-        rs.triangleMeshAddVertex_XYZ_ST( w, 0, z,  1, 0);
-        rs.triangleMeshAddTriangle(0,1,2);
-        rs.triangleMeshAddTriangle(0,2,3);
-        return rs.triangleMeshCreate();
-    }
-
-    static RenderScript.TriangleMesh createTab(RenderScript rs) {
-        RenderScript.Element vtx = rs.elementGetPredefined(
-            RenderScript.ElementPredefined.ST_XYZ_F32);
-        RenderScript.Element idx = rs.elementGetPredefined(
-            RenderScript.ElementPredefined.INDEX_16);
-
-
-        float tabSlope = 0.1f;
-        float num = 0;
-
-        float w = (mCardWidth - ((mTabs - 1) * mTabGap)) / mTabs;
-        float w1 = -(mCardWidth / 2) + ((w + mTabGap) * num);
-        float w2 = w1 + (w * tabSlope);
-        float w3 = w1 + w - (w * tabSlope);
-        float w4 = w1 + w;
-        float h1 = mCardHeight;
-        float h2 = h1 + mTabHeight;
-        float z = 0;
-
-        float stScale = w / mTabHeight / 2;
-        float stScale2 = stScale * (tabSlope / w);
-
-
-        rs.triangleMeshBegin(vtx, idx);
-        rs.triangleMeshAddVertex_XYZ_ST(w1, h1, z,  -stScale, 0);
-        rs.triangleMeshAddVertex_XYZ_ST(w2, h2, z,  -stScale2, 1);
-        rs.triangleMeshAddVertex_XYZ_ST(w3, h2, z,   stScale2, 1);
-        rs.triangleMeshAddVertex_XYZ_ST(w4, h1, z,   stScale, 0);
-        rs.triangleMeshAddTriangle(0,1,2);
-        rs.triangleMeshAddTriangle(0,2,3);
-        return rs.triangleMeshCreate();
-    }
-
-
-
-}
-
-
diff --git a/libs/rs/java/Rollo/src/com/android/rollo/RolloRS.java b/libs/rs/java/Rollo/src/com/android/rollo/RolloRS.java
index 039d4e9..7f9727c 100644
--- a/libs/rs/java/Rollo/src/com/android/rollo/RolloRS.java
+++ b/libs/rs/java/Rollo/src/com/android/rollo/RolloRS.java
@@ -20,9 +20,8 @@
 
 import android.renderscript.RenderScript;
 import android.renderscript.ProgramVertexAlloc;
+import android.renderscript.Element;
 
-import android.content.Context;
-import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
@@ -30,8 +29,9 @@
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.Typeface;
-import android.os.Handler;
-import android.os.Message;
+
+import android.content.Context;
+import android.content.res.Resources;
 import android.util.Log;
 
 public class RolloRS {
@@ -190,8 +190,8 @@
         mRS.contextBindProgramVertex(mPV);
 
         mAllocScratchBuf = new int[32];
-        mAllocScratch = mRS.allocationCreatePredefSized(
-            RenderScript.ElementPredefined.USER_I32, mAllocScratchBuf.length);
+        mAllocScratch = mRS.allocationCreateSized(
+            Element.USER_I32, mAllocScratchBuf.length);
         mAllocScratch.data(mAllocScratchBuf);
 
         Log.e("rs", "Done loading named");
@@ -201,18 +201,15 @@
         {
             mIcons = new RenderScript.Allocation[29];
             mAllocIconIDBuf = new int[mIcons.length];
-            mAllocIconID = mRS.allocationCreatePredefSized(
-                RenderScript.ElementPredefined.USER_I32, mAllocIconIDBuf.length);
+            mAllocIconID = mRS.allocationCreateSized(
+                Element.USER_I32, mAllocIconIDBuf.length);
 
             mLabels = new RenderScript.Allocation[29];
             mAllocLabelIDBuf = new int[mLabels.length];
-            mAllocLabelID = mRS.allocationCreatePredefSized(
-                RenderScript.ElementPredefined.USER_I32, mLabels.length);
+            mAllocLabelID = mRS.allocationCreateSized(
+                Element.USER_I32, mLabels.length);
 
-            RenderScript.ElementPredefined ie565 =
-                RenderScript.ElementPredefined.RGB_565;
-            RenderScript.ElementPredefined ie8888 =
-                RenderScript.ElementPredefined.RGBA_8888;
+            Element ie8888 = Element.RGBA_8888;
 
             mIcons[0] = mRS.allocationCreateFromBitmapResource(mRes, R.raw.browser, ie8888, true);
             mIcons[1] = mRS.allocationCreateFromBitmapResource(mRes, R.raw.market, ie8888, true);
@@ -310,7 +307,7 @@
         p.setTextSize(20);
         p.setColor(0xffffffff);
         c.drawText(t, 2, 26, p);
-        return mRS.allocationCreateFromBitmap(b, RenderScript.ElementPredefined.RGBA_8888, true);
+        return mRS.allocationCreateFromBitmap(b, Element.RGBA_8888, true);
     }
 
 
@@ -323,8 +320,8 @@
         mScript = mRS.scriptCCreate();
 
         mAllocStateBuf = new int[] {0, 0, 0, 8, 0, 0, -1, 0, mAllocIconIDBuf.length, 0, 0};
-        mAllocState = mRS.allocationCreatePredefSized(
-            RenderScript.ElementPredefined.USER_I32, mAllocStateBuf.length);
+        mAllocState = mRS.allocationCreateSized(
+            Element.USER_I32, mAllocStateBuf.length);
         mScript.bindAllocation(mAllocState, 0);
         mScript.bindAllocation(mAllocIconID, 1);
         mScript.bindAllocation(mAllocScratch, 2);
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index 45e6d1b..d9a6456 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -280,6 +280,11 @@
 	param float a
 	}
 
+ScriptCSetTimeZone {
+	param const char * timeZone
+	param uint32_t length
+	}
+
 ScriptCSetClearDepth {
 	param float depth
 	}
diff --git a/libs/rs/rsScript.h b/libs/rs/rsScript.h
index 7dd2b61..a8e04a6 100644
--- a/libs/rs/rsScript.h
+++ b/libs/rs/rsScript.h
@@ -43,6 +43,9 @@
         float mClearDepth;
         uint32_t mClearStencil;
 
+        uint32_t mStartTimeMillis;
+        const char* mTimeZone;
+
         ObjectBaseRef<ProgramVertex> mVertex;
         ObjectBaseRef<ProgramFragment> mFragment;
         //ObjectBaseRef<ProgramRaster> mRaster;
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index 842c836..3b9d27a 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -230,6 +230,12 @@
     ss->mEnviroment.mClearColor[3] = a;
 }
 
+void rsi_ScriptCSetTimeZone(Context * rsc, const char * timeZone, uint32_t length)
+{
+    ScriptCState *ss = &rsc->mScriptC;
+    ss->mEnviroment.mTimeZone = timeZone;
+}
+
 void rsi_ScriptCSetClearDepth(Context * rsc, float v)
 {
     ScriptCState *ss = &rsc->mScriptC;
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
index 7db3619..21c9753 100644
--- a/libs/rs/rsScriptC_Lib.cpp
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -24,6 +24,9 @@
 #include <GLES/gl.h>
 #include <GLES/glext.h>
 
+#include <time.h>
+#include <cutils/tztime.h>
+
 using namespace android;
 using namespace android::renderscript;
 
@@ -126,14 +129,203 @@
 // Math routines
 //////////////////////////////////////////////////////////////////////////////
 
+#define PI 3.1415926f
+#define DEG_TO_RAD PI / 180.0f
+#define RAD_TO_DEG 180.0f / PI
+
 static float SC_randf(float max)
 {
     float r = (float)rand();
     return r / RAND_MAX * max;
 }
 
+static float SC_randf2(float min, float max)
+{
+    float r = (float)rand();
+    return r / RAND_MAX * (max - min) + min;
+}
 
+static float SC_clampf(float amount, float low, float high)
+{
+    return amount < low ? low : (amount > high ? high : amount);
+}
 
+static float SC_maxf(float a, float b)
+{
+    return a > b ? a : b; 
+}
+
+static float SC_minf(float a, float b)
+{
+    return a < b ? a : b; 
+}
+
+static float SC_sqrf(float v)
+{
+    return v * v; 
+}
+
+static float SC_distf2(float x1, float y1, float x2, float y2)
+{
+    float x = x2 - x1;
+    float y = y2 - y1;
+    return sqrtf(x * x + y * y); 
+}
+
+static float SC_distf3(float x1, float y1, float z1, float x2, float y2, float z2)
+{
+    float x = x2 - x1;
+    float y = y2 - y1;
+    float z = z2 - z1;
+    return sqrtf(x * x + y * y + z * z); 
+}
+
+static float SC_magf2(float a, float b)
+{
+    return sqrtf(a * a + b * b);
+}
+
+static float SC_magf3(float a, float b, float c)
+{
+    return sqrtf(a * a + b * b + c * c);
+}
+
+static float SC_radf(float degrees)
+{
+    return degrees * DEG_TO_RAD; 
+}
+
+static float SC_degf(float radians)
+{
+    return radians * RAD_TO_DEG; 
+}
+
+static float SC_lerpf(float start, float stop, float amount)
+{
+    return start + (stop - start) * amount;
+}
+
+static float SC_normf(float start, float stop, float value)
+{
+    return (value - start) / (stop - start);
+}
+
+static float SC_mapf(float minStart, float minStop, float maxStart, float maxStop, float value)
+{
+    return maxStart + (maxStart - maxStop) * ((value - minStart) / (minStop - minStart));
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Time routines
+//////////////////////////////////////////////////////////////////////////////
+
+static uint32_t SC_second()
+{
+    GET_TLS();
+
+    time_t rawtime;
+    time(&rawtime);
+
+    if (sc->mEnviroment.mTimeZone) {
+        struct tm timeinfo;
+        localtime_tz(&rawtime, &timeinfo, sc->mEnviroment.mTimeZone);
+        return timeinfo.tm_sec;
+    } else {
+        struct tm *timeinfo;
+        timeinfo = localtime(&rawtime);
+        return timeinfo->tm_sec;
+    }
+}
+
+static uint32_t SC_minute()
+{
+    GET_TLS();
+    
+    time_t rawtime;
+    time(&rawtime);
+    
+    if (sc->mEnviroment.mTimeZone) {
+        struct tm timeinfo;
+        localtime_tz(&rawtime, &timeinfo, sc->mEnviroment.mTimeZone);
+        return timeinfo.tm_min;
+    } else {
+        struct tm *timeinfo;
+        timeinfo = localtime(&rawtime);
+        return timeinfo->tm_min;
+    }
+}   
+
+static uint32_t SC_hour()
+{
+    GET_TLS();
+    
+    time_t rawtime;
+    time(&rawtime);
+    
+    if (sc->mEnviroment.mTimeZone) {
+        struct tm timeinfo;
+        localtime_tz(&rawtime, &timeinfo, sc->mEnviroment.mTimeZone);
+        return timeinfo.tm_hour;
+    } else {
+        struct tm *timeinfo;
+        timeinfo = localtime(&rawtime);
+        return timeinfo->tm_hour;
+    }
+}
+
+static uint32_t SC_day()
+{
+    GET_TLS();
+    
+    time_t rawtime;
+    time(&rawtime);
+    
+    if (sc->mEnviroment.mTimeZone) {
+        struct tm timeinfo;
+        localtime_tz(&rawtime, &timeinfo, sc->mEnviroment.mTimeZone);
+        return timeinfo.tm_mday;
+    } else {
+        struct tm *timeinfo;
+        timeinfo = localtime(&rawtime);
+        return timeinfo->tm_mday;
+    }
+}   
+
+static uint32_t SC_month()
+{
+    GET_TLS();
+    
+    time_t rawtime;
+    time(&rawtime);
+    
+    if (sc->mEnviroment.mTimeZone) {
+        struct tm timeinfo;
+        localtime_tz(&rawtime, &timeinfo, sc->mEnviroment.mTimeZone);
+        return timeinfo.tm_mon;
+    } else {
+        struct tm *timeinfo;
+        timeinfo = localtime(&rawtime);
+        return timeinfo->tm_mon;
+    }
+} 
+
+static uint32_t SC_year()
+{
+    GET_TLS();
+    
+    time_t rawtime;
+    time(&rawtime);
+    
+    if (sc->mEnviroment.mTimeZone) {
+        struct tm timeinfo;
+        localtime_tz(&rawtime, &timeinfo, sc->mEnviroment.mTimeZone);
+        return timeinfo.tm_year;
+    } else {
+        struct tm *timeinfo;
+        timeinfo = localtime(&rawtime);
+        return timeinfo->tm_year;
+    }
+}
 
 //////////////////////////////////////////////////////////////////////////////
 // Matrix routines
@@ -451,14 +643,72 @@
         "float", "(float)" },
     { "cosf", (void *)&cosf,
         "float", "(float)" },
+    { "asinf", (void *)&asinf,
+        "float", "(float)" },
+    { "acosf", (void *)&acosf,
+        "float", "(float)" },
+    { "atanf", (void *)&atanf,
+        "float", "(float)" },
+    { "atan2f", (void *)&atan2f,
+        "float", "(floatm float)" },
     { "fabsf", (void *)&fabsf,
         "float", "(float)" },
     { "randf", (void *)&SC_randf,
         "float", "(float)" },
+    { "randf2", (void *)&SC_randf2,
+        "float", "(float, float)" },
     { "floorf", (void *)&floorf,
         "float", "(float)" },
     { "ceilf", (void *)&ceilf,
         "float", "(float)" },
+    { "expf", (void *)&expf,
+        "float", "(float)" },
+    { "logf", (void *)&logf,
+        "float", "(float)" },
+    { "powf", (void *)&powf,
+        "float", "(float, float)" },
+    { "maxf", (void *)&SC_maxf,
+        "float", "(float, float)" },
+    { "minf", (void *)&SC_minf,
+        "float", "(float, float)" },
+    { "sqrtf", (void *)&sqrtf,
+        "float", "(float)" },
+    { "sqrf", (void *)&SC_sqrf,
+        "float", "(float)" },
+    { "clampf", (void *)&SC_clampf,
+        "float", "(float, float, float)" },
+    { "distf2", (void *)&SC_distf2,
+        "float", "(float, float, float, float)" },
+    { "distf3", (void *)&SC_distf3,
+        "float", "(float, float, float, float, float, float)" },
+    { "magf2", (void *)&SC_magf2,
+        "float", "(float, float)" },
+    { "magf3", (void *)&SC_magf3,
+        "float", "(float, float, float)" },
+    { "radf", (void *)&SC_radf,
+        "float", "(float)" },
+    { "degf", (void *)&SC_degf,
+        "float", "(float)" },
+    { "lerpf", (void *)&SC_lerpf,
+        "float", "(float, float, float)" },
+    { "normf", (void *)&SC_normf,
+        "float", "(float, float, float)" },
+    { "mapf", (void *)&SC_mapf,
+        "float", "(float, float, float, float, float)" },
+
+    // time
+    { "second", (void *)&SC_second,
+        "int", "()" },
+    { "minute", (void *)&SC_minute,
+        "int", "()" },
+    { "hour", (void *)&SC_hour,
+        "int", "()" },
+    { "day", (void *)&SC_day,
+        "int", "()" },
+    { "month", (void *)&SC_month,
+        "int", "()" },
+    { "year", (void *)&SC_year,
+        "int", "()" },
 
     // matrix
     { "matrixLoadIdentity", (void *)&SC_matrixLoadIdentity,
diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp
index 8c8fd6b..8b7ea21 100644
--- a/libs/ui/FramebufferNativeWindow.cpp
+++ b/libs/ui/FramebufferNativeWindow.cpp
@@ -124,6 +124,7 @@
     android_native_window_t::dequeueBuffer = dequeueBuffer;
     android_native_window_t::lockBuffer = lockBuffer;
     android_native_window_t::queueBuffer = queueBuffer;
+    android_native_window_t::query = query;
 }
 
 FramebufferNativeWindow::~FramebufferNativeWindow() {
@@ -198,6 +199,23 @@
     return res;
 }
 
+int FramebufferNativeWindow::query(android_native_window_t* window,
+        int what, int* value) 
+{
+    FramebufferNativeWindow* self = getSelf(window);
+    Mutex::Autolock _l(self->mutex);
+    framebuffer_device_t* fb = self->fbDev;
+    switch (what) {
+        case NATIVE_WINDOW_WIDTH:
+            *value = fb->width;
+            return NO_ERROR;
+        case NATIVE_WINDOW_HEIGHT:
+            *value = fb->height;
+            return NO_ERROR;
+    }
+    return BAD_VALUE;
+}
+
 // ----------------------------------------------------------------------------
 }; // namespace android
 // ----------------------------------------------------------------------------
diff --git a/libs/ui/Surface.cpp b/libs/ui/Surface.cpp
index aef47fd..a4710aa 100644
--- a/libs/ui/Surface.cpp
+++ b/libs/ui/Surface.cpp
@@ -180,7 +180,7 @@
         uint32_t w, uint32_t h, PixelFormat format, uint32_t flags)
     : mClient(client), mSurface(surface),
       mToken(data.token), mIdentity(data.identity),
-      mFormat(format), mFlags(flags)
+      mWidth(w), mHeight(h), mFormat(format), mFlags(flags)
 {
 }
         
@@ -338,6 +338,8 @@
     uint32_t format = 0;
     SurfaceID token = -1;
     uint32_t identity = 0;
+    uint32_t width = 0;
+    uint32_t height = 0;
     sp<SurfaceComposerClient> client;
     sp<ISurface> sur;
     if (SurfaceControl::isValid(control)) {
@@ -345,6 +347,8 @@
         identity = control->mIdentity;
         client   = control->mClient;
         sur      = control->mSurface;
+        width    = control->mWidth;
+        height   = control->mHeight;
         format   = control->mFormat;
         flags    = control->mFlags;
     }
@@ -352,6 +356,8 @@
     parcel->writeStrongBinder(sur!=0     ? sur->asBinder()      : NULL);
     parcel->writeInt32(token);
     parcel->writeInt32(identity);
+    parcel->writeInt32(width);
+    parcel->writeInt32(height);
     parcel->writeInt32(format);
     parcel->writeInt32(flags);
     return NO_ERROR;
@@ -373,6 +379,7 @@
 Surface::Surface(const sp<SurfaceControl>& surface)
     : mClient(surface->mClient), mSurface(surface->mSurface),
       mToken(surface->mToken), mIdentity(surface->mIdentity),
+      mWidth(surface->mWidth), mHeight(surface->mHeight),
       mFormat(surface->mFormat), mFlags(surface->mFlags),
       mBufferMapper(BufferMapper::get())
 {
@@ -386,6 +393,8 @@
     mSurface    = interface_cast<ISurface>(parcel.readStrongBinder());
     mToken      = parcel.readInt32();
     mIdentity   = parcel.readInt32();
+    mWidth      = parcel.readInt32();
+    mHeight     = parcel.readInt32();
     mFormat     = parcel.readInt32();
     mFlags      = parcel.readInt32();
 
@@ -401,6 +410,7 @@
     android_native_window_t::dequeueBuffer    = dequeueBuffer;
     android_native_window_t::lockBuffer       = lockBuffer;
     android_native_window_t::queueBuffer      = queueBuffer;
+    android_native_window_t::query            = query;
     mSwapRectangle.makeInvalid();
     DisplayInfo dinfo;
     SurfaceComposerClient::getDisplayInfo(0, &dinfo);
@@ -492,6 +502,13 @@
     return self->queueBuffer(buffer);
 }
 
+int Surface::query(android_native_window_t* window, 
+        int what, int* value)
+{
+    Surface* self = getSelf(window);
+    return self->query(what, value);
+}
+
 // ----------------------------------------------------------------------------
 
 status_t Surface::dequeueBuffer(sp<SurfaceBuffer>* buffer)
@@ -499,6 +516,9 @@
     android_native_buffer_t* out;
     status_t err = dequeueBuffer(&out);
     *buffer = SurfaceBuffer::getSelf(out);
+    // reset the width/height with the what we get from the buffer
+    mWidth  = uint32_t(out->width);
+    mHeight = uint32_t(out->height);
     return err;
 }
 
@@ -538,14 +558,16 @@
 
     volatile const surface_info_t* const back = lcblk->surface + backIdx;
     if (back->flags & surface_info_t::eNeedNewBuffer) {
-        getBufferLocked(backIdx);
+        err = getBufferLocked(backIdx);
     }
 
-    const sp<SurfaceBuffer>& backBuffer(mBuffers[backIdx]);
-    mDirtyRegion.set(backBuffer->width, backBuffer->height);
-    *buffer = backBuffer.get();
+    if (err == NO_ERROR) {
+        const sp<SurfaceBuffer>& backBuffer(mBuffers[backIdx]);
+        mDirtyRegion.set(backBuffer->width, backBuffer->height);
+        *buffer = backBuffer.get();
+    }
   
-    return NO_ERROR;
+    return err;
 }
 
 int Surface::lockBuffer(android_native_buffer_t* buffer)
@@ -586,6 +608,19 @@
     return NO_ERROR;
 }
 
+int Surface::query(int what, int* value)
+{
+    switch (what) {
+        case NATIVE_WINDOW_WIDTH:
+            *value = int(mWidth);
+            return NO_ERROR;
+        case NATIVE_WINDOW_HEIGHT:
+            *value = int(mHeight);
+            return NO_ERROR;
+    }
+    return BAD_VALUE;
+}
+
 // ----------------------------------------------------------------------------
 
 status_t Surface::lock(SurfaceInfo* info, bool blocking) {
@@ -696,7 +731,7 @@
             currentBuffer.clear();
         }
         err = getBufferMapper().registerBuffer(buffer->handle);
-        LOGW_IF(err, "map(...) failed %d (%s)", err, strerror(-err));
+        LOGW_IF(err, "registerBuffer(...) failed %d (%s)", err, strerror(-err));
         if (err == NO_ERROR) {
             currentBuffer = buffer;
         }
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index 4dca8bd..0831f4a 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -1486,7 +1486,7 @@
 
 ssize_t ResTable::Theme::resolveAttributeReference(Res_value* inOutValue,
         ssize_t blockIndex, uint32_t* outLastRef,
-        uint32_t* inoutTypeSpecFlags) const
+        uint32_t* inoutTypeSpecFlags, ResTable_config* inoutConfig) const
 {
     //printf("Resolving type=0x%x\n", inOutValue->dataType);
     if (inOutValue->dataType == Res_value::TYPE_ATTRIBUTE) {
@@ -1498,7 +1498,8 @@
             return blockIndex;
         }
     }
-    return mTable.resolveReference(inOutValue, blockIndex, outLastRef);
+    return mTable.resolveReference(inOutValue, blockIndex, outLastRef,
+            inoutTypeSpecFlags, inoutConfig);
 }
 
 void ResTable::Theme::dumpToLog() const
@@ -1891,7 +1892,8 @@
 }
 
 ssize_t ResTable::resolveReference(Res_value* value, ssize_t blockIndex,
-        uint32_t* outLastRef, uint32_t* inoutTypeSpecFlags) const
+        uint32_t* outLastRef, uint32_t* inoutTypeSpecFlags,
+        ResTable_config* outConfig) const
 {
     int count=0;
     while (blockIndex >= 0 && value->dataType == value->TYPE_REFERENCE
@@ -1899,7 +1901,8 @@
         if (outLastRef) *outLastRef = value->data;
         uint32_t lastRef = value->data;
         uint32_t newFlags = 0;
-        const ssize_t newIndex = getResource(value->data, value, true, &newFlags);
+        const ssize_t newIndex = getResource(value->data, value, true, &newFlags,
+                outConfig);
         //LOGI("Resolving reference d=%p: newIndex=%d, t=0x%02x, d=%p\n",
         //     (void*)lastRef, (int)newIndex, (int)value->dataType, (void*)value->data);
         //printf("Getting reference 0x%08x: newIndex=%d\n", value->data, newIndex);
diff --git a/media/java/android/media/JetPlayer.java b/media/java/android/media/JetPlayer.java
index 2263605..1570db4 100644
--- a/media/java/android/media/JetPlayer.java
+++ b/media/java/android/media/JetPlayer.java
@@ -183,6 +183,7 @@
      */
     public void release() {
         native_release();
+        singletonRef = null;
     }
     
     
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index 0d07abe..b17e31b 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -93,7 +93,7 @@
 
 void SoundPool::addToRestartList(SoundChannel* channel)
 {
-    Mutex::Autolock lock(&mLock);
+    Mutex::Autolock lock(&mRestartLock);
     mRestart.push_back(channel);
     mCondition.signal();
 }
@@ -106,9 +106,9 @@
 
 int SoundPool::run()
 {
-    mLock.lock();
+    mRestartLock.lock();
     while (!mQuit) {
-        mCondition.wait(mLock);
+        mCondition.wait(mRestartLock);
         LOGV("awake");
         if (mQuit) break;
 
@@ -125,19 +125,19 @@
 
     mRestart.clear();
     mCondition.signal();
-    mLock.unlock();
+    mRestartLock.unlock();
     LOGV("goodbye");
     return 0;
 }
 
 void SoundPool::quit()
 {
-    mLock.lock();
+    mRestartLock.lock();
     mQuit = true;
     mCondition.signal();
-    mCondition.wait(mLock);
+    mCondition.wait(mRestartLock);
     LOGV("return from quit");
-    mLock.unlock();
+    mRestartLock.unlock();
 }
 
 bool SoundPool::startThreads()
@@ -484,11 +484,8 @@
     // if not idle, this voice is being stolen
     if (mState != IDLE) {
         LOGV("channel %d stolen - event queued for channel %d", channelID(), nextChannelID);
-        stop_l();
         mNextEvent.set(sample, nextChannelID, leftVolume, rightVolume, priority, loop, rate);
-#ifdef USE_SHARED_MEM_BUFFER
-        mSoundPool->done(this);
-#endif
+        stop();
         return;
     }
 
diff --git a/media/jni/soundpool/SoundPool.h b/media/jni/soundpool/SoundPool.h
index 7802781..ab86e90 100644
--- a/media/jni/soundpool/SoundPool.h
+++ b/media/jni/soundpool/SoundPool.h
@@ -204,6 +204,7 @@
 
     jobject                 mSoundPoolRef;
     Mutex                   mLock;
+    Mutex                   mRestartLock;
     Condition               mCondition;
     SoundPoolThread*        mDecodeThread;
     SoundChannel*           mChannelPool;
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index f2a657a..4661af6 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -5,6 +5,7 @@
 #include <binder/IMemory.h>
 #include <binder/Parcel.h>
 #include <media/IOMX.h>
+#include <ui/ISurface.h>
 
 namespace android {
 
@@ -23,7 +24,9 @@
     OBSERVE_NODE,
     FILL_BUFFER,
     EMPTY_BUFFER,
+    CREATE_RENDERER,
     OBSERVER_ON_MSG,
+    RENDERER_RENDER,
 };
 
 static void *readVoidStar(const Parcel *parcel) {
@@ -262,6 +265,28 @@
         remote()->transact(EMPTY_BUFFER, data, &reply, IBinder::FLAG_ONEWAY);
     }
 #endif
+
+    virtual sp<IOMXRenderer> createRenderer(
+            const sp<ISurface> &surface,
+            const char *componentName,
+            OMX_COLOR_FORMATTYPE colorFormat,
+            size_t encodedWidth, size_t encodedHeight,
+            size_t displayWidth, size_t displayHeight) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+
+        data.writeStrongBinder(surface->asBinder());
+        data.writeCString(componentName);
+        data.writeInt32(colorFormat);
+        data.writeInt32(encodedWidth);
+        data.writeInt32(encodedHeight);
+        data.writeInt32(displayWidth);
+        data.writeInt32(displayHeight);
+
+        remote()->transact(CREATE_RENDERER, data, &reply);
+
+        return interface_cast<IOMXRenderer>(reply.readStrongBinder());
+    }
 };
 
 IMPLEMENT_META_INTERFACE(OMX, "android.hardware.IOMX");
@@ -513,6 +538,33 @@
         }
 #endif
 
+        case CREATE_RENDERER:
+        {
+            CHECK_INTERFACE(IOMX, data, reply);
+
+            sp<ISurface> isurface =
+                interface_cast<ISurface>(data.readStrongBinder());
+
+            const char *componentName = data.readCString();
+
+            OMX_COLOR_FORMATTYPE colorFormat =
+                static_cast<OMX_COLOR_FORMATTYPE>(data.readInt32());
+
+            size_t encodedWidth = (size_t)data.readInt32();
+            size_t encodedHeight = (size_t)data.readInt32();
+            size_t displayWidth = (size_t)data.readInt32();
+            size_t displayHeight = (size_t)data.readInt32();
+
+            sp<IOMXRenderer> renderer =
+                createRenderer(isurface, componentName, colorFormat,
+                               encodedWidth, encodedHeight,
+                               displayWidth, displayHeight);
+
+            reply->writeStrongBinder(renderer->asBinder());
+
+            return OK;
+        }
+
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
@@ -558,4 +610,44 @@
     }
 }
 
+////////////////////////////////////////////////////////////////////////////////
+
+class BpOMXRenderer : public BpInterface<IOMXRenderer> {
+public:
+    BpOMXRenderer(const sp<IBinder> &impl)
+        : BpInterface<IOMXRenderer>(impl) {
+    }
+
+    virtual void render(IOMX::buffer_id buffer) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IOMXRenderer::getInterfaceDescriptor());
+        writeVoidStar(buffer, &data);
+
+        // NOTE: Do NOT make this a ONE_WAY call, it must be synchronous
+        // so that the caller knows when to recycle the buffer.
+        remote()->transact(RENDERER_RENDER, data, &reply);
+    }
+};
+
+IMPLEMENT_META_INTERFACE(OMXRenderer, "android.hardware.IOMXRenderer");
+
+status_t BnOMXRenderer::onTransact(
+    uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
+    switch (code) {
+        case RENDERER_RENDER:
+        {
+            CHECK_INTERFACE(IOMXRenderer, data, reply);
+
+            IOMX::buffer_id buffer = readVoidStar(&data);
+
+            render(buffer);
+
+            return NO_ERROR;
+        }
+
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
 }  // namespace android
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 5be9224..0a44762 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -19,14 +19,10 @@
         MediaSource.cpp           \
         MetaData.cpp              \
         MmapSource.cpp            \
-        QComHardwareRenderer.cpp  \
         SampleTable.cpp           \
         ShoutcastSource.cpp       \
-        SoftwareRenderer.cpp      \
-        SurfaceRenderer.cpp       \
         TimeSource.cpp            \
         TimedEventQueue.cpp       \
-        TIHardwareRenderer.cpp    \
         Utils.cpp                 \
         AudioPlayer.cpp           \
         ESDS.cpp                  \
diff --git a/media/libstagefright/MediaPlayerImpl.cpp b/media/libstagefright/MediaPlayerImpl.cpp
index 04c9a11..341f002 100644
--- a/media/libstagefright/MediaPlayerImpl.cpp
+++ b/media/libstagefright/MediaPlayerImpl.cpp
@@ -35,12 +35,8 @@
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/MmapSource.h>
 #include <media/stagefright/OMXDecoder.h>
-#include <media/stagefright/QComHardwareRenderer.h>
 #include <media/stagefright/ShoutcastSource.h>
-#include <media/stagefright/SoftwareRenderer.h>
-#include <media/stagefright/SurfaceRenderer.h>
 #include <media/stagefright/TimeSource.h>
-#include <media/stagefright/TIHardwareRenderer.h>
 #include <ui/PixelFormat.h>
 #include <ui/Surface.h>
 
@@ -61,7 +57,6 @@
       mDuration(0),
       mPlaying(false),
       mPaused(false),
-      mRenderer(NULL),
       mSeeking(false),
       mFrameSize(0),
       mUseSoftwareColorConversion(false) {
@@ -121,7 +116,6 @@
       mDuration(0),
       mPlaying(false),
       mPaused(false),
-      mRenderer(NULL),
       mSeeking(false),
       mFrameSize(0),
       mUseSoftwareColorConversion(false) {
@@ -379,7 +373,7 @@
 
     {
         Mutex::Autolock autoLock(mLock);
-        if (mRenderer != NULL) {
+        if (mVideoRenderer.get() != NULL) {
             sendFrameToISurface(buffer);
         }
     }
@@ -652,52 +646,26 @@
     success = success && meta->findInt32(kKeyHeight, &decodedHeight);
     assert(success);
 
-    static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
+    const sp<ISurface> &isurface =
+        mSurface.get() != NULL ? mSurface->getISurface() : mISurface;
 
-    if (mSurface.get() != NULL) {
-        LOGW("Using SurfaceRenderer.");
-        mRenderer =
-            new SurfaceRenderer(
-                    mSurface, mVideoWidth, mVideoHeight,
-                    decodedWidth, decodedHeight);
-    } else if (format == OMX_QCOM_COLOR_FormatYVU420SemiPlanar
-        && !strncmp(component, "OMX.qcom.video.decoder.", 23)) {
-        LOGW("Using QComHardwareRenderer.");
-        mRenderer =
-            new QComHardwareRenderer(
-                    mISurface, mVideoWidth, mVideoHeight,
-                    decodedWidth, decodedHeight);
-    } else if (format == OMX_COLOR_FormatCbYCrY
-            && !strcmp(component, "OMX.TI.Video.Decoder")) {
-        LOGW("Using TIHardwareRenderer.");
-        mRenderer =
-            new TIHardwareRenderer(
-                    mISurface, mVideoWidth, mVideoHeight,
-                    decodedWidth, decodedHeight);
-    } else {
-        LOGW("Using software renderer.");
-        mRenderer = new SoftwareRenderer(
-                mISurface, mVideoWidth, mVideoHeight,
-                decodedWidth, decodedHeight);
-    }
+    mVideoRenderer =
+        mClient.interface()->createRenderer(
+                isurface, component,
+                (OMX_COLOR_FORMATTYPE)format,
+                decodedWidth, decodedHeight,
+                mVideoWidth, mVideoHeight);
 }
 
 void MediaPlayerImpl::depopulateISurface() {
-    delete mRenderer;
-    mRenderer = NULL;
+    mVideoRenderer.clear();
 }
 
 void MediaPlayerImpl::sendFrameToISurface(MediaBuffer *buffer) {
-    void *platformPrivate;
-    if (!buffer->meta_data()->findPointer(
-                kKeyPlatformPrivate, &platformPrivate)) {
-        platformPrivate = NULL;
+    void *id;
+    if (buffer->meta_data()->findPointer(kKeyBufferID, &id)) {
+        mVideoRenderer->render((IOMX::buffer_id)id);
     }
-
-    mRenderer->render(
-        (const uint8_t *)buffer->data() + buffer->range_offset(),
-        buffer->range_length(),
-        platformPrivate);
 }
 
 void MediaPlayerImpl::setAudioSink(
diff --git a/media/libstagefright/OMXDecoder.cpp b/media/libstagefright/OMXDecoder.cpp
index 5e44999..780cd2e 100644
--- a/media/libstagefright/OMXDecoder.cpp
+++ b/media/libstagefright/OMXDecoder.cpp
@@ -154,8 +154,7 @@
     if (!strncmp(codec, "OMX.qcom.video.", 15)) {
         quirks |= kRequiresLoadedToIdleAfterAllocation;
     }
-    if (!strcmp(codec, "OMX.TI.AAC.decode")
-        || !strcmp(codec, "OMX.TI.MP3.decode")) {
+    if (!strcmp(codec, "OMX.TI.MP3.decode")) {
         quirks |= kMeasuresTimeInMilliseconds;
     }
 
@@ -1551,6 +1550,10 @@
             kKeyPlatformPrivate,
             msg.u.extended_buffer_data.platform_private);
 
+    media_buffer->meta_data()->setPointer(
+            kKeyBufferID,
+            msg.u.extended_buffer_data.buffer);
+
     if (msg.u.extended_buffer_data.flags & OMX_BUFFERFLAG_EOS) {
         mErrorCondition = ERROR_END_OF_STREAM;
     }
diff --git a/media/libstagefright/SurfaceRenderer.cpp b/media/libstagefright/SurfaceRenderer.cpp
deleted file mode 100644
index e54288d..0000000
--- a/media/libstagefright/SurfaceRenderer.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "SurfaceRenderer"
-#include <utils/Log.h>
-
-#undef NDEBUG
-#include <assert.h>
-
-#include <media/stagefright/SurfaceRenderer.h>
-#include <ui/Surface.h>
-
-namespace android {
-
-SurfaceRenderer::SurfaceRenderer(
-        const sp<Surface> &surface,
-        size_t displayWidth, size_t displayHeight,
-        size_t decodedWidth, size_t decodedHeight)
-    : mSurface(surface),
-      mDisplayWidth(displayWidth),
-      mDisplayHeight(displayHeight),
-      mDecodedWidth(decodedWidth),
-      mDecodedHeight(decodedHeight) {
-}
-
-SurfaceRenderer::~SurfaceRenderer() {
-}
-
-void SurfaceRenderer::render(
-        const void *data, size_t size, void *platformPrivate) {
-    Surface::SurfaceInfo info;
-    status_t err = mSurface->lock(&info);
-    if (err != OK) {
-        return;
-    }
-
-    const uint8_t *src = (const uint8_t *)data;
-    uint8_t *dst = (uint8_t *)info.bits;
-
-    for (size_t i = 0; i < mDisplayHeight; ++i) {
-        memcpy(dst, src, mDisplayWidth);
-        src += mDecodedWidth;
-        dst += mDisplayWidth;
-    }
-    src += (mDecodedHeight - mDisplayHeight) * mDecodedWidth;
-    
-    for (size_t i = 0; i < (mDisplayHeight + 1) / 2; ++i) {
-        memcpy(dst, src, (mDisplayWidth + 1) & ~1);
-        src += (mDecodedWidth + 1) & ~1;
-        dst += (mDisplayWidth + 1) & ~1;
-    }
-
-    mSurface->unlockAndPost();
-}
-
-}  // namespace android
diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
index 9c6d475..2e564e9 100644
--- a/media/libstagefright/omx/Android.mk
+++ b/media/libstagefright/omx/Android.mk
@@ -9,13 +9,17 @@
 LOCAL_CFLAGS := $(PV_CFLAGS_MINUS_VISIBILITY)
 
 LOCAL_SRC_FILES:=                 \
-	OMX.cpp
+	OMX.cpp                   \
+        QComHardwareRenderer.cpp  \
+        SoftwareRenderer.cpp      \
+        TIHardwareRenderer.cpp
 
-LOCAL_SHARED_LIBRARIES := \
-        libbinder         \
-        libmedia          \
-	libutils          \
-        libui             \
+LOCAL_SHARED_LIBRARIES :=       \
+        libbinder               \
+        libmedia                \
+	libutils                \
+        libui                   \
+        libcutils               \
         libopencore_common
 
 LOCAL_PRELINK_MODULE:= false
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index daaa741..062afd4 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -24,9 +24,15 @@
 #include <assert.h>
 
 #include "OMX.h"
+#include "OMXRenderer.h"
+
 #include "pv_omxcore.h"
 
 #include <binder/IMemory.h>
+#include <media/stagefright/QComHardwareRenderer.h>
+#include <media/stagefright/SoftwareRenderer.h>
+#include <media/stagefright/TIHardwareRenderer.h>
+#include <media/stagefright/VideoRenderer.h>
 
 #include <OMX_Component.h>
 
@@ -619,5 +625,62 @@
 }
 #endif
 
+////////////////////////////////////////////////////////////////////////////////
+
+sp<IOMXRenderer> OMX::createRenderer(
+        const sp<ISurface> &surface,
+        const char *componentName,
+        OMX_COLOR_FORMATTYPE colorFormat,
+        size_t encodedWidth, size_t encodedHeight,
+        size_t displayWidth, size_t displayHeight) {
+    VideoRenderer *impl = NULL;
+
+    static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
+
+    if (colorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar
+        && !strncmp(componentName, "OMX.qcom.video.decoder.", 23)) {
+        LOGW("Using QComHardwareRenderer.");
+        impl =
+            new QComHardwareRenderer(
+                    surface,
+                    displayWidth, displayHeight,
+                    encodedWidth, encodedHeight);
+    } else if (colorFormat == OMX_COLOR_FormatCbYCrY
+            && !strcmp(componentName, "OMX.TI.Video.Decoder")) {
+        LOGW("Using TIHardwareRenderer.");
+        impl =
+            new TIHardwareRenderer(
+                    surface,
+                    displayWidth, displayHeight,
+                    encodedWidth, encodedHeight);
+    } else {
+        LOGW("Using software renderer.");
+        impl = new SoftwareRenderer(
+                surface,
+                displayWidth, displayHeight,
+                encodedWidth, encodedHeight);
+    }
+
+    return new OMXRenderer(impl);
+}
+
+OMXRenderer::OMXRenderer(VideoRenderer *impl)
+    : mImpl(impl) {
+}
+
+OMXRenderer::~OMXRenderer() {
+    delete mImpl;
+    mImpl = NULL;
+}
+
+void OMXRenderer::render(IOMX::buffer_id buffer) {
+    OMX_BUFFERHEADERTYPE *header = (OMX_BUFFERHEADERTYPE *)buffer;
+
+    mImpl->render(
+            header->pBuffer + header->nOffset,
+            header->nFilledLen,
+            header->pPlatformPrivate);
+}
+
 }  // namespace android
 
diff --git a/media/libstagefright/omx/OMX.h b/media/libstagefright/omx/OMX.h
index ed4e5dd..20430bb 100644
--- a/media/libstagefright/omx/OMX.h
+++ b/media/libstagefright/omx/OMX.h
@@ -79,6 +79,13 @@
             OMX_U32 flags, OMX_TICKS timestamp);
 #endif
 
+    virtual sp<IOMXRenderer> createRenderer(
+            const sp<ISurface> &surface,
+            const char *componentName,
+            OMX_COLOR_FORMATTYPE colorFormat,
+            size_t encodedWidth, size_t encodedHeight,
+            size_t displayWidth, size_t displayHeight);
+
 private:
     static OMX_CALLBACKTYPE kCallbacks;
 
diff --git a/media/libstagefright/omx/OMXRenderer.h b/media/libstagefright/omx/OMXRenderer.h
new file mode 100644
index 0000000..4d194ce
--- /dev/null
+++ b/media/libstagefright/omx/OMXRenderer.h
@@ -0,0 +1,44 @@
+/*
+ * 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 OMX_RENDERER_H_
+
+#define OMX_RENDERER_H_
+
+#include <media/IOMX.h>
+
+namespace android {
+
+class VideoRenderer;
+
+class OMXRenderer : public BnOMXRenderer {
+public:
+    // Assumes ownership of "impl".
+    OMXRenderer(VideoRenderer *impl);
+    virtual ~OMXRenderer();
+
+    virtual void render(IOMX::buffer_id buffer);
+
+private:
+    VideoRenderer *mImpl;
+
+    OMXRenderer(const OMXRenderer &);
+    OMXRenderer &operator=(const OMXRenderer &);
+};
+
+}  // namespace android
+
+#endif  // OMX_RENDERER_H_
diff --git a/media/libstagefright/QComHardwareRenderer.cpp b/media/libstagefright/omx/QComHardwareRenderer.cpp
similarity index 100%
rename from media/libstagefright/QComHardwareRenderer.cpp
rename to media/libstagefright/omx/QComHardwareRenderer.cpp
diff --git a/media/libstagefright/SoftwareRenderer.cpp b/media/libstagefright/omx/SoftwareRenderer.cpp
similarity index 96%
rename from media/libstagefright/SoftwareRenderer.cpp
rename to media/libstagefright/omx/SoftwareRenderer.cpp
index 66b6b07..5483238 100644
--- a/media/libstagefright/SoftwareRenderer.cpp
+++ b/media/libstagefright/omx/SoftwareRenderer.cpp
@@ -61,6 +61,10 @@
 
 void SoftwareRenderer::render(
         const void *data, size_t size, void *platformPrivate) {
+    if (size != (mDecodedHeight * mDecodedWidth * 3) / 2) {
+        LOGE("size is %d, expected %d",
+                size, (mDecodedHeight * mDecodedWidth * 3) / 2);
+    }
     assert(size >= (mDecodedWidth * mDecodedHeight * 3) / 2);
 
     static const signed kClipMin = -278;
diff --git a/media/libstagefright/TIHardwareRenderer.cpp b/media/libstagefright/omx/TIHardwareRenderer.cpp
similarity index 100%
rename from media/libstagefright/TIHardwareRenderer.cpp
rename to media/libstagefright/omx/TIHardwareRenderer.cpp
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index 7afcae7..cf66be3 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -145,7 +145,7 @@
 
     virtual     EGLBoolean  bindDrawSurface(ogles_context_t* gl) = 0;
     virtual     EGLBoolean  bindReadSurface(ogles_context_t* gl) = 0;
-    virtual     void        connect() {}
+    virtual     EGLBoolean  connect() { return EGL_TRUE; }
     virtual     void        disconnect() {}
     virtual     EGLint      getWidth() const = 0;
     virtual     EGLint      getHeight() const = 0;
@@ -214,10 +214,10 @@
     virtual     EGLBoolean  swapBuffers();
     virtual     EGLBoolean  bindDrawSurface(ogles_context_t* gl);
     virtual     EGLBoolean  bindReadSurface(ogles_context_t* gl);
-    virtual     void        connect();
+    virtual     EGLBoolean  connect();
     virtual     void        disconnect();
-    virtual     EGLint      getWidth() const    { return buffer->width;  }
-    virtual     EGLint      getHeight() const   { return buffer->height; }
+    virtual     EGLint      getWidth() const    { return width;  }
+    virtual     EGLint      getHeight() const   { return height; }
     virtual     EGLint      getHorizontalResolution() const;
     virtual     EGLint      getVerticalResolution() const;
     virtual     EGLint      getRefreshRate() const;
@@ -365,26 +365,8 @@
     
     // keep a reference on the window
     nativeWindow->common.incRef(&nativeWindow->common);
-
-    // dequeue a buffer
-    nativeWindow->dequeueBuffer(nativeWindow, &buffer);
-
-    // allocate a corresponding depth-buffer
-    width = buffer->width;
-    height = buffer->height;
-    if (depthFormat) {
-        depth.width   = width;
-        depth.height  = height;
-        depth.stride  = depth.width; // use the width here
-        depth.data    = (GGLubyte*)malloc(depth.stride*depth.height*2);
-        if (depth.data == 0) {
-            setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
-            return;
-        }
-    }
-
-    // keep a reference on the buffer
-    buffer->common.incRef(&buffer->common);
+    nativeWindow->query(nativeWindow, NATIVE_WINDOW_WIDTH, &width);
+    nativeWindow->query(nativeWindow, NATIVE_WINDOW_HEIGHT, &height);
 }
 
 egl_window_surface_v2_t::~egl_window_surface_v2_t() {
@@ -400,8 +382,29 @@
     }
 }
 
-void egl_window_surface_v2_t::connect() 
+EGLBoolean egl_window_surface_v2_t::connect() 
 {
+    // dequeue a buffer
+    if (nativeWindow->dequeueBuffer(nativeWindow, &buffer) != NO_ERROR) {
+        return setError(EGL_BAD_ALLOC, EGL_FALSE);
+    }
+
+    // allocate a corresponding depth-buffer
+    width = buffer->width;
+    height = buffer->height;
+    if (depth.format) {
+        depth.width   = width;
+        depth.height  = height;
+        depth.stride  = depth.width; // use the width here
+        depth.data    = (GGLubyte*)malloc(depth.stride*depth.height*2);
+        if (depth.data == 0) {
+            return setError(EGL_BAD_ALLOC, EGL_FALSE);
+        }
+    }
+
+    // keep a reference on the buffer
+    buffer->common.incRef(&buffer->common);
+
     // Lock the buffer
     nativeWindow->lockBuffer(nativeWindow, buffer);
     // pin the buffer down
@@ -409,9 +412,10 @@
             GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) {
         LOGE("connect() failed to lock buffer %p (%ux%u)",
                 buffer, buffer->width, buffer->height);
-        setError(EGL_BAD_ACCESS, EGL_NO_SURFACE);
+        return setError(EGL_BAD_ACCESS, EGL_FALSE);
         // FIXME: we should make sure we're not accessing the buffer anymore
     }
+    return EGL_TRUE;
 }
 
 void egl_window_surface_v2_t::disconnect() 
@@ -420,6 +424,16 @@
         bits = NULL;
         unlock(buffer);
     }
+    // enqueue the last frame
+    nativeWindow->queueBuffer(nativeWindow, buffer);
+    if (buffer) {
+        buffer->common.decRef(&buffer->common);
+        buffer = 0;
+    }
+    if (previousBuffer) {
+        previousBuffer->common.decRef(&previousBuffer->common); 
+        previousBuffer = 0;
+    }
 }
 
 status_t egl_window_surface_v2_t::lock(
@@ -432,6 +446,7 @@
 
 status_t egl_window_surface_v2_t::unlock(android_native_buffer_t* buf)
 {
+    if (!buf) return BAD_VALUE;
     int err = module->unlock(module, buf->handle);
     return err;
 }
@@ -503,6 +518,10 @@
 
 EGLBoolean egl_window_surface_v2_t::swapBuffers()
 {
+    if (!buffer) {
+        return setError(EGL_BAD_ACCESS, EGL_FALSE);
+    }
+    
     /*
      * Handle eglSetSwapRectangleANDROID()
      * We copyback from the front buffer 
@@ -568,7 +587,7 @@
             GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) {
         LOGE("eglSwapBuffers() failed to lock buffer %p (%ux%u)",
                 buffer, buffer->width, buffer->height);
-        setError(EGL_BAD_ACCESS, EGL_NO_SURFACE);
+        return setError(EGL_BAD_ACCESS, EGL_FALSE);
         // FIXME: we should make sure we're not accessing the buffer anymore
     }
 
@@ -1736,7 +1755,9 @@
                 ogles_scissor(gl, 0, 0, w, h);
             }
             if (d) {
-                d->connect();
+                if (d->connect() == EGL_FALSE) {
+                    return EGL_FALSE;
+                }
                 d->ctx = ctx;
                 d->bindDrawSurface(gl);
             }
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index c2003dd..236d247 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -135,9 +135,10 @@
 
 struct tls_t
 {
-    tls_t() : error(EGL_SUCCESS), ctx(0) { }
+    tls_t() : error(EGL_SUCCESS), ctx(0), logCallWithNoContext(EGL_TRUE) { }
     EGLint      error;
     EGLContext  ctx;
+    EGLBoolean  logCallWithNoContext;
 };
 
 
@@ -352,8 +353,14 @@
 }
 
 static void gl_no_context() {
-    LOGE("call to OpenGL ES API with no current context");
+    tls_t* tls = getTLS();
+    if (tls->logCallWithNoContext == EGL_TRUE) {
+        tls->logCallWithNoContext = EGL_FALSE;
+        LOGE("call to OpenGL ES API with no current context "
+             "(logged once per thread)");
+    }
 }
+
 static void early_egl_init(void) 
 {
 #if !USE_FAST_TLS_KEY
diff --git a/packages/VpnServices/src/com/android/server/vpn/DaemonProxy.java b/packages/VpnServices/src/com/android/server/vpn/DaemonProxy.java
index b749821..289ee45 100644
--- a/packages/VpnServices/src/com/android/server/vpn/DaemonProxy.java
+++ b/packages/VpnServices/src/com/android/server/vpn/DaemonProxy.java
@@ -25,6 +25,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.io.Serializable;
 
 /**
  * Proxy to start, stop and interact with a VPN daemon.
@@ -33,7 +34,10 @@
  * connection with the daemon, to both send commands to the daemon and receive
  * response and connecting error code from the daemon.
  */
-class DaemonProxy {
+class DaemonProxy implements Serializable {
+    private static final long serialVersionUID = 1L;
+    private static final boolean DBG = true;
+
     private static final int WAITING_TIME = 15; // sec
 
     private static final String SVC_STATE_CMD_PREFIX = "init.svc.";
@@ -45,8 +49,8 @@
     private static final int END_OF_ARGUMENTS = 255;
 
     private String mName;
-    private LocalSocket mControlSocket;
     private String mTag;
+    private transient LocalSocket mControlSocket;
 
     /**
      * Creates a proxy of the specified daemon.
@@ -63,14 +67,8 @@
 
     void start() throws IOException {
         String svc = mName;
-        Log.d(mTag, "-----  Stop the daemon just in case: " + mName);
-        SystemProperties.set(SVC_STOP_CMD, mName);
-        if (!blockUntil(SVC_STATE_STOPPED, 5)) {
-            throw new IOException("cannot start service anew: " + svc
-                    + ", it is still running");
-        }
 
-        Log.d(mTag, "+++++  Start: " + svc);
+        Log.i(mTag, "Start VPN daemon: " + svc);
         SystemProperties.set(SVC_START_CMD, svc);
 
         if (!blockUntil(SVC_STATE_RUNNING, WAITING_TIME)) {
@@ -103,7 +101,7 @@
         try {
             mControlSocket.close();
         } catch (IOException e) {
-            Log.e(mTag, "close control socket", e);
+            Log.w(mTag, "close control socket", e);
         } finally {
             mControlSocket = null;
         }
@@ -111,10 +109,10 @@
 
     void stop() {
         String svc = mName;
-        Log.d(mTag, "-----  Stop: " + svc);
+        Log.i(mTag, "Stop VPN daemon: " + svc);
         SystemProperties.set(SVC_STOP_CMD, svc);
         boolean success = blockUntil(SVC_STATE_STOPPED, 5);
-        Log.d(mTag, "stopping " + svc + ", success? " + success);
+        if (DBG) Log.d(mTag, "stopping " + svc + ", success? " + success);
     }
 
     boolean isStopped() {
@@ -129,7 +127,7 @@
         if (!blocking && in.available() == 0) return 0;
 
         int data = in.read();
-        Log.d(mTag, "got data from control socket: " + data);
+        Log.i(mTag, "got data from control socket: " + data);
 
         return data;
     }
@@ -146,7 +144,7 @@
                 s.connect(a);
                 return s;
             } catch (IOException e) {
-                Log.d(mTag, "service not yet listen()ing; try again");
+                if (DBG) Log.d(mTag, "service not yet listen()ing; try again");
                 excp = e;
                 sleep(500);
             }
@@ -173,8 +171,10 @@
         int n = waitTime * 1000 / sleepTime;
         for (int i = 0; i < n; i++) {
             if (expectedState.equals(SystemProperties.get(cmd))) {
-                Log.d(mTag, mName + " is " + expectedState + " after "
-                        + (i * sleepTime) + " msec");
+                if (DBG) {
+                    Log.d(mTag, mName + " is " + expectedState + " after "
+                            + (i * sleepTime) + " msec");
+                }
                 break;
             }
             sleep(sleepTime);
diff --git a/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecPskService.java b/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecPskService.java
index 8efd7c4..7910f4a 100644
--- a/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecPskService.java
+++ b/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecPskService.java
@@ -45,4 +45,10 @@
                 (p.isSecretEnabled() ? p.getSecretString() : null),
                 username, password);
     }
+
+    @Override
+    protected void stopPreviouslyRunDaemons() {
+        stopDaemon(IPSEC);
+        stopDaemon(MtpdHelper.MTPD);
+    }
 }
diff --git a/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java b/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java
index 56694b6..13b4952 100644
--- a/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java
+++ b/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java
@@ -46,6 +46,12 @@
                 username, password);
     }
 
+    @Override
+    protected void stopPreviouslyRunDaemons() {
+        stopDaemon(IPSEC);
+        stopDaemon(MtpdHelper.MTPD);
+    }
+
     private String getCaCertPath() {
         return CertTool.getInstance().getCaCertificate(
                 getProfile().getCaCertificate());
diff --git a/packages/VpnServices/src/com/android/server/vpn/L2tpService.java b/packages/VpnServices/src/com/android/server/vpn/L2tpService.java
index 9273f35..d658a366 100644
--- a/packages/VpnServices/src/com/android/server/vpn/L2tpService.java
+++ b/packages/VpnServices/src/com/android/server/vpn/L2tpService.java
@@ -35,4 +35,9 @@
                 (p.isSecretEnabled() ? p.getSecretString() : null),
                 username, password);
     }
+
+    @Override
+    protected void stopPreviouslyRunDaemons() {
+        stopDaemon(MtpdHelper.MTPD);
+    }
 }
diff --git a/packages/VpnServices/src/com/android/server/vpn/MtpdHelper.java b/packages/VpnServices/src/com/android/server/vpn/MtpdHelper.java
index 805a5b5..9078d9b 100644
--- a/packages/VpnServices/src/com/android/server/vpn/MtpdHelper.java
+++ b/packages/VpnServices/src/com/android/server/vpn/MtpdHelper.java
@@ -24,26 +24,33 @@
  * A helper class for sending commands to the MTP daemon (mtpd).
  */
 class MtpdHelper {
-    private static final String MTPD = "mtpd";
+    static final String MTPD = "mtpd";
     private static final String VPN_LINKNAME = "vpn";
     private static final String PPP_ARGS_SEPARATOR = "";
 
     static void sendCommand(VpnService<?> vpnService, String protocol,
             String serverIp, String port, String secret, String username,
             String password) throws IOException {
+        sendCommand(vpnService, protocol, serverIp, port, secret, username,
+                password, false);
+    }
+
+    static void sendCommand(VpnService<?> vpnService, String protocol,
+            String serverIp, String port, String secret, String username,
+            String password, boolean encryption) throws IOException {
         ArrayList<String> args = new ArrayList<String>();
         args.addAll(Arrays.asList(protocol, serverIp, port));
         if (secret != null) args.add(secret);
         args.add(PPP_ARGS_SEPARATOR);
-        addPppArguments(vpnService, args, serverIp, username, password);
+        addPppArguments(args, serverIp, username, password, encryption);
 
         DaemonProxy mtpd = vpnService.startDaemon(MTPD);
         mtpd.sendCommand(args.toArray(new String[args.size()]));
     }
 
-    private static void addPppArguments(VpnService<?> vpnService,
-            ArrayList<String> args, String serverIp, String username,
-            String password) throws IOException {
+    private static void addPppArguments(ArrayList<String> args, String serverIp,
+            String username, String password, boolean encryption)
+            throws IOException {
         args.addAll(Arrays.asList(
                 "linkname", VPN_LINKNAME,
                 "name", username,
@@ -52,6 +59,9 @@
                 "idle", "1800",
                 "mtu", "1400",
                 "mru", "1400"));
+        if (encryption) {
+            args.add("+mppe");
+        }
     }
 
     private MtpdHelper() {
diff --git a/packages/VpnServices/src/com/android/server/vpn/PptpService.java b/packages/VpnServices/src/com/android/server/vpn/PptpService.java
index 01362a5..d903d1b 100644
--- a/packages/VpnServices/src/com/android/server/vpn/PptpService.java
+++ b/packages/VpnServices/src/com/android/server/vpn/PptpService.java
@@ -26,11 +26,17 @@
 class PptpService extends VpnService<PptpProfile> {
     static final String PPTP_DAEMON = "pptp";
     static final String PPTP_PORT = "1723";
+
     @Override
     protected void connect(String serverIp, String username, String password)
             throws IOException {
+        PptpProfile p = getProfile();
         MtpdHelper.sendCommand(this, PPTP_DAEMON, serverIp, PPTP_PORT, null,
-                username, password);
+                username, password, p.isEncryptionEnabled());
     }
 
+    @Override
+    protected void stopPreviouslyRunDaemons() {
+        stopDaemon(MtpdHelper.MTPD);
+    }
 }
diff --git a/packages/VpnServices/src/com/android/server/vpn/VpnService.java b/packages/VpnServices/src/com/android/server/vpn/VpnService.java
index 60a07d5..b107c7d 100644
--- a/packages/VpnServices/src/com/android/server/vpn/VpnService.java
+++ b/packages/VpnServices/src/com/android/server/vpn/VpnService.java
@@ -28,7 +28,11 @@
 import android.util.Log;
 
 import java.io.IOException;
+import java.io.Serializable;
+import java.net.DatagramSocket;
+import java.net.Socket;
 import java.net.InetAddress;
+import java.net.NetworkInterface;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.List;
@@ -36,7 +40,9 @@
 /**
  * The service base class for managing a type of VPN connection.
  */
-abstract class VpnService<E extends VpnProfile> {
+abstract class VpnService<E extends VpnProfile> implements Serializable {
+    protected static final long serialVersionUID = 1L;
+    private static final boolean DBG = true;
     private static final int NOTIFICATION_ID = 1;
 
     private static final String DNS1 = "net.dns1";
@@ -50,12 +56,16 @@
     private static final String REMOTE_IP = "net.ipremote";
     private static final String DNS_DOMAIN_SUFFICES = "net.dns.search";
 
+    private static final int CHALLENGE_ERROR_CODE = 5;
+    private static final int REMOTE_HUNG_UP_ERROR_CODE = 7;
     private static final int AUTH_ERROR_CODE = 51;
 
     private final String TAG = VpnService.class.getSimpleName();
 
+    // FIXME: profile is only needed in connecting phase, so we can just save
+    // the profile name and service class name for recovery
     E mProfile;
-    VpnServiceBinder mContext;
+    transient VpnServiceBinder mContext;
 
     private VpnState mState = VpnState.IDLE;
     private Throwable mError;
@@ -63,9 +73,9 @@
     // connection settings
     private String mOriginalDns1;
     private String mOriginalDns2;
-    private String mVpnDns1 = "";
-    private String mVpnDns2 = "";
     private String mOriginalDomainSuffices;
+    private String mLocalIp;
+    private String mLocalIf;
 
     private long mStartTime; // VPN connection start time
 
@@ -73,7 +83,7 @@
     private DaemonHelper mDaemonHelper = new DaemonHelper();
 
     // for helping showing, updating notification
-    private NotificationHelper mNotification = new NotificationHelper();
+    private transient NotificationHelper mNotification;
 
     /**
      * Establishes a VPN connection with the specified username and password.
@@ -81,6 +91,8 @@
     protected abstract void connect(String serverIp, String username,
             String password) throws IOException;
 
+    protected abstract void stopPreviouslyRunDaemons();
+
     /**
      * Starts a VPN daemon.
      */
@@ -90,6 +102,13 @@
     }
 
     /**
+     * Stops a VPN daemon.
+     */
+    protected void stopDaemon(String daemonName) {
+        new DaemonProxy(daemonName).stop();
+    }
+
+    /**
      * Returns the VPN profile associated with the connection.
      */
     protected E getProfile() {
@@ -104,8 +123,22 @@
     }
 
     void setContext(VpnServiceBinder context, E profile) {
-        mContext = context;
         mProfile = profile;
+        recover(context);
+    }
+
+    void recover(VpnServiceBinder context) {
+        mContext = context;
+        mNotification = new NotificationHelper();
+
+        if (VpnState.CONNECTED.equals(mState)) {
+            Log.i("VpnService", "     recovered: " + mProfile.getName());
+            new Thread(new Runnable() {
+                public void run() {
+                    enterConnectivityLoop();
+                }
+            }).start();
+        }
     }
 
     VpnState getState() {
@@ -117,14 +150,14 @@
             mState = VpnState.CONNECTING;
             broadcastConnectivity(VpnState.CONNECTING);
 
+            stopPreviouslyRunDaemons();
             String serverIp = getIp(getProfile().getServerName());
-
+            saveLocalIpAndInterface(serverIp);
             onBeforeConnect();
             connect(serverIp, username, password);
             waitUntilConnectedOrTimedout();
             return true;
         } catch (Throwable e) {
-            Log.e(TAG, "onConnect()", e);
             onError(e);
             return false;
         }
@@ -132,7 +165,7 @@
 
     synchronized void onDisconnect() {
         try {
-            Log.d(TAG, "       disconnecting VPN...");
+            Log.i(TAG, "disconnecting VPN...");
             mState = VpnState.DISCONNECTING;
             broadcastConnectivity(VpnState.DISCONNECTING);
             mNotification.showDisconnect();
@@ -152,6 +185,7 @@
             Log.w(TAG, "   multiple errors occur, record the last one: "
                     + error);
         }
+        Log.e(TAG, "onError()", error);
         mError = error;
         onDisconnect();
     }
@@ -161,16 +195,18 @@
     }
 
 
-    private void onBeforeConnect() {
+    private void onBeforeConnect() throws IOException {
         mNotification.disableNotification();
 
-        SystemProperties.set(VPN_DNS1, "-");
-        SystemProperties.set(VPN_DNS2, "-");
+        SystemProperties.set(VPN_DNS1, "");
+        SystemProperties.set(VPN_DNS2, "");
         SystemProperties.set(VPN_STATUS, VPN_IS_DOWN);
-        Log.d(TAG, "       VPN UP: " + SystemProperties.get(VPN_STATUS));
+        if (DBG) {
+            Log.d(TAG, "       VPN UP: " + SystemProperties.get(VPN_STATUS));
+        }
     }
 
-    private void waitUntilConnectedOrTimedout() {
+    private void waitUntilConnectedOrTimedout() throws IOException {
         sleep(2000); // 2 seconds
         for (int i = 0; i < 60; i++) {
             if (mState != VpnState.CONNECTING) {
@@ -187,39 +223,49 @@
 
         synchronized (VpnService.this) {
             if (mState == VpnState.CONNECTING) {
-                Log.d(TAG, "       connecting timed out !!");
                 onError(new IOException("Connecting timed out"));
             }
         }
     }
 
-    private synchronized void onConnected() {
-        Log.d(TAG, "onConnected()");
+    private synchronized void onConnected() throws IOException {
+        if (DBG) Log.d(TAG, "onConnected()");
 
         mDaemonHelper.closeSockets();
-        saveVpnDnsProperties();
+        saveOriginalDns();
         saveAndSetDomainSuffices();
 
         mState = VpnState.CONNECTED;
+        mStartTime = System.currentTimeMillis();
+
+        // set DNS after saving the states in case the process gets killed
+        // before states are saved
+        saveSelf();
+        setVpnDns();
         broadcastConnectivity(VpnState.CONNECTED);
 
         enterConnectivityLoop();
     }
 
+    private void saveSelf() throws IOException {
+        mContext.saveStates();
+    }
+
     private synchronized void onFinalCleanUp() {
-        Log.d(TAG, "onFinalCleanUp()");
+        if (DBG) Log.d(TAG, "onFinalCleanUp()");
 
         if (mState == VpnState.IDLE) return;
 
         // keep the notification when error occurs
         if (!anyError()) mNotification.disableNotification();
 
-        restoreOriginalDnsProperties();
+        restoreOriginalDns();
         restoreOriginalDomainSuffices();
         mState = VpnState.IDLE;
         broadcastConnectivity(VpnState.IDLE);
 
         // stop the service itself
+        mContext.removeStates();
         mContext.stopSelf();
     }
 
@@ -227,46 +273,38 @@
         return (mError != null);
     }
 
-    private void restoreOriginalDnsProperties() {
+    private void restoreOriginalDns() {
         // restore only if they are not overridden
-        if (mVpnDns1.equals(SystemProperties.get(DNS1))) {
-            Log.d(TAG, String.format("restore original dns prop: %s --> %s",
+        String vpnDns1 = SystemProperties.get(VPN_DNS1);
+        if (vpnDns1.equals(SystemProperties.get(DNS1))) {
+            Log.i(TAG, String.format("restore original dns prop: %s --> %s",
                     SystemProperties.get(DNS1), mOriginalDns1));
-            Log.d(TAG, String.format("restore original dns prop: %s --> %s",
+            Log.i(TAG, String.format("restore original dns prop: %s --> %s",
                     SystemProperties.get(DNS2), mOriginalDns2));
             SystemProperties.set(DNS1, mOriginalDns1);
             SystemProperties.set(DNS2, mOriginalDns2);
         }
     }
 
-    private void saveVpnDnsProperties() {
-        mOriginalDns1 = mOriginalDns2 = "";
-        for (int i = 0; i < 5; i++) {
-            mVpnDns1 = SystemProperties.get(VPN_DNS1);
-            mVpnDns2 = SystemProperties.get(VPN_DNS2);
-            if (mOriginalDns1.equals(mVpnDns1)) {
-                Log.d(TAG, "wait for vpn dns to settle in..." + i);
-                sleep(200);
-            } else {
-                mOriginalDns1 = SystemProperties.get(DNS1);
-                mOriginalDns2 = SystemProperties.get(DNS2);
-                SystemProperties.set(DNS1, mVpnDns1);
-                SystemProperties.set(DNS2, mVpnDns2);
-                Log.d(TAG, String.format("save original dns prop: %s, %s",
-                        mOriginalDns1, mOriginalDns2));
-                Log.d(TAG, String.format("set vpn dns prop: %s, %s",
-                        mVpnDns1, mVpnDns2));
-                return;
-            }
-        }
-        Log.d(TAG, "saveVpnDnsProperties(): DNS not updated??");
-        mOriginalDns1 = mVpnDns1 = SystemProperties.get(DNS1);
-        mOriginalDns2 = mVpnDns2 = SystemProperties.get(DNS2);
+    private void saveOriginalDns() {
+        mOriginalDns1 = SystemProperties.get(DNS1);
+        mOriginalDns2 = SystemProperties.get(DNS2);
+        Log.i(TAG, String.format("save original dns prop: %s, %s",
+                mOriginalDns1, mOriginalDns2));
+    }
+
+    private void setVpnDns() {
+        String vpnDns1 = SystemProperties.get(VPN_DNS1);
+        String vpnDns2 = SystemProperties.get(VPN_DNS2);
+        SystemProperties.set(DNS1, vpnDns1);
+        SystemProperties.set(DNS2, vpnDns2);
+        Log.i(TAG, String.format("set vpn dns prop: %s, %s",
+                vpnDns1, vpnDns2));
     }
 
     private void saveAndSetDomainSuffices() {
         mOriginalDomainSuffices = SystemProperties.get(DNS_DOMAIN_SUFFICES);
-        Log.d(TAG, "save original dns search: " + mOriginalDomainSuffices);
+        Log.i(TAG, "save original suffices: " + mOriginalDomainSuffices);
         String list = mProfile.getDomainSuffices();
         if (!TextUtils.isEmpty(list)) {
             SystemProperties.set(DNS_DOMAIN_SUFFICES, list);
@@ -274,7 +312,7 @@
     }
 
     private void restoreOriginalDomainSuffices() {
-        Log.d(TAG, "restore original dns search --> " + mOriginalDomainSuffices);
+        Log.i(TAG, "restore original suffices --> " + mOriginalDomainSuffices);
         SystemProperties.set(DNS_DOMAIN_SUFFICES, mOriginalDomainSuffices);
     }
 
@@ -298,46 +336,73 @@
     }
 
     private void enterConnectivityLoop() {
-        mStartTime = System.currentTimeMillis();
-
-        Log.d(TAG, "   +++++   connectivity monitor running");
+        Log.i(TAG, "VPN connectivity monitor running");
         try {
             for (;;) {
                 synchronized (VpnService.this) {
-                    if (mState != VpnState.CONNECTED) break;
+                    if (mState != VpnState.CONNECTED || !checkConnectivity()) {
+                        break;
+                    }
                     mNotification.update();
-                    checkConnectivity();
+                    checkDns();
                     VpnService.this.wait(1000); // 1 second
                 }
             }
         } catch (InterruptedException e) {
-            Log.e(TAG, "connectivity monitor", e);
+            onError(e);
         }
-        Log.d(TAG, "   -----   connectivity monitor stopped");
+        Log.i(TAG, "VPN connectivity monitor stopped");
     }
 
-    private void checkConnectivity() {
+    private void saveLocalIpAndInterface(String serverIp) throws IOException {
+        DatagramSocket s = new DatagramSocket();
+        int port = 80; // arbitrary
+        s.connect(InetAddress.getByName(serverIp), port);
+        InetAddress localIp = s.getLocalAddress();
+        mLocalIp = localIp.getHostAddress();
+        NetworkInterface localIf = NetworkInterface.getByInetAddress(localIp);
+        mLocalIf = (localIf == null) ? null : localIf.getName();
+        if (TextUtils.isEmpty(mLocalIf)) {
+            throw new IOException("Local interface is empty!");
+        }
+        if (DBG) {
+            Log.d(TAG, "  Local IP: " + mLocalIp + ", if: " + mLocalIf);
+        }
+    }
+
+    // returns false if vpn connectivity is broken
+    private boolean checkConnectivity() {
         if (mDaemonHelper.anyDaemonStopped() || isLocalIpChanged()) {
             onDisconnect();
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    private void checkDns() {
+        String dns1 = SystemProperties.get(DNS1);
+        String vpnDns1 = SystemProperties.get(VPN_DNS1);
+        if (!dns1.equals(vpnDns1) && dns1.equals(mOriginalDns1)) {
+            // dhcp expires?
+            setVpnDns();
         }
     }
 
     private boolean isLocalIpChanged() {
-        // TODO
-        if (!isDnsIntact()) {
-            Log.w(TAG, "       local IP changed");
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    private boolean isDnsIntact() {
-        String dns1 = SystemProperties.get(DNS1);
-        if (!mVpnDns1.equals(dns1)) {
-            Log.w(TAG, "   dns being overridden by: " + dns1);
-            return false;
-        } else {
+        try {
+            InetAddress localIp = InetAddress.getByName(mLocalIp);
+            NetworkInterface localIf =
+                    NetworkInterface.getByInetAddress(localIp);
+            if (localIf == null || !mLocalIf.equals(localIf.getName())) {
+                Log.w(TAG, "       local If changed from " + mLocalIf
+                        + " to " + localIf);
+                return true;
+            } else {
+                return false;
+            }
+        } catch (IOException e) {
+            Log.w(TAG, "isLocalIpChanged()", e);
             return true;
         }
     }
@@ -349,7 +414,7 @@
         }
     }
 
-    private class DaemonHelper {
+    private class DaemonHelper implements Serializable {
         private List<DaemonProxy> mDaemonList =
                 new ArrayList<DaemonProxy>();
 
@@ -376,7 +441,7 @@
         synchronized boolean anyDaemonStopped() {
             for (DaemonProxy s : mDaemonList) {
                 if (s.isStopped()) {
-                    Log.w(TAG, "       daemon gone: " + s.getName());
+                    Log.w(TAG, "    VPN daemon gone: " + s.getName());
                     return true;
                 }
             }
@@ -401,6 +466,14 @@
                         onError(VpnManager.VPN_ERROR_AUTH);
                         return true;
 
+                    case CHALLENGE_ERROR_CODE:
+                        onError(VpnManager.VPN_ERROR_CHALLENGE);
+                        return true;
+
+                    case REMOTE_HUNG_UP_ERROR_CODE:
+                        onError(VpnManager.VPN_ERROR_REMOTE_HUNG_UP);
+                        return true;
+
                     default:
                         onError(VpnManager.VPN_ERROR_CONNECTION_FAILED);
                         return true;
diff --git a/packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java b/packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java
index 513a2c9..4892a7b 100644
--- a/packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java
+++ b/packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java
@@ -27,23 +27,31 @@
 import android.net.vpn.VpnProfile;
 import android.net.vpn.VpnState;
 import android.os.IBinder;
+import android.util.Log;
 
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
 
 /**
  * The service class for managing a VPN connection. It implements the
  * {@link IVpnService} binder interface.
  */
 public class VpnServiceBinder extends Service {
-    private final String TAG = VpnServiceBinder.class.getSimpleName();
+    private static final String TAG = VpnServiceBinder.class.getSimpleName();
+    private static final boolean DBG = true;
+
+    private static final String STATES_FILE_PATH = "/data/misc/vpn/.states";
 
     // The actual implementation is delegated to the VpnService class.
     private VpnService<? extends VpnProfile> mService;
 
     private final IBinder mBinder = new IVpnService.Stub() {
         public boolean connect(VpnProfile p, String username, String password) {
-            android.util.Log.d("VpnServiceBinder", "becoming foreground");
-            setForeground(true);
             return VpnServiceBinder.this.connect(p, username, password);
         }
 
@@ -57,6 +65,13 @@
     };
 
     @Override
+    public void onCreate() {
+        super.onCreate();
+        checkSavedStates();
+    }
+
+
+    @Override
     public void onStart(Intent intent, int startId) {
         super.onStart(intent, startId);
     }
@@ -66,14 +81,30 @@
         return mBinder;
     }
 
+    void saveStates() throws IOException {
+        if (DBG) Log.d("VpnServiceBinder", "     saving states");
+        ObjectOutputStream oos =
+                new ObjectOutputStream(new FileOutputStream(STATES_FILE_PATH));
+        oos.writeObject(mService);
+        oos.close();
+    }
+
+    void removeStates() {
+        try {
+            new File(STATES_FILE_PATH).delete();
+        } catch (Throwable e) {
+            if (DBG) Log.d("VpnServiceBinder", "     remove states: " + e);
+        }
+    }
+
     private synchronized boolean connect(final VpnProfile p,
             final String username, final String password) {
         if (mService != null) return false;
+        final VpnService s = mService = createService(p);
 
         new Thread(new Runnable() {
             public void run() {
-                mService = createService(p);
-                mService.onConnect(username, password);
+                s.onConnect(username, password);
             }
         }).start();
         return true;
@@ -81,12 +112,11 @@
 
     private synchronized void disconnect() {
         if (mService == null) return;
+        final VpnService s = mService;
 
         new Thread(new Runnable() {
             public void run() {
-                mService.onDisconnect();
-                android.util.Log.d("VpnServiceBinder", "becoming background");
-                setForeground(false);
+                s.onDisconnect();
             }
         }).start();
     }
@@ -100,6 +130,21 @@
         }
     }
 
+    private void checkSavedStates() {
+        try {
+            ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
+                    STATES_FILE_PATH));
+            mService = (VpnService<? extends VpnProfile>) ois.readObject();
+            mService.recover(this);
+            ois.close();
+        } catch (FileNotFoundException e) {
+            // do nothing
+        } catch (Throwable e) {
+            Log.i("VpnServiceBinder", "recovery error, remove states: " + e);
+            removeStates();
+        }
+    }
+
     private VpnService<? extends VpnProfile> createService(VpnProfile p) {
         switch (p.getType()) {
             case L2TP:
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 134fb6f..9e8816b 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -494,7 +494,7 @@
             mDrmAppInstallObserver = new AppDirObserver(
                 mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false);
             mDrmAppInstallObserver.startWatching();
-            scanDirLI(mDrmAppPrivateInstallDir, 0, scanMode);
+            scanDirLI(mDrmAppPrivateInstallDir, 0, scanMode | SCAN_FORWARD_LOCKED);
 
             EventLog.writeEvent(LOG_BOOT_PROGRESS_PMS_SCAN_END,
                     SystemClock.uptimeMillis());
@@ -1766,7 +1766,12 @@
         int i;
         for (i=0; i<files.length; i++) {
             File file = new File(dir, files[i]);
-            PackageParser.Package pkg = scanPackageLI(file, file, file, 
+            File resFile = file;
+            // Pick up the resource path from settings for fwd locked apps
+            if ((scanMode & SCAN_FORWARD_LOCKED) != 0) {
+                resFile = null;
+            }
+            PackageParser.Package pkg = scanPackageLI(file, file, resFile,
                     flags|PackageParser.PARSE_MUST_BE_APK, scanMode);
         }
     }
@@ -1868,8 +1873,12 @@
         if (ps != null && !ps.codePath.equals(ps.resourcePath)) {
             scanMode |= SCAN_FORWARD_LOCKED;
         }
+        File resFile = destResourceFile;
+        if ((scanMode & SCAN_FORWARD_LOCKED) != 0) {
+            resFile = getFwdLockedResource(ps.name);
+        }
         // Note that we invoke the following method only if we are about to unpack an application
-        return scanPackageLI(scanFile, destCodeFile, destResourceFile,
+        return scanPackageLI(scanFile, destCodeFile, resFile,
                 pkg, parseFlags, scanMode | SCAN_UPDATE_SIGNATURE);
     }
 
@@ -3811,6 +3820,11 @@
         }
     }
     
+    private File getFwdLockedResource(String pkgName) {
+        final String publicZipFileName = pkgName + ".zip";
+        return new File(mAppInstallDir, publicZipFileName);
+    }
+
     private PackageInstalledInfo installPackageLI(Uri pPackageURI,
             int pFlags, boolean newInstall, String installerPackageName) {
         File tmpPackageFile = null;
@@ -3890,8 +3904,7 @@
             final String destFilePath = destPackageFile.getAbsolutePath();
             File destResourceFile;
             if ((pFlags&PackageManager.INSTALL_FORWARD_LOCK) != 0) {
-                final String publicZipFileName = pkgName + ".zip";
-                destResourceFile = new File(mAppInstallDir, publicZipFileName);
+                destResourceFile = getFwdLockedResource(pkgName);
                 forwardLocked = true;
             } else {
                 destResourceFile = destPackageFile;
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 890f930..82539fb 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -40,7 +40,6 @@
 /**
  * Manages SMS operations such as sending data, text, and pdu SMS messages.
  * Get this object by calling the static method SmsManager.getDefault().
- * @hide
  */
 public final class SmsManager {
     private static SmsManager sInstance;
@@ -202,6 +201,8 @@
 
     /**
      * Send a raw SMS PDU.
+     * A PDU is a protocol data unit. It contains the message and the
+     * associated meta information.
      *
      * @param smsc the SMSC to send the message through, or NULL for the
      *  default SMSC
@@ -219,8 +220,6 @@
      * @param deliveryIntent if not NULL this <code>PendingIntent</code> is
      *  broadcast when the message is delivered to the recipient.  The
      *  raw pdu of the status report is in the extended data ("pdu").
-     *
-     * @hide
      */
     private void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent,
             PendingIntent deliveryIntent) {
@@ -252,6 +251,8 @@
 
     /**
      * Copy a raw SMS PDU to the ICC.
+     * ICC (Integrated Circuit Card) is the card of the device.
+     * For example, this can be the SIM or USIM for GSM.
      *
      * @param smsc the SMSC for this message, or NULL for the default SMSC
      * @param pdu the raw PDU to store
@@ -278,6 +279,8 @@
 
     /**
      * Delete the specified message from the ICC.
+     * ICC (Integrated Circuit Card) is the card of the device.
+     * For example, this can be the SIM or USIM for GSM.
      *
      * @param messageIndex is the record index of the message on ICC
      * @return true for success
@@ -304,6 +307,8 @@
 
     /**
      * Update the specified message on the ICC.
+     * ICC (Integrated Circuit Card) is the card of the device.
+     * For example, this can be the SIM or USIM for GSM.
      *
      * @param messageIndex record index of message to update
      * @param newStatus new message status (STATUS_ON_ICC_READ,
@@ -331,6 +336,8 @@
 
     /**
      * Retrieves all messages currently stored on ICC.
+     * ICC (Integrated Circuit Card) is the card of the device.
+     * For example, this can be the SIM or USIM for GSM.
      *
      * @return <code>ArrayList</code> of <code>SmsMessage</code> objects
      *
@@ -359,12 +366,12 @@
      *   <code>getAllMessagesFromIcc</code>
      * @return <code>ArrayList</code> of <code>SmsMessage</code> objects.
      */
-    private ArrayList<SmsMessage> createMessageListFromRawRecords(List records) {
+    private ArrayList<SmsMessage> createMessageListFromRawRecords(List<SmsRawData> records) {
         ArrayList<SmsMessage> messages = new ArrayList<SmsMessage>();
         if (records != null) {
             int count = records.size();
             for (int i = 0; i < count; i++) {
-                SmsRawData data = (SmsRawData)records.get(i);
+                SmsRawData data = records.get(i);
                 // List contains all records, including "free" records (null)
                 if (data != null) {
                     SmsMessage sms = SmsMessage.createFromEfRecord(i+1, data.getBytes());
diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java
index fc491d7..0617dad 100644
--- a/telephony/java/android/telephony/SmsMessage.java
+++ b/telephony/java/android/telephony/SmsMessage.java
@@ -28,13 +28,13 @@
 
 import java.lang.Math;
 import java.util.ArrayList;
+import java.util.Arrays;
 
 import static android.telephony.TelephonyManager.PHONE_TYPE_CDMA;
 
 
 /**
  * A Short Message Service message.
- * @hide
  */
 public class SmsMessage {
     private static final boolean LOCAL_DEBUG = true;
@@ -49,18 +49,6 @@
         UNKNOWN, CLASS_0, CLASS_1, CLASS_2, CLASS_3;
     }
 
-    /**
-     * TODO(cleanup): given that we now have more than one possible
-     * 7bit encoding, this result starts to look rather vague and
-     * maybe confusing...  If this is just an indication of code unit
-     * size, maybe that is no problem.  Otherwise, should we try to
-     * create an aggregate collection of GSM and CDMA encodings?  CDMA
-     * contains a superset of the encodings we use (it does not
-     * support 8-bit GSM, but we also do not use that encoding
-     * currently)...  We could get rid of these and directly reference
-     * the CDMA encoding definitions...
-     */
-
     /** User data text encoding code unit size */
     public static final int ENCODING_UNKNOWN = 0;
     public static final int ENCODING_7BIT = 1;
@@ -71,24 +59,9 @@
     public static final int MAX_USER_DATA_BYTES = 140;
 
     /**
-     * TODO(cleanup): It would be more flexible and less fragile to
-     * rewrite this (meaning get rid of the following constant) such
-     * that an actual UDH is taken into consideration (meaning its
-     * length is measured), allowing for messages that actually
-     * contain other UDH fields...  Hence it is actually a shame to
-     * extend the API with this constant.  If necessary, maybe define
-     * the size of such a header and let the math for calculating
-     * max_octets/septets be done elsewhere.  And, while I am griping,
-     * if we use the word septet, we should use the word octet in
-     * corresponding places, not byte...
-     */
-
-    /**
      * The maximum number of payload bytes per message if a user data header
      * is present.  This assumes the header only contains the
      * CONCATENATED_8_BIT_REFERENCE element.
-     *
-     * @hide pending API Council approval to extend the public API
      */
     public static final int MAX_USER_DATA_BYTES_WITH_HEADER = 134;
 
@@ -103,17 +76,26 @@
     public static final int MAX_USER_DATA_SEPTETS_WITH_HEADER = 153;
 
     /** Contains actual SmsMessage. Only public for debugging and for framework layer.
-    * {@hide}
-    */
+     *
+     * @hide
+     */
     public SmsMessageBase mWrappedSmsMessage;
 
-    public static class SubmitPdu extends SubmitPduBase {
+    public static class SubmitPdu {
 
-        //Constructor
-        public SubmitPdu() {
+        public byte[] encodedScAddress; // Null if not applicable.
+        public byte[] encodedMessage;
+
+        public String toString() {
+            return "SubmitPdu: encodedScAddress = "
+                    + Arrays.toString(encodedScAddress)
+                    + ", encodedMessage = "
+                    + Arrays.toString(encodedMessage);
         }
 
-        /* {@hide} */
+        /**
+         * @hide
+         */
         protected SubmitPdu(SubmitPduBase spb) {
             this.encodedMessage = spb.encodedMessage;
             this.encodedScAddress = spb.encodedScAddress;
@@ -121,7 +103,11 @@
 
     }
 
-    // Constructor
+    /**
+     * Constructor
+     *
+     * @hide
+     */
     public SmsMessage() {
         this(getSmsFacility());
     }
@@ -295,6 +281,8 @@
      * @param text text, must not be null.
      * @return an <code>ArrayList</code> of strings that, in order,
      *   comprise the original msg text
+     *
+     * @hide
      */
     public static ArrayList<String> fragmentText(String text) {
         int activePhone = TelephonyManager.getDefault().getPhoneType();
@@ -343,10 +331,11 @@
      * current encoding.
      *
      * @param messageBody the message to encode
-     * @param use7bitOnly if true, characters that are not part of the GSM
-     *         alphabet are counted as a single space char.  If false, a
-     *         messageBody containing non-GSM alphabet characters is calculated
-     *         for 16-bit encoding.
+     * @param use7bitOnly if true, characters that are not part of the radio
+     *         specific (GSM / CDMA) alphabet encoding are converted to as a
+     *         single space characters. If false, a messageBody containing
+     *         non-GSM or non-CDMA alphabet characters are encoded using
+     *         16-bit encoding.
      * @return an int[4] with int[0] being the number of SMS's required, int[1]
      *         the number of code units used, and int[2] is the number of code
      *         units remaining until the next message. int[3] is the encoding
@@ -688,6 +677,8 @@
     /** This method returns the reference to a specific
      *  SmsMessage object, which is used for accessing its static methods.
      * @return Specific SmsMessage.
+     *
+     * @hide
      */
     private static final SmsMessageBase getSmsFacility(){
         int activePhone = TelephonyManager.getDefault().getPhoneType();
diff --git a/telephony/java/android/telephony/gsm/SmsManager.java b/telephony/java/android/telephony/gsm/SmsManager.java
index cdd707e..241c485 100644
--- a/telephony/java/android/telephony/gsm/SmsManager.java
+++ b/telephony/java/android/telephony/gsm/SmsManager.java
@@ -43,6 +43,7 @@
         return sInstance;
     }
 
+    @Deprecated
     private SmsManager() {
         mSmsMgrProxy = android.telephony.SmsManager.getDefault();
     }
diff --git a/telephony/java/com/android/internal/telephony/CommandsInterface.java b/telephony/java/com/android/internal/telephony/CommandsInterface.java
index c52fe06..6ebd8d6 100644
--- a/telephony/java/com/android/internal/telephony/CommandsInterface.java
+++ b/telephony/java/com/android/internal/telephony/CommandsInterface.java
@@ -1300,11 +1300,13 @@
      *            the username for APN, or NULL
      * @param password
      *            the password for APN, or NULL
+     * @param authType
+     *            the PAP / CHAP auth type. Values is one of SETUP_DATA_AUTH_*
      * @param result
      *            Callback message
      */
     public void setupDataCall(String radioTechnology, String profile, String apn,
-            String user, String password, Message result);
+            String user, String password, String authType, Message result);
 
     /**
      * Deactivate packet data connection
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index 52f6526..50bf218 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -1237,10 +1237,17 @@
      */
     public void
     setupDefaultPDP(String apn, String user, String password, Message result) {
-        String radioTechnology = "1"; //0 for CDMA, 1 for GSM/UMTS
+        int radioTechnology;
+        int authType;
         String profile = ""; //profile number, NULL for GSM/UMTS
-        setupDataCall(radioTechnology, profile, apn, user,
-                password, result);
+
+        radioTechnology = RILConstants.SETUP_DATA_TECH_GSM;
+        //TODO(): Add to the APN database, AuthType is set to CHAP/PAP
+        authType = (user != null) ? RILConstants.SETUP_DATA_AUTH_PAP_CHAP
+                : RILConstants.SETUP_DATA_AUTH_NONE;
+
+        setupDataCall(Integer.toString(radioTechnology), profile, apn, user,
+                password, Integer.toString(authType), result);
 
     }
 
@@ -1259,7 +1266,7 @@
      */
     public void
     setupDataCall(String radioTechnology, String profile, String apn,
-            String user, String password, Message result) {
+            String user, String password, String authType, Message result) {
         RILRequest rr
                 = RILRequest.obtain(RIL_REQUEST_SETUP_DATA_CALL, result);
 
@@ -1270,15 +1277,12 @@
         rr.mp.writeString(apn);
         rr.mp.writeString(user);
         rr.mp.writeString(password);
-        //TODO(): Add to the APN database, AuthType is set to CHAP/PAP
-        // 0 => Neither PAP nor CHAP will be performed, 3 => PAP / CHAP will be performed.
-        if (user != null)
-            rr.mp.writeString("3");
-        else
-            rr.mp.writeString("0");
+        rr.mp.writeString(authType);
 
-        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) + " "
-                + apn);
+        if (RILJ_LOGD) riljLog(rr.serialString() + "> "
+                + requestToString(rr.mRequest) + " " + radioTechnology + " "
+                + profile + " " + apn + " " + user + " "
+                + password + " " + authType);
 
         send(rr);
     }
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 1f4ce3d..90a82f9 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -79,6 +79,14 @@
     int CDM_TTY_HCO_MODE = 2;
     int CDM_TTY_VCO_MODE = 3;
 
+    /* Setup a packet data connection. See ril.h RIL_REQUEST_SETUP_DATA_CALL */
+    int SETUP_DATA_TECH_CDMA      = 0;
+    int SETUP_DATA_TECH_GSM       = 1;
+    int SETUP_DATA_AUTH_NONE      = 0;
+    int SETUP_DATA_AUTH_PAP       = 1;
+    int SETUP_DATA_AUTH_CHAP      = 2;
+    int SETUP_DATA_AUTH_PAP_CHAP  = 3;
+
 /*
 cat include/telephony/ril.h | \
    egrep '^#define' | \
@@ -86,14 +94,6 @@
    >>java/android/com.android.internal.telephony/gsm/RILConstants.java
 */
 
-
-    int RIL_SIM_ABSENT = 0;
-    int RIL_SIM_NOT_READY = 1;
-    int RIL_SIM_READY = 2;
-    int RIL_SIM_PIN = 3;
-    int RIL_SIM_PUK = 4;
-    int RIL_SIM_NETWORK_PERSONALIZATION = 5;
-
     /**
      * No restriction at all including voice/SMS/USSD/SS/AV64
      * and packet data.
diff --git a/telephony/java/com/android/internal/telephony/SmsMessageBase.java b/telephony/java/com/android/internal/telephony/SmsMessageBase.java
index 9c78b98..6177c8a 100644
--- a/telephony/java/com/android/internal/telephony/SmsMessageBase.java
+++ b/telephony/java/com/android/internal/telephony/SmsMessageBase.java
@@ -118,6 +118,7 @@
         public int codeUnitSize;
     }
 
+    // TODO(): This class is duplicated in SmsMessage.java. Refactor accordingly.
     public static abstract class SubmitPduBase  {
         public byte[] encodedScAddress; // Null if not applicable.
         public byte[] encodedMessage;
@@ -371,16 +372,10 @@
          * -or-
          * 2. [x@y][ ]/[body]
          */
-         String[] parts = messageBody.split("( /)|( )", 3);
-         if (parts.length < 2 || parts[0].indexOf('@') == -1) return;
+         String[] parts = messageBody.split("( /)|( )", 2);
+         if (parts.length < 1 || parts[0].indexOf('@') == -1) return;
          emailFrom = parts[0];
-         if (parts.length == 3) {
-             pseudoSubject = parts[1];
-             emailBody = parts[2];
-         } else {
-             pseudoSubject = null;
-             emailBody = parts[1];
-         }
+         emailBody = parts[1];
          isEmail = true;
     }
 
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index 28ce6a5..0d46777 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -1338,25 +1338,26 @@
         return isOtaSpNum;
     }
 
-     /**
-      * isOTASPNumber: checks a given number against the IS-683A OTASP dial string and carrier
-      * OTASP dial string.
-      *
-      * @param dialStr the number to look up.
-      * @return true if the number is in IS-683A OTASP dial string or carrier OTASP dial string
-      */
+    /**
+     * isOTASPNumber: checks a given number against the IS-683A OTASP dial string and carrier
+     * OTASP dial string.
+     *
+     * @param dialStr the number to look up.
+     * @return true if the number is in IS-683A OTASP dial string or carrier OTASP dial string
+     */
     @Override
-     public  boolean isOtaSpNumber(String dialStr){
-         boolean isOtaSpNum = false;
-         if (dialStr != null) {
-             isOtaSpNum = isIs683OtaSpDialStr(dialStr);
-             if(isOtaSpNum == false){
-                 isOtaSpNum = isCarrierOtaSpNum(dialStr);
-             }
-         }
-         if (DBG) Log.d(LOG_TAG, "isOtaSpNumber " + isOtaSpNum);
-         return isOtaSpNum;
-     }
+    public  boolean isOtaSpNumber(String dialStr){
+        boolean isOtaSpNum = false;
+        String dialableStr = PhoneNumberUtils.extractNetworkPortion(dialStr);
+        if (dialableStr != null) {
+            isOtaSpNum = isIs683OtaSpDialStr(dialableStr);
+            if (isOtaSpNum == false) {
+                isOtaSpNum = isCarrierOtaSpNum(dialableStr);
+            }
+        }
+        if (DBG) Log.d(LOG_TAG, "isOtaSpNumber " + isOtaSpNum);
+        return isOtaSpNum;
+    }
 
     @Override
     public int getCdmaEriIconIndex() {
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
index fef6d3c..4588f36 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
@@ -143,9 +143,10 @@
         lastFailTime = -1;
         lastFailCause = FailCause.NONE;
         receivedDisconnectReq = false;
-        phone.mCM.setupDataCall(Integer.toString(RILConstants.CDMA_PHONE),
+        phone.mCM.setupDataCall(Integer.toString(RILConstants.SETUP_DATA_TECH_CDMA),
                 Integer.toString(RILConstants.DATA_PROFILE_DEFAULT), null, null,
-                null, obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE));
+                null, Integer.toString(RILConstants.SETUP_DATA_AUTH_PAP_CHAP),
+                obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE));
     }
 
     private void tearDownData(Message msg) {
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
index 3ab1f77..1f1f7c1 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
@@ -19,6 +19,7 @@
 
 import android.app.Activity;
 import android.app.PendingIntent;
+import android.app.PendingIntent.CanceledException;
 import android.content.ContentValues;
 import android.content.SharedPreferences;
 import android.database.Cursor;
@@ -31,6 +32,7 @@
 import android.preference.PreferenceManager;
 import android.util.Config;
 import android.util.Log;
+import android.telephony.SmsManager;
 
 import com.android.internal.telephony.TelephonyProperties;
 import com.android.internal.telephony.CommandsInterface;
@@ -45,6 +47,7 @@
 import java.io.ByteArrayOutputStream;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.lang.Boolean;
 
 
 final class CdmaSMSDispatcher extends SMSDispatcher {
@@ -331,6 +334,24 @@
                 sentIntent, deliveryIntent);
     }
 
+    protected void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent,
+            PendingIntent deliveryIntent) {
+        String inEcm = SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE);
+        if (Boolean.parseBoolean(inEcm)) {
+            if (sentIntent != null) {
+                try {
+                    sentIntent.send(SmsManager.RESULT_ERROR_NO_SERVICE);
+                } catch (CanceledException ex) {}
+            }
+            if (Config.LOGD) {
+                Log.d(TAG, "Block SMS in Emergency Callback mode");
+            }
+            return;
+        }
+
+        super.sendRawPdu(smsc, pdu, sentIntent, deliveryIntent);
+    }
+
     /** {@inheritDoc} */
     protected void sendSms(SmsTracker tracker) {
         HashMap map = tracker.mData;
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index 0cae604..53f0274 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -121,8 +121,8 @@
     private int curSpnRule = 0;
 
     private String mMdn;
-    private int mHomeSystemId;
-    private int mHomeNetworkId;
+    private int mHomeSystemId[] = null;
+    private int mHomeNetworkId[] = null;
     private String mMin;
     private String mPrlVersion;
 
@@ -398,23 +398,31 @@
                 String cdmaSubscription[] = (String[])ar.result;
                 if (cdmaSubscription != null && cdmaSubscription.length >= 5) {
                     mMdn = cdmaSubscription[0];
-                    // TODO: Only grabbing the first SID/NID for now.
                     if (cdmaSubscription[1] != null) {
                         String[] sid = cdmaSubscription[1].split(",");
-                        try {
-                            mHomeSystemId = sid.length > 0 ? Integer.parseInt(sid[0]) : 0;
-                        } catch (NumberFormatException e) {
-                            mHomeSystemId = 0;
+                        mHomeSystemId = new int[sid.length];
+                        for (int i = 0; i < sid.length; i++) {
+                            try {
+                                mHomeSystemId[i] = Integer.parseInt(sid[i]);
+                            } catch (NumberFormatException ex) {
+                                Log.e(LOG_TAG, "error parsing system id: ", ex);
+                            }
                         }
                     }
+                    Log.d(LOG_TAG,"GET_CDMA_SUBSCRIPTION SID=" + cdmaSubscription[1] );
+
                     if (cdmaSubscription[2] != null) {
                         String[] nid = cdmaSubscription[2].split(",");
-                        try {
-                            mHomeNetworkId = nid.length > 0 ? Integer.parseInt(nid[0]) : 0;
-                        } catch (NumberFormatException e) {
-                            mHomeNetworkId = 0;
+                        mHomeNetworkId = new int[nid.length];
+                        for (int i = 0; i < nid.length; i++) {
+                            try {
+                                mHomeNetworkId[i] = Integer.parseInt(nid[i]);
+                            } catch (NumberFormatException ex) {
+                                Log.e(LOG_TAG, "error parsing network id: ", ex);
+                            }
                         }
                     }
+                    Log.d(LOG_TAG,"GET_CDMA_SUBSCRIPTION NID=" + cdmaSubscription[2] );
                     mMin = cdmaSubscription[3];
                     mPrlVersion = cdmaSubscription[4];
                     Log.d(LOG_TAG,"GET_CDMA_SUBSCRIPTION MDN=" + mMdn);
@@ -712,7 +720,7 @@
 
         if (pollingContext[0] == 0) {
             boolean namMatch = false;
-            if ((mHomeSystemId != 0) && (mHomeSystemId == newSS.getSystemId()) ) {
+            if (!isSidsAllZeros() && isHomeSid(newSS.getSystemId())) {
                 namMatch = true;
             }
 
@@ -724,33 +732,43 @@
             }
 
             // Setting SS CdmaRoamingIndicator and CdmaDefaultRoamingIndicator
-            // TODO(Teleca): Validate this is correct.
-            if (mIsInPrl) {
-                if (namMatch && (mRoamingIndicator <= 2)) {
-                        // System is acquired, prl match, nam match and mRoamingIndicator <= 2
-                        newSS.setCdmaRoamingIndicator(EriInfo.ROAMING_INDICATOR_OFF);
-                } else {
-                    // System is acquired, prl match, no nam match  or mRoamingIndicator > 2
-                    newSS.setCdmaRoamingIndicator(mRoamingIndicator);
-                }
-            } else {
-                if (mRegistrationState == 5) {
-                    // System is acquired but prl not loaded or no prl match
+            newSS.setCdmaDefaultRoamingIndicator(mDefaultRoamingIndicator);
+            newSS.setCdmaRoamingIndicator(mRoamingIndicator);
+            boolean isPrlLoaded = true;
+            if (TextUtils.isEmpty(mPrlVersion)) {
+                isPrlLoaded = false;
+            }
+            if (!isPrlLoaded) {
+                newSS.setCdmaRoamingIndicator(EriInfo.ROAMING_INDICATOR_FLASH);
+            } else if (!isSidsAllZeros()) {
+                if (!namMatch && !mIsInPrl) {
+                    // Use default
+                    newSS.setCdmaRoamingIndicator(mDefaultRoamingIndicator);
+                } else if (namMatch && !mIsInPrl) {
                     newSS.setCdmaRoamingIndicator(EriInfo.ROAMING_INDICATOR_FLASH);
+                } else if (!namMatch && mIsInPrl) {
+                    // Use the one from PRL/ERI
+                    newSS.setCdmaRoamingIndicator(mRoamingIndicator);
                 } else {
-                    // Use the default indicator
+                    // It means namMatch && mIsInPrl
+                    if ((mRoamingIndicator <= 2)) {
+                        newSS.setCdmaRoamingIndicator(EriInfo.ROAMING_INDICATOR_OFF);
+                    } else {
+                        // Use the one from PRL/ERI
+                        newSS.setCdmaRoamingIndicator(mRoamingIndicator);
+                    }
                 }
             }
 
-            newSS.setCdmaDefaultRoamingIndicator(mDefaultRoamingIndicator);
 
             // NOTE: Some operator may require to override the mCdmaRoaming (set by the modem)
             // depending on the mRoamingIndicator.
 
             if (DBG) {
                 log("Set CDMA Roaming Indicator to: " + newSS.getCdmaRoamingIndicator()
-                    + ". mCdmaRoaming = " + mCdmaRoaming + ",  namMatch = " + namMatch
-                    + ", mIsInPrl = " + mIsInPrl + ", mRoamingIndicator = " + mRoamingIndicator
+                    + ". mCdmaRoaming = " + mCdmaRoaming + ", isPrlLoaded = " + isPrlLoaded
+                    + ". namMatch = " + namMatch + " , mIsInPrl = " + mIsInPrl
+                    + ", mRoamingIndicator = " + mRoamingIndicator
                     + ", mDefaultRoamingIndicator= " + mDefaultRoamingIndicator);
             }
             pollStateDone();
@@ -1458,6 +1476,31 @@
         }
     }
 
+    private boolean isSidsAllZeros() {
+        if (mHomeSystemId != null) {
+            for (int i=0; i < mHomeSystemId.length; i++) {
+                if (mHomeSystemId[i] != 0) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Check whether a specified system ID that matches one of the home system IDs.
+     */
+    private boolean isHomeSid(int sid) {
+        if (mHomeSystemId != null) {
+            for (int i=0; i < mHomeSystemId.length; i++) {
+                if (sid == mHomeSystemId[i]) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     /**
      * @return true if phone is camping on a technology
      * that could support voice and data simultaneously.
diff --git a/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java b/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java
index 89de867..224419e 100644
--- a/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java
+++ b/telephony/java/com/android/internal/telephony/gsm/PdpConnection.java
@@ -84,9 +84,13 @@
         lastFailCause = FailCause.NONE;
         receivedDisconnectReq = false;
 
-        phone.mCM.setupDataCall(Integer.toString(RILConstants.GSM_PHONE),
+        int authType = (apn.user != null) ? RILConstants.SETUP_DATA_AUTH_PAP_CHAP :
+            RILConstants.SETUP_DATA_AUTH_NONE;
+
+        phone.mCM.setupDataCall(Integer.toString(RILConstants.SETUP_DATA_TECH_GSM),
                 Integer.toString(RILConstants.DATA_PROFILE_DEFAULT), apn.apn, apn.user,
-                apn.password, obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE));
+                apn.password, Integer.toString(authType),
+                obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE));
     }
 
     private void tearDownData(Message msg) {
diff --git a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
index be5b842..11b3fd6 100644
--- a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
+++ b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
@@ -944,7 +944,7 @@
     }
 
     public void setupDataCall(String radioTechnology, String profile, String apn, String user,
-            String password, Message result) {
+            String password, String authType, Message result) {
         unimplemented(result);
     }
 
diff --git a/tests/DpiTest/res/drawable-hdpi/reslogo240dpi.png b/tests/DpiTest/res/drawable-hdpi/reslogo240dpi.png
new file mode 100644
index 0000000..4d717a8
--- /dev/null
+++ b/tests/DpiTest/res/drawable-hdpi/reslogo240dpi.png
Binary files differ
diff --git a/tests/DpiTest/res/drawable-hdpi/stylogo240dpi.png b/tests/DpiTest/res/drawable-hdpi/stylogo240dpi.png
new file mode 100644
index 0000000..4d717a8
--- /dev/null
+++ b/tests/DpiTest/res/drawable-hdpi/stylogo240dpi.png
Binary files differ
diff --git a/tests/DpiTest/res/drawable-ldpi/reslogo120dpi.png b/tests/DpiTest/res/drawable-ldpi/reslogo120dpi.png
new file mode 100644
index 0000000..46bbd5b
--- /dev/null
+++ b/tests/DpiTest/res/drawable-ldpi/reslogo120dpi.png
Binary files differ
diff --git a/tests/DpiTest/res/drawable-ldpi/stylogo120dpi.png b/tests/DpiTest/res/drawable-ldpi/stylogo120dpi.png
new file mode 100644
index 0000000..46bbd5b
--- /dev/null
+++ b/tests/DpiTest/res/drawable-ldpi/stylogo120dpi.png
Binary files differ
diff --git a/tests/DpiTest/res/drawable/reslogo160dpi.png b/tests/DpiTest/res/drawable/reslogo160dpi.png
new file mode 100644
index 0000000..c23b2ce
--- /dev/null
+++ b/tests/DpiTest/res/drawable/reslogo160dpi.png
Binary files differ
diff --git a/tests/DpiTest/res/drawable/stylogo160dpi.png b/tests/DpiTest/res/drawable/stylogo160dpi.png
new file mode 100644
index 0000000..c23b2ce
--- /dev/null
+++ b/tests/DpiTest/res/drawable/stylogo160dpi.png
Binary files differ
diff --git a/tests/DpiTest/res/layout/image_views.xml b/tests/DpiTest/res/layout/image_views.xml
new file mode 100644
index 0000000..6a91497
--- /dev/null
+++ b/tests/DpiTest/res/layout/image_views.xml
@@ -0,0 +1,37 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content">
+
+    <ImageView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:src="@drawable/reslogo120dpi" />
+
+    <ImageView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:src="@drawable/reslogo160dpi" />
+
+    <ImageView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:src="@drawable/reslogo240dpi" />
+
+</LinearLayout>
diff --git a/tests/DpiTest/res/layout/styled_image_views.xml b/tests/DpiTest/res/layout/styled_image_views.xml
new file mode 100644
index 0000000..86c63bf
--- /dev/null
+++ b/tests/DpiTest/res/layout/styled_image_views.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content">
+
+    <ImageView style="@style/ImageView120dpi" />
+    <ImageView style="@style/ImageView160dpi" />
+    <ImageView style="@style/ImageView240dpi" />
+
+</LinearLayout>
diff --git a/tests/DpiTest/res/values/styles.xml b/tests/DpiTest/res/values/styles.xml
new file mode 100644
index 0000000..bb4b13c
--- /dev/null
+++ b/tests/DpiTest/res/values/styles.xml
@@ -0,0 +1,35 @@
+<?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.
+-->
+
+<resources>
+    <style name="ImageView120dpi">
+        <item name="android:src">@drawable/stylogo120dpi</item>
+        <item name="android:layout_width">wrap_content</item>
+        <item name="android:layout_height">wrap_content</item>
+    </style>
+
+    <style name="ImageView160dpi">
+        <item name="android:src">@drawable/stylogo160dpi</item>
+        <item name="android:layout_width">wrap_content</item>
+        <item name="android:layout_height">wrap_content</item>
+    </style>
+
+    <style name="ImageView240dpi">
+        <item name="android:src">@drawable/stylogo240dpi</item>
+        <item name="android:layout_width">wrap_content</item>
+        <item name="android:layout_height">wrap_content</item>
+    </style>
+</resources>
diff --git a/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java b/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java
index 68220a1..ae53b76 100644
--- a/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java
+++ b/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java
@@ -28,6 +28,7 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 import android.widget.ScrollView;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
@@ -71,6 +72,9 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
+        final LayoutInflater li = (LayoutInflater)getSystemService(
+                LAYOUT_INFLATER_SERVICE);
+        
         this.setTitle(R.string.act_title);
         LinearLayout root = new LinearLayout(this);
         root.setOrientation(LinearLayout.VERTICAL);
@@ -96,6 +100,14 @@
         addLabelToRoot(root, "Prescaled resource drawable");
         addChildToRoot(root, layout);
 
+        layout = (LinearLayout)li.inflate(R.layout.image_views, null);
+        addLabelToRoot(root, "Inflated layout");
+        addChildToRoot(root, layout);
+        
+        layout = (LinearLayout)li.inflate(R.layout.styled_image_views, null);
+        addLabelToRoot(root, "Inflated styled layout");
+        addChildToRoot(root, layout);
+        
         layout = new LinearLayout(this);
         addCanvasBitmap(layout, R.drawable.logo120dpi, true);
         addCanvasBitmap(layout, R.drawable.logo160dpi, true);
diff --git a/vpn/java/android/net/vpn/PptpProfile.java b/vpn/java/android/net/vpn/PptpProfile.java
index c68bb71..b4b7be5 100644
--- a/vpn/java/android/net/vpn/PptpProfile.java
+++ b/vpn/java/android/net/vpn/PptpProfile.java
@@ -16,15 +16,41 @@
 
 package android.net.vpn;
 
+import android.os.Parcel;
+
 /**
  * The profile for PPTP type of VPN.
  * {@hide}
  */
 public class PptpProfile extends VpnProfile {
     private static final long serialVersionUID = 1L;
+    private boolean mEncryption = true;
 
     @Override
     public VpnType getType() {
         return VpnType.PPTP;
     }
+
+    /**
+     * Enables/disables the encryption for PPTP tunnel.
+     */
+    public void setEncryptionEnabled(boolean enabled) {
+        mEncryption = enabled;
+    }
+
+    public boolean isEncryptionEnabled() {
+        return mEncryption;
+    }
+
+    @Override
+    protected void readFromParcel(Parcel in) {
+        super.readFromParcel(in);
+        mEncryption = in.readInt() > 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        super.writeToParcel(parcel, flags);
+        parcel.writeInt(mEncryption ? 1 : 0);
+    }
 }
diff --git a/vpn/java/android/net/vpn/VpnManager.java b/vpn/java/android/net/vpn/VpnManager.java
index 0bf2346..e448e5a 100644
--- a/vpn/java/android/net/vpn/VpnManager.java
+++ b/vpn/java/android/net/vpn/VpnManager.java
@@ -50,6 +50,10 @@
     public static final int VPN_ERROR_CONNECTION_FAILED = 2;
     /** Error code to indicate the server is not known. */
     public static final int VPN_ERROR_UNKNOWN_SERVER = 3;
+    /** Error code to indicate an error from challenge response. */
+    public static final int VPN_ERROR_CHALLENGE = 4;
+    /** Error code to indicate an error of remote server hanging up. */
+    public static final int VPN_ERROR_REMOTE_HUNG_UP = 5;
     private static final int VPN_ERROR_NO_ERROR = 0;
 
     public static final String PROFILES_PATH = "/data/misc/vpn/profiles";