Merge change 25523 into eclair

* changes:
  Add additional error checking, exit early if errors occur.
diff --git a/Android.mk b/Android.mk
index 138ff09..4e7b14e 100644
--- a/Android.mk
+++ b/Android.mk
@@ -126,6 +126,8 @@
 	core/java/android/view/IWindow.aidl \
 	core/java/android/view/IWindowManager.aidl \
 	core/java/android/view/IWindowSession.aidl \
+	core/java/android/speech/IRecognitionListener.aidl \
+	core/java/android/speech/IRecognitionService.aidl \
 	core/java/android/speech/tts/ITts.aidl \
 	core/java/android/speech/tts/ITtsCallback.aidl \
 	core/java/com/android/internal/app/IBatteryStats.aidl \
diff --git a/api/current.xml b/api/current.xml
index 7562f2e..2c9a087 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -10659,6 +10659,17 @@
  visibility="public"
 >
 </field>
+<field name="screen_background_light_transparent"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="17301674"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="spinner_background"
  type="int"
  transient="false"
@@ -12714,6 +12725,17 @@
  visibility="public"
 >
 </field>
+<field name="Theme_Light_WallpaperSettings"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16973922"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="Theme_NoDisplay"
  type="int"
  transient="false"
@@ -12802,6 +12824,17 @@
  visibility="public"
 >
 </field>
+<field name="Theme_WallpaperSettings"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16973921"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="Theme_Wallpaper_NoTitleBar"
  type="int"
  transient="false"
@@ -26104,6 +26137,16 @@
 <parameter name="flags" type="int">
 </parameter>
 </method>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 </class>
 <class name="BluetoothClass.Device"
  extends="java.lang.Object"
@@ -27164,6 +27207,16 @@
  visibility="public"
 >
 </field>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="ERROR"
  type="int"
  transient="false"
@@ -27368,6 +27421,87 @@
 >
 </method>
 </class>
+<class name="ParcelUuid"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<constructor name="ParcelUuid"
+ type="android.bluetooth.ParcelUuid"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uuid" type="java.util.UUID">
+</parameter>
+</constructor>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="fromString"
+ return="android.bluetooth.ParcelUuid"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uuid" type="java.lang.String">
+</parameter>
+</method>
+<method name="getUuid"
+ return="java.util.UUID"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="dest" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
 </package>
 <package name="android.content"
 >
@@ -35145,6 +35279,17 @@
  visibility="public"
 >
 </field>
+<field name="ACTION_DOCK_EVENT"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.intent.action.DOCK_EVENT&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="ACTION_EDIT"
  type="java.lang.String"
  transient="false"
@@ -35860,6 +36005,17 @@
  visibility="public"
 >
 </field>
+<field name="CATEGORY_CAR_DOCK"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.intent.category.CAR_DOCK&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="CATEGORY_DEFAULT"
  type="java.lang.String"
  transient="false"
@@ -35871,6 +36027,17 @@
  visibility="public"
 >
 </field>
+<field name="CATEGORY_DESK_DOCK"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.intent.category.DESK_DOCK&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="CATEGORY_DEVELOPMENT_PREFERENCE"
  type="java.lang.String"
  transient="false"
@@ -36090,6 +36257,50 @@
  visibility="public"
 >
 </field>
+<field name="EXTRA_DOCK_STATE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.intent.extra.DOCK_STATE&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_DOCK_STATE_CAR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_DOCK_STATE_DESK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_DOCK_STATE_UNDOCKED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="EXTRA_DONT_KILL_APP"
  type="java.lang.String"
  transient="false"
@@ -43753,6 +43964,39 @@
  visibility="public"
 >
 </field>
+<field name="NAVIGATIONHIDDEN_NO"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="NAVIGATIONHIDDEN_UNDEFINED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="NAVIGATIONHIDDEN_YES"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="NAVIGATION_DPAD"
  type="int"
  transient="false"
@@ -44075,6 +44319,16 @@
  visibility="public"
 >
 </field>
+<field name="navigationHidden"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="orientation"
  type="int"
  transient="false"
@@ -66923,6 +67177,17 @@
 <parameter name="cb" type="android.hardware.Camera.AutoFocusCallback">
 </parameter>
 </method>
+<method name="cancelAutoFocus"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getParameters"
  return="android.hardware.Camera.Parameters"
  abstract="false"
@@ -77281,6 +77546,387 @@
 </parameter>
 </method>
 </interface>
+<class name="ExifInterface"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="ExifInterface"
+ type="android.media.ExifInterface"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="filename" type="java.lang.String">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</constructor>
+<method name="getAttribute"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="tag" type="java.lang.String">
+</parameter>
+</method>
+<method name="getDateTime"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getLatLong"
+ return="float[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getOrientationString"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getThumbnail"
+ return="byte[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getWhiteBalanceString"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="hasThumbnail"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="saveAttributes"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="setAttribute"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="tag" type="java.lang.String">
+</parameter>
+<parameter name="value" type="java.lang.String">
+</parameter>
+</method>
+<field name="ORIENTATION_FLIP_HORIZONTAL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ORIENTATION_FLIP_VERTICAL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ORIENTATION_NORMAL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ORIENTATION_ROTATE_180"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ORIENTATION_ROTATE_270"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="8"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ORIENTATION_ROTATE_90"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="6"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ORIENTATION_TRANSPOSE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="5"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ORIENTATION_TRANSVERSE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="7"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ORIENTATION_UNDEFINED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TAG_DATETIME"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;DateTime&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TAG_FLASH"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;Flash&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TAG_GPS_LATITUDE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;GPSLatitude&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TAG_GPS_LATITUDE_REF"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;GPSLatitudeRef&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TAG_GPS_LONGITUDE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;GPSLongitude&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TAG_GPS_LONGITUDE_REF"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;GPSLongitudeRef&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TAG_IMAGE_LENGTH"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;ImageLength&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TAG_IMAGE_WIDTH"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;ImageWidth&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TAG_MAKE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;Make&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TAG_MODEL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;Model&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TAG_ORIENTATION"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;Orientation&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TAG_WHITE_BALANCE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;WhiteBalance&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="WHITEBALANCE_AUTO"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="WHITEBALANCE_MANUAL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
 <class name="FaceDetector"
  extends="java.lang.Object"
  abstract="false"
@@ -117496,6 +118142,37 @@
 </implements>
 </interface>
 </package>
+<package name="android.service.wallpaper"
+>
+<class name="WallpaperSettingsActivity"
+ extends="android.preference.PreferenceActivity"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="WallpaperSettingsActivity"
+ type="android.service.wallpaper.WallpaperSettingsActivity"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<field name="EXTRA_PREVIEW_MODE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.service.wallpaper.PREVIEW_MODE&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+</package>
 <package name="android.speech"
 >
 <class name="RecognizerIntent"
@@ -128787,6 +129464,17 @@
  visibility="public"
 >
 </field>
+<field name="TYPE_TEXT_FLAG_NO_SUGGESTIONS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="524288"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="TYPE_TEXT_VARIATION_EMAIL_ADDRESS"
  type="int"
  transient="false"
@@ -159296,6 +159984,17 @@
  visibility="public"
 >
 </field>
+<field name="FLAG_TURN_SCREEN_ON"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2097152"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="FLAG_WATCH_OUTSIDE_TOUCH"
  type="int"
  transient="false"
@@ -167438,24 +168137,13 @@
 </parameter>
 </method>
 </class>
-<class name="PluginStub"
- extends="java.lang.Object"
+<interface name="PluginStub"
  abstract="true"
  static="false"
  final="false"
  deprecated="not deprecated"
  visibility="public"
 >
-<constructor name="PluginStub"
- type="android.webkit.PluginStub"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="npp" type="int">
-</parameter>
-</constructor>
 <method name="getEmbeddedView"
  return="android.view.View"
  abstract="true"
@@ -167466,6 +168154,8 @@
  deprecated="not deprecated"
  visibility="public"
 >
+<parameter name="NPP" type="int">
+</parameter>
 <parameter name="context" type="android.content.Context">
 </parameter>
 </method>
@@ -167479,10 +168169,12 @@
  deprecated="not deprecated"
  visibility="public"
 >
+<parameter name="NPP" type="int">
+</parameter>
 <parameter name="context" type="android.content.Context">
 </parameter>
 </method>
-</class>
+</interface>
 <class name="SslErrorHandler"
  extends="android.os.Handler"
  abstract="false"
diff --git a/cmds/keystore/netkeystore.c b/cmds/keystore/netkeystore.c
index 83c7871..87fdc80 100644
--- a/cmds/keystore/netkeystore.c
+++ b/cmds/keystore/netkeystore.c
@@ -116,10 +116,13 @@
 
 static int is_alnum_string(char *s)
 {
+    char *s0 = s;
     while (*s != 0) {
-        if (!isalnum(*s++)) return 0;
+        if (!isalnum(*s++)) {
+            LOGE("The string '%s' is not an alphanumeric string\n", s0);
+            return 0;
+        }
     }
-    LOGE("The string %s is not an alphanumeric string\n", s);
     return 1;
 }
 
@@ -159,7 +162,9 @@
 // no argument
 static void do_get_state(LPC_MARSHAL *cmd, LPC_MARSHAL *reply)
 {
-    reply->retcode = get_state();
+    int s = get_state();
+    if (DBG) LOGD("keystore state = %d\n", s);
+    reply->retcode = s;
 }
 
 // args of listkeys():
@@ -413,12 +418,10 @@
 
         // read the command, execute and send the result back.
         if(read_marshal(s, &cmd)) goto err;
-        if (DBG) LOGD("new connection\n");
         execute(&cmd, &reply);
         write_marshal(s, &reply);
 err:
         memset(&reply, 0, sizeof(LPC_MARSHAL));
-        if (DBG) LOGD("closing connection\n");
         close(s);
     }
 
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index c13893a..4217957 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -46,7 +46,6 @@
 import android.app.PendingIntent;
 import android.app.NotificationManager;
 import android.app.Notification;
-import android.app.Activity;
 import android.Manifest;
 
 import java.io.FileDescriptor;
@@ -471,6 +470,7 @@
     }
 
     private boolean saveAuthTokenToDatabase(Account account, String type, String authToken) {
+        cancelNotification(getSigninRequiredNotificationId(account));
         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
         db.beginTransaction();
         try {
@@ -523,7 +523,7 @@
         checkAuthenticateAccountsPermission(account);
         long identityToken = clearCallingIdentity();
         try {
-            cacheAuthToken(account, authTokenType, authToken);
+            saveAuthTokenToDatabase(account, authTokenType, authToken);
         } finally {
             restoreCallingIdentity(identityToken);
         }
@@ -686,7 +686,8 @@
                                         "the type and name should not be empty");
                                 return;
                             }
-                            cacheAuthToken(new Account(name, type), authTokenType, authToken);
+                            saveAuthTokenToDatabase(new Account(name, type),
+                                    authTokenType, authToken);
                         }
 
                         Intent intent = result.getParcelable(Constants.INTENT_KEY);
@@ -714,11 +715,14 @@
 
         Notification n = new Notification(android.R.drawable.stat_sys_warning, null,
                 0 /* when */);
-        final CharSequence subtitleFormatString =
-                mContext.getText(R.string.permission_request_notification_subtitle);
+        final String titleAndSubtitle =
+                mContext.getString(R.string.permission_request_notification_with_subtitle,
+                account.name);
+        final int index = titleAndSubtitle.indexOf('\n');
+        final String title = titleAndSubtitle.substring(0, index);
+        final String subtitle = titleAndSubtitle.substring(index + 1);
         n.setLatestEventInfo(mContext,
-                mContext.getText(R.string.permission_request_notification_title),
-                String.format(subtitleFormatString.toString(), account.name),
+                title, subtitle,
                 PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT));
         ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
                 .notify(getCredentialPermissionNotificationId(account, authTokenType, uid), n);
@@ -1001,10 +1005,6 @@
         }
     }
 
-    private boolean cacheAuthToken(Account account, String authTokenType, String authToken) {
-        return saveAuthTokenToDatabase(account, authTokenType, authToken);
-    }
-
     private long getAccountId(SQLiteDatabase db, Account account) {
         Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_ID},
                 "name=? AND type=?", new String[]{account.name, account.type}, null, null, null);
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 75a90c4..1209d0f 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -739,11 +739,6 @@
             return false;
         }
 
-        // handle back key to go back to previous searchable, etc.
-        if (handleBackKey(keyCode, event)) {
-            return true;
-        }
-        
         if (keyCode == KeyEvent.KEYCODE_SEARCH) {
             // Consume search key for later use.
             return true;
@@ -756,8 +751,8 @@
             launchQuerySearch(keyCode, actionKey.getQueryActionMsg());
             return true;
         }
-        
-        return false;
+
+        return super.onKeyDown(keyCode, event);
     }
     
     @Override
@@ -767,11 +762,6 @@
             return false;
         }
 
-        // handle back key to go back to previous searchable, etc.
-        if (handleBackKey(keyCode, event)) {
-            return true;
-        }
-        
         if (keyCode == KeyEvent.KEYCODE_SEARCH && event.isTracking()
                 && !event.isCanceled()) {
             // If the search key is pressed, toggle between global and in-app search. If we are
@@ -779,8 +769,8 @@
             // just don't do anything.
             return toggleGlobalSearch();
         }
-        
-        return false;
+
+        return super.onKeyUp(keyCode, event);
     }
     
     /**
@@ -1488,6 +1478,13 @@
     }
 
     /**
+     * Checks if there are any previous searchable components in the history stack.
+     */
+    private boolean hasPreviousComponent() {
+        return mPreviousComponents != null && !mPreviousComponents.isEmpty();
+    }
+
+    /**
      * Saves the previous component that was searched, so that we can go
      * back to it.
      */
@@ -1505,14 +1502,10 @@
      *         no previous component.
      */
     private ComponentName popPreviousComponent() {
-        if (mPreviousComponents == null) {
+        if (!hasPreviousComponent()) {
             return null;
         }
-        int size = mPreviousComponents.size();
-        if (size == 0) {
-            return null;
-        }
-        return mPreviousComponents.remove(size - 1);
+        return mPreviousComponents.remove(mPreviousComponents.size() - 1);
     }
     
     /**
@@ -1520,25 +1513,22 @@
      * 
      * @return <code>true</code> if there was a previous component that we could go back to.
      */
-    private boolean backToPreviousComponent(boolean doIt) {
+    private boolean backToPreviousComponent() {
         ComponentName previous = popPreviousComponent();
         if (previous == null) {
             return false;
         }
-        
-        if (doIt) {
-            if (!show(previous, mAppSearchData, false)) {
-                Log.w(LOG_TAG, "Failed to switch to source " + previous);
-                return false;
-            }
-            
-            // must touch text to trigger suggestions
-            // TODO: should this be the text as it was when the user left
-            // the source that we are now going back to?
-            String query = mSearchAutoComplete.getText().toString();
-            setUserQuery(query);
+
+        if (!show(previous, mAppSearchData, false)) {
+            Log.w(LOG_TAG, "Failed to switch to source " + previous);
+            return false;
         }
-        
+
+        // must touch text to trigger suggestions
+        // TODO: should this be the text as it was when the user left
+        // the source that we are now going back to?
+        String query = mSearchAutoComplete.getText().toString();
+        setUserQuery(query);
         return true;
     }
     
@@ -1763,74 +1753,49 @@
          */
         @Override
         public boolean onKeyPreIme(int keyCode, KeyEvent event) {
+            if (DBG) Log.d(LOG_TAG, "onKeyPreIme(" + keyCode + "," + event + ")");
             if (mSearchDialog.mSearchable == null) {
                 return false;
             }
             if (keyCode == KeyEvent.KEYCODE_BACK) {
                 if (event.getAction() == KeyEvent.ACTION_DOWN
                         && event.getRepeatCount() == 0) {
-                    // We release the back key, might we want to do
-                    // something before the IME?
-                    if (mSearchDialog.backToPreviousComponent(false)) {
+                    if (mSearchDialog.hasPreviousComponent() || isDismissingKeyboardPointless()) {
                         getKeyDispatcherState().startTracking(event, this);
                         return true;
                     }
-                    if (isInputMethodNotNeeded() ||
-                            (isEmpty() && getDropDownChildCount() >= getAdapterCount())) {
-                        getKeyDispatcherState().startTracking(event, this);
-                        return true;
-                    }
-                    return false; // will dismiss soft keyboard if necessary
                 } else if (event.getAction() == KeyEvent.ACTION_UP
                         && event.isTracking() && !event.isCanceled()) {
-                    if (mSearchDialog.backToPreviousComponent(true)) {
+                    if (mSearchDialog.backToPreviousComponent()) {
                         return true;
-                    }
-                    // If the drop-down obscures the keyboard, the user wouldn't see anything
-                    // happening when pressing back, so we dismiss the entire dialog instead.
-                    //
-                    // also: if there is no text entered, we also want to dismiss the whole dialog,
-                    // not just the soft keyboard.  the exception to this is if there are shortcuts
-                    // that aren't displayed (e.g are being obscured by the soft keyboard); in that
-                    // case we want to dismiss the soft keyboard so the user can see the rest of the
-                    // shortcuts.
-                    if (isInputMethodNotNeeded() ||
-                            (isEmpty() && getDropDownChildCount() >= getAdapterCount())) {
+                    } else if (isDismissingKeyboardPointless()) {
                         mSearchDialog.cancel();
                         return true;
                     }
-                    return false; // will dismiss soft keyboard if necessary
                 }
             }
             return false;
         }
 
+        // If the drop-down obscures the keyboard, or if the drop-down shows all suggestions,
+        // dismissing the keyboard is pointless, so we dismiss the entire dialog instead.
+        private boolean isDismissingKeyboardPointless() {
+            return (isInputMethodNotNeeded() || getDropDownChildCount() >= getAdapterCount());
+        }
+
         private int getAdapterCount() {
             final ListAdapter adapter = getAdapter();
             return adapter == null ? 0 : adapter.getCount();
         }
     }
-    
-    protected boolean handleBackKey(int keyCode, KeyEvent event) {
-        if (keyCode == KeyEvent.KEYCODE_BACK) {
-            if (event.getAction() == KeyEvent.ACTION_DOWN
-                    && event.getRepeatCount() == 0) {
-                // Consume the event, to get an up at which point we execute.
-                event.startTracking();
-                return true;
-            }
-            if (event.getAction() == KeyEvent.ACTION_UP && event.isTracking()
-                    && !event.isCanceled()) {
-                if (backToPreviousComponent(true)) {
-                    return true;
-                }
-                cancel();
-            }
-            return true;
+
+    @Override
+    public void onBackPressed() {
+        if (!backToPreviousComponent()) {
+            cancel();
         }
-        return false;
     }
-    
+
     /**
      * Implements OnItemClickListener
      */
diff --git a/core/java/android/app/SuggestionsAdapter.java b/core/java/android/app/SuggestionsAdapter.java
index 8f7e8ca..4f9531e 100644
--- a/core/java/android/app/SuggestionsAdapter.java
+++ b/core/java/android/app/SuggestionsAdapter.java
@@ -20,14 +20,15 @@
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.ContentResolver.OpenResourceIdResult;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
 import android.database.Cursor;
+import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
-import android.graphics.drawable.DrawableContainer;
 import android.graphics.drawable.StateListDrawable;
 import android.net.Uri;
 import android.os.Bundle;
@@ -38,14 +39,15 @@
 import android.util.SparseArray;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.Filter;
 import android.widget.ImageView;
 import android.widget.ResourceCursorAdapter;
 import android.widget.TextView;
-import android.widget.Filter;
 
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.List;
 import java.util.WeakHashMap;
 
 /**
@@ -580,14 +582,26 @@
             // Not cached, try using it as a plain resource ID in the provider's context.
             int resourceId = Integer.parseInt(drawableId);
             drawable = mProviderContext.getResources().getDrawable(resourceId);
-            if (DBG) Log.d(LOG_TAG, "Found icon by resource ID: " + drawableId);
         } catch (NumberFormatException nfe) {
-            // The id was not an integer resource id.
-            // Let the ContentResolver handle content, android.resource and file URIs.
+            // The id was not an integer resource id, use it as a URI
             try {
                 Uri uri = Uri.parse(drawableId);
-                InputStream stream = mProviderContext.getContentResolver().openInputStream(uri);
-                if (stream != null) {
+                String scheme = uri.getScheme();
+                if (ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)) {
+                    // Load drawables through Resources, to get the source density information
+                    OpenResourceIdResult r =
+                            mProviderContext.getContentResolver().getResourceId(uri);
+                    try {
+                        drawable = r.r.getDrawable(r.id);
+                    } catch (Resources.NotFoundException ex) {
+                        throw new FileNotFoundException("Resource does not exist: " + uri);
+                    }
+                } else {
+                    // Let the ContentResolver handle content and file URIs.
+                    InputStream stream = mProviderContext.getContentResolver().openInputStream(uri);
+                    if (stream == null) {
+                        throw new FileNotFoundException("Failed to open " + uri);
+                    }
                     try {
                         drawable = Drawable.createFromStream(stream, null);
                     } finally {
@@ -598,22 +612,25 @@
                         }
                     }
                 }
-                if (DBG) Log.d(LOG_TAG, "Opened icon input stream: " + drawableId);
             } catch (FileNotFoundException fnfe) {
-                if (DBG) Log.d(LOG_TAG, "Icon stream not found: " + drawableId);
+                Log.w(LOG_TAG, "Icon not found: " + drawableId + ", " + fnfe.getMessage());
                 // drawable = null;
             }
-
-            // If we got a drawable for this resource id, then stick it in the
-            // map so we don't do this lookup again.
-            if (drawable != null) {
-                mOutsideDrawablesCache.put(drawableId, drawable.getConstantState());
-            }
         } catch (Resources.NotFoundException nfe) {
-            if (DBG) Log.d(LOG_TAG, "Icon resource not found: " + drawableId);
+            Log.w(LOG_TAG, "Icon resource not found: " + drawableId);
             // drawable = null;
         }
 
+        if (drawable == null) {
+            if (DBG) Log.d(LOG_TAG, "Didn't find icon: " + drawableId);
+        } else {
+            if (DBG) {
+                Log.d(LOG_TAG, "Found icon: " + drawableId);
+            }
+            // Cache it so we don't do this lookup again
+            mOutsideDrawablesCache.put(drawableId, drawable.getConstantState());
+        }
+
         return drawable;
     }
 
diff --git a/core/java/android/bluetooth/BluetoothClass.java b/core/java/android/bluetooth/BluetoothClass.java
index 1fbbf78..6210380 100644
--- a/core/java/android/bluetooth/BluetoothClass.java
+++ b/core/java/android/bluetooth/BluetoothClass.java
@@ -72,12 +72,10 @@
         return Integer.toHexString(mClass);
     }
 
-    /** @hide */
     public int describeContents() {
         return 0;
     }
 
-    /** @hide */
     public static final Parcelable.Creator<BluetoothClass> CREATOR =
             new Parcelable.Creator<BluetoothClass>() {
         public BluetoothClass createFromParcel(Parcel in) {
@@ -88,7 +86,6 @@
         }
     };
 
-    /** @hide */
     public void writeToParcel(Parcel out, int flags) {
         out.writeInt(mClass);
     }
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index b1861ac..f81ba73 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -349,12 +349,10 @@
         return mAddress;
     }
 
-    /** @hide */
     public int describeContents() {
         return 0;
     }
 
-    /** @hide */
     public static final Parcelable.Creator<BluetoothDevice> CREATOR =
             new Parcelable.Creator<BluetoothDevice>() {
         public BluetoothDevice createFromParcel(Parcel in) {
@@ -365,7 +363,6 @@
         }
     };
 
-    /** @hide */
     public void writeToParcel(Parcel out, int flags) {
         out.writeString(mAddress);
     }
@@ -503,7 +500,7 @@
     }
 
     /** @hide */
-     public String[] getUuids() {
+     public ParcelUuid[] getUuids() {
         try {
             return sService.getRemoteUuids(mAddress);
         } catch (RemoteException e) {Log.e(TAG, "", e);}
@@ -511,7 +508,7 @@
     }
 
     /** @hide */
-    public int getServiceChannel(String uuid) {
+    public int getServiceChannel(ParcelUuid uuid) {
          try {
              return sService.getRemoteServiceChannel(mAddress, uuid);
          } catch (RemoteException e) {Log.e(TAG, "", e);}
diff --git a/core/java/android/bluetooth/BluetoothUuid.java b/core/java/android/bluetooth/BluetoothUuid.java
index c15bc20..409c744 100644
--- a/core/java/android/bluetooth/BluetoothUuid.java
+++ b/core/java/android/bluetooth/BluetoothUuid.java
@@ -16,10 +16,11 @@
 
 package android.bluetooth;
 
-import java.util.UUID;
+import java.util.Arrays;
+import java.util.HashSet;
 
 /**
-* Static helper methods and constants to decode the UUID of remote devices.
+* Static helper methods and constants to decode the ParcelUuid of remote devices.
 *  @hide
 */
 public final class BluetoothUuid {
@@ -30,40 +31,99 @@
      * The following 128 bit values are calculated as:
      *  uuid * 2^96 + BASE_UUID
      */
-    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 Handsfree  = UUID.fromString("0000111E-0000-1000-8000-00805F9B34FB");
-    public static final UUID AvrcpController =
-                                          UUID.fromString("0000110E-0000-1000-8000-00805F9B34FB");
-    public static final UUID AvrcpTarget = UUID.fromString("0000110C-0000-1000-8000-00805F9B34FB");
+    public static final ParcelUuid AudioSink =
+            ParcelUuid.fromString("0000110B-0000-1000-8000-00805F9B34FB");
+    public static final ParcelUuid AudioSource =
+            ParcelUuid.fromString("0000110A-0000-1000-8000-00805F9B34FB");
+    public static final ParcelUuid AdvAudioDist =
+            ParcelUuid.fromString("0000110D-0000-1000-8000-00805F9B34FB");
+    public static final ParcelUuid HSP =
+            ParcelUuid.fromString("00001108-0000-1000-8000-00805F9B34FB");
+    public static final ParcelUuid Handsfree =
+            ParcelUuid.fromString("0000111E-0000-1000-8000-00805F9B34FB");
+    public static final ParcelUuid AvrcpController =
+            ParcelUuid.fromString("0000110E-0000-1000-8000-00805F9B34FB");
+    public static final ParcelUuid AvrcpTarget =
+            ParcelUuid.fromString("0000110C-0000-1000-8000-00805F9B34FB");
+    public static final ParcelUuid ObexObjectPush =
+            ParcelUuid.fromString("00001105-0000-1000-8000-00805f9b34fb");
 
-    public static boolean isAudioSource(UUID uuid) {
+    public static boolean isAudioSource(ParcelUuid uuid) {
         return uuid.equals(AudioSource);
     }
 
-    public static boolean isAudioSink(UUID uuid) {
+    public static boolean isAudioSink(ParcelUuid uuid) {
         return uuid.equals(AudioSink);
     }
 
-    public static boolean isAdvAudioDist(UUID uuid) {
+    public static boolean isAdvAudioDist(ParcelUuid uuid) {
         return uuid.equals(AdvAudioDist);
     }
 
-    public static boolean isHandsfree(UUID uuid) {
+    public static boolean isHandsfree(ParcelUuid uuid) {
         return uuid.equals(Handsfree);
     }
 
-    public static boolean isHeadset(UUID uuid) {
+    public static boolean isHeadset(ParcelUuid uuid) {
         return uuid.equals(HSP);
     }
 
-    public static boolean isAvrcpController(UUID uuid) {
+    public static boolean isAvrcpController(ParcelUuid uuid) {
         return uuid.equals(AvrcpController);
     }
 
-    public static boolean isAvrcpTarget(UUID uuid) {
+    public static boolean isAvrcpTarget(ParcelUuid uuid) {
         return uuid.equals(AvrcpTarget);
     }
+
+    /**
+     * Returns true if ParcelUuid is present in uuidArray
+     *
+     * @param uuidArray - Array of ParcelUuids
+     * @param uuid
+     */
+    public static boolean isUuidPresent(ParcelUuid[] uuidArray, ParcelUuid uuid) {
+        for (ParcelUuid element: uuidArray) {
+            if (element.equals(uuid)) return true;
+        }
+        return false;
+    }
+
+    /**
+     * Returns true if there any common ParcelUuids in uuidA and uuidB.
+     *
+     * @param uuidA - List of ParcelUuids
+     * @param uuidB - List of ParcelUuids
+     *
+     */
+    public static boolean containsAnyUuid(ParcelUuid[] uuidA, ParcelUuid[] uuidB) {
+        if (uuidA == null && uuidB == null) return true;
+        if (uuidA == null || uuidB == null) return false;
+
+        HashSet<ParcelUuid> uuidSet = new HashSet<ParcelUuid> (Arrays.asList(uuidA));
+        for (ParcelUuid uuid: uuidB) {
+            if (uuidSet.contains(uuid)) return true;
+        }
+        return false;
+    }
+
+    /**
+     * Returns true if all the ParcelUuids in ParcelUuidB are present in
+     * ParcelUuidA
+     *
+     * @param uuidA - Array of ParcelUuidsA
+     * @param uuidB - Array of ParcelUuidsB
+     *
+     */
+    public static boolean containsAllUuids(ParcelUuid[] uuidA, ParcelUuid[] uuidB) {
+        if (uuidA == null && uuidB == null) return true;
+        if (uuidA == null || uuidB == null) return false;
+
+        HashSet<ParcelUuid> uuidSet = new HashSet<ParcelUuid> (Arrays.asList(uuidA));
+        for (ParcelUuid uuid: uuidB) {
+            if (!uuidSet.contains(uuid)) return false;
+        }
+        return true;
+    }
+
 }
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index a11ceac..04c8ec9 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -16,6 +16,8 @@
 
 package android.bluetooth;
 
+import android.bluetooth.ParcelUuid;
+
 /**
  * System private API for talking with the Bluetooth service.
  *
@@ -50,8 +52,8 @@
 
     String getRemoteName(in String address);
     int getRemoteClass(in String address);
-    String[] getRemoteUuids(in String address);
-    int getRemoteServiceChannel(in String address, String uuid);
+    ParcelUuid[] getRemoteUuids(in String address);
+    int getRemoteServiceChannel(in String address,in ParcelUuid uuid);
 
     boolean setPin(in String address, in byte[] pin);
     boolean setPasskey(in String address, int passkey);
diff --git a/core/java/android/bluetooth/ParcelUuid.aidl b/core/java/android/bluetooth/ParcelUuid.aidl
new file mode 100644
index 0000000..70bcc4b
--- /dev/null
+++ b/core/java/android/bluetooth/ParcelUuid.aidl
@@ -0,0 +1,19 @@
+/*
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.bluetooth;
+
+parcelable ParcelUuid;
diff --git a/core/java/android/bluetooth/ParcelUuid.java b/core/java/android/bluetooth/ParcelUuid.java
new file mode 100644
index 0000000..27166a0
--- /dev/null
+++ b/core/java/android/bluetooth/ParcelUuid.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.bluetooth;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.UUID;
+
+/**
+ * This class is a Parcelable wrapper around {@link UUID} which is an
+ * immutable representation of a 128-bit universally unique
+ * identifier.
+ */
+public final class ParcelUuid implements Parcelable {
+
+    private final UUID mUuid;
+
+    /**
+     * Constructor creates a ParcelUuid instance from the
+     * given {@link UUID}.
+     *
+     * @param uuid UUID
+     */
+    public ParcelUuid(UUID uuid) {
+        mUuid = uuid;
+    }
+
+    /**
+     * Creates a new ParcelUuid from a string representation of {@link UUID}.
+     *
+     * @param uuid
+     *            the UUID string to parse.
+     * @return an ParcelUuid instance.
+     * @throws NullPointerException
+     *             if {@code uuid} is {@code null}.
+     * @throws IllegalArgumentException
+     *             if {@code uuid} is not formatted correctly.
+     */
+    public static ParcelUuid fromString(String uuid) {
+        return new ParcelUuid(UUID.fromString(uuid));
+    }
+
+    /**
+     * Get the {@link UUID} represented by the ParcelUuid.
+     *
+     * @return UUID contained in the ParcelUuid.
+     */
+    public UUID getUuid() {
+        return mUuid;
+    }
+
+    /**
+     * Returns a string representation of the ParcelUuid
+     * For example: 0000110B-0000-1000-8000-00805F9B34FB will be the return value.
+     *
+     * @return a String instance.
+     */
+    @Override
+    public String toString() {
+        return mUuid.toString();
+    }
+
+
+   @Override
+   public int hashCode() {
+       return mUuid.hashCode();
+   }
+
+   /**
+    * Compares this ParcelUuid to another object for equality. If {@code object}
+    * is not {@code null}, is a ParcelUuid instance, and all bits are equal, then
+    * {@code true} is returned.
+    *
+    * @param object
+    *            the {@code Object} to compare to.
+    * @return {@code true} if this ParcelUuid is equal to {@code object}
+    *         or {@code false} if not.
+    */
+   @Override
+   public boolean equals(Object object) {
+       if (object == null) {
+           return false;
+       }
+
+       if (this == object) {
+           return true;
+       }
+
+       if (!(object instanceof ParcelUuid)) {
+           return false;
+       }
+
+       ParcelUuid that = (ParcelUuid) object;
+
+       return (this.mUuid.equals(that.mUuid));
+   }
+
+   public static final Parcelable.Creator<ParcelUuid> CREATOR =
+               new Parcelable.Creator<ParcelUuid>() {
+        public ParcelUuid createFromParcel(Parcel source) {
+            long mostSigBits = source.readLong();
+            long leastSigBits = source.readLong();
+            UUID uuid = new UUID(mostSigBits, leastSigBits);
+            return new ParcelUuid(uuid);
+        }
+
+        public ParcelUuid[] newArray(int size) {
+            return new ParcelUuid[size];
+        }
+    };
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeLong(mUuid.getMostSignificantBits());
+        dest.writeLong(mUuid.getLeastSignificantBits());
+    }
+}
diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java
index 238792b..60b406d 100644
--- a/core/java/android/content/ContentProviderOperation.java
+++ b/core/java/android/content/ContentProviderOperation.java
@@ -221,26 +221,30 @@
         } else if (mType == TYPE_UPDATE) {
             numRows = provider.update(mUri, values, mSelection, selectionArgs);
         } else if (mType == TYPE_ASSERT) {
-            // Build projection map from expected values
-            final ArrayList<String> projectionList = new ArrayList<String>();
-            for (Map.Entry<String, Object> entry : values.valueSet()) {
-                projectionList.add(entry.getKey());
-            }
-
             // Assert that all rows match expected values
-            final String[] projection = projectionList.toArray(new String[projectionList.size()]);
+            String[] projection =  null;
+            if (values != null) {
+                // Build projection map from expected values
+                final ArrayList<String> projectionList = new ArrayList<String>();
+                for (Map.Entry<String, Object> entry : values.valueSet()) {
+                    projectionList.add(entry.getKey());
+                }
+                projection = projectionList.toArray(new String[projectionList.size()]);
+            }
             final Cursor cursor = provider.query(mUri, projection, mSelection, selectionArgs, null);
-            numRows = cursor.getCount();
             try {
-                while (cursor.moveToNext()) {
-                    for (int i = 0; i < projection.length; i++) {
-                        final String cursorValue = cursor.getString(i);
-                        final String expectedValue = values.getAsString(projection[i]);
-                        if (!TextUtils.equals(cursorValue, expectedValue)) {
-                            // Throw exception when expected values don't match
-                            throw new OperationApplicationException("Found value " + cursorValue
-                                    + " when expected " + expectedValue + " for column "
-                                    + projection[i]);
+                numRows = cursor.getCount();
+                if (projection != null) {
+                    while (cursor.moveToNext()) {
+                        for (int i = 0; i < projection.length; i++) {
+                            final String cursorValue = cursor.getString(i);
+                            final String expectedValue = values.getAsString(projection[i]);
+                            if (!TextUtils.equals(cursorValue, expectedValue)) {
+                                // Throw exception when expected values don't match
+                                throw new OperationApplicationException("Found value " + cursorValue
+                                        + " when expected " + expectedValue + " for column "
+                                        + projection[i]);
+                            }
                         }
                     }
                 }
@@ -395,12 +399,19 @@
 
         /** Create a ContentProviderOperation from this {@link Builder}. */
         public ContentProviderOperation build() {
-            if (mType == TYPE_UPDATE || mType == TYPE_ASSERT) {
+            if (mType == TYPE_UPDATE) {
                 if ((mValues == null || mValues.size() == 0)
                         && (mValuesBackReferences == null || mValuesBackReferences.size() == 0)) {
                     throw new IllegalArgumentException("Empty values");
                 }
             }
+            if (mType == TYPE_ASSERT) {
+                if ((mValues == null || mValues.size() == 0)
+                        && (mValuesBackReferences == null || mValuesBackReferences.size() == 0)
+                        && (mExpectedCount == null)) {
+                    throw new IllegalArgumentException("Empty values");
+                }
+            }
             return new ContentProviderOperation(this);
         }
 
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 88a4d02f..307899a 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -527,12 +527,22 @@
         }
     }
 
-    class OpenResourceIdResult {
-        Resources r;
-        int id;
+    /**
+     * A resource identified by the {@link Resources} that contains it, and a resource id.
+     *
+     * @hide
+     */
+    public class OpenResourceIdResult {
+        public Resources r;
+        public int id;
     }
-    
-    OpenResourceIdResult getResourceId(Uri uri) throws FileNotFoundException {
+
+    /**
+     * Resolves an android.resource URI to a {@link Resources} and a resource id.
+     *
+     * @hide
+     */
+    public OpenResourceIdResult getResourceId(Uri uri) throws FileNotFoundException {
         String authority = uri.getAuthority();
         Resources r;
         if (TextUtils.isEmpty(authority)) {
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index c053ace..fc977c8 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -529,6 +529,8 @@
  *     <li> {@link #CATEGORY_HOME}
  *     <li> {@link #CATEGORY_PREFERENCE}
  *     <li> {@link #CATEGORY_TEST}
+ *     <li> {@link #CATEGORY_CAR_DOCK}
+ *     <li> {@link #CATEGORY_DESK_DOCK}
  * </ul>
  *
  * <h3>Standard Extra Data</h3>
@@ -1861,12 +1863,29 @@
      */
     public static final String CATEGORY_FRAMEWORK_INSTRUMENTATION_TEST =
             "android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST";
+    /**
+     * An activity to run when device is inserted into a car dock.
+    * Used with {@link #ACTION_MAIN} to launch an activity.
+     * To monitor dock state, use {@link #ACTION_DOCK_EVENT} instead.
+     */
+    @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+    public static final String CATEGORY_CAR_DOCK = "android.intent.category.CAR_DOCK";
+    /**
+     * An activity to run when device is inserted into a car dock.
+     * Used with {@link #ACTION_MAIN} to launch an activity.
+     * To monitor dock state, use {@link #ACTION_DOCK_EVENT} instead.
+     */
+    @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+    public static final String CATEGORY_DESK_DOCK = "android.intent.category.DESK_DOCK";
 
     /**
      * Broadcast Action:  The phone was docked or undocked.  Includes the extra
      * field {@link #EXTRA_DOCK_STATE}, containing the current dock state.
-     * @hide
+     * This is intended for monitoring the current dock state.
+     * To launch an activity from a dock state change, use {@link #CATEGORY_CAR_DOCK}
+     * or {@link #CATEGORY_DESK_DOCK} instead.
      */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_DOCK_EVENT = "android.intent.action.DOCK_EVENT";
 
     // ---------------------------------------------------------------------
@@ -2005,28 +2024,24 @@
      * {@link android.content.Intent#EXTRA_DOCK_STATE_UNDOCKED},
      * {@link android.content.Intent#EXTRA_DOCK_STATE_DESK}, or
      * {@link android.content.Intent#EXTRA_DOCK_STATE_CAR}.
-     * @hide
      */
     public static final String EXTRA_DOCK_STATE = "android.intent.extra.DOCK_STATE";
 
     /**
      * Used as an int value for {@link android.content.Intent#EXTRA_DOCK_STATE}
      * to represent that the phone is not in any dock.
-     * @hide
      */
     public static final int EXTRA_DOCK_STATE_UNDOCKED = 0;
 
     /**
      * Used as an int value for {@link android.content.Intent#EXTRA_DOCK_STATE}
      * to represent that the phone is in a desk dock.
-     * @hide
      */
     public static final int EXTRA_DOCK_STATE_DESK = 1;
 
     /**
      * Used as an int value for {@link android.content.Intent#EXTRA_DOCK_STATE}
      * to represent that the phone is in a car dock.
-     * @hide
      */
     public static final int EXTRA_DOCK_STATE_CAR = 2;
 
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index 1e590f0..7859d5a 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -583,13 +583,8 @@
             return;
         }
 
-        if (!getConnectivityManager().getBackgroundDataSetting()) {
-            if (isLoggable) {
-                Log.v(TAG, "not syncing because background data usage isn't allowed");
-            }
-            setStatusText("Sync is disabled.");
-            return;
-        }
+        final boolean backgroundDataUsageAllowed =
+                getConnectivityManager().getBackgroundDataSetting();
 
         if (mAccounts == null) setStatusText("The accounts aren't known yet.");
         if (!mDataConnectionIsConnected) setStatusText("No data connection");
@@ -686,7 +681,8 @@
                     } else {
                         final boolean syncAutomatically = masterSyncAutomatically
                                 && mSyncStorageEngine.getSyncAutomatically(account, authority);
-                        boolean syncAllowed = manualSync || syncAutomatically;
+                        boolean syncAllowed =
+                                manualSync || (backgroundDataUsageAllowed && syncAutomatically);
                         if (!syncAllowed) {
                             if (isLoggable) {
                                 Log.d(TAG, "scheduleSync: sync of " + account + ", " + authority
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 27783ef..1ad13c5 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -217,7 +217,9 @@
     public static final int CONFIG_KEYBOARD = 0x0010;
     /**
      * Bit in {@link #configChanges} that indicates that the activity
-     * can itself handle changes to the keyboard being hidden/exposed. 
+     * can itself handle changes to the keyboard or navigation being hidden/exposed.
+     * Note that inspite of the name, this applies to the changes to any
+     * hidden states: keyboard or navigation.
      * Set from the {@link android.R.attr#configChanges} attribute.
      */
     public static final int CONFIG_KEYBOARD_HIDDEN = 0x0020;
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index cbf8410..1fe34b5 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -138,6 +138,18 @@
      */
     public int navigation;
     
+    public static final int NAVIGATIONHIDDEN_UNDEFINED = 0;
+    public static final int NAVIGATIONHIDDEN_NO = 1;
+    public static final int NAVIGATIONHIDDEN_YES = 2;
+    
+    /**
+     * A flag indicating whether any 5-way or DPAD navigation available.
+     * This will be set on a device with a mechanism to hide the navigation
+     * controls from the user, when that mechanism is closed.  One of:
+     * {@link #NAVIGATIONHIDDEN_NO}, {@link #NAVIGATIONHIDDEN_YES}.
+     */
+    public int navigationHidden;
+    
     public static final int ORIENTATION_UNDEFINED = 0;
     public static final int ORIENTATION_PORTRAIT = 1;
     public static final int ORIENTATION_LANDSCAPE = 2;
@@ -174,6 +186,7 @@
         keyboardHidden = o.keyboardHidden;
         hardKeyboardHidden = o.hardKeyboardHidden;
         navigation = o.navigation;
+        navigationHidden = o.navigationHidden;
         orientation = o.orientation;
         screenLayout = o.screenLayout;
     }
@@ -198,6 +211,8 @@
         sb.append(hardKeyboardHidden);
         sb.append(" nav=");
         sb.append(navigation);
+        sb.append("/");
+        sb.append(navigationHidden);
         sb.append(" orien=");
         sb.append(orientation);
         sb.append(" layout=");
@@ -219,6 +234,7 @@
         keyboardHidden = KEYBOARDHIDDEN_UNDEFINED;
         hardKeyboardHidden = HARDKEYBOARDHIDDEN_UNDEFINED;
         navigation = NAVIGATION_UNDEFINED;
+        navigationHidden = NAVIGATIONHIDDEN_UNDEFINED;
         orientation = ORIENTATION_UNDEFINED;
         screenLayout = SCREENLAYOUT_SIZE_UNDEFINED;
     }
@@ -286,6 +302,11 @@
             changed |= ActivityInfo.CONFIG_NAVIGATION;
             navigation = delta.navigation;
         }
+        if (delta.navigationHidden != NAVIGATIONHIDDEN_UNDEFINED
+                && navigationHidden != delta.navigationHidden) {
+            changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
+            navigationHidden = delta.navigationHidden;
+        }
         if (delta.orientation != ORIENTATION_UNDEFINED
                 && orientation != delta.orientation) {
             changed |= ActivityInfo.CONFIG_ORIENTATION;
@@ -360,6 +381,10 @@
                 && navigation != delta.navigation) {
             changed |= ActivityInfo.CONFIG_NAVIGATION;
         }
+        if (delta.navigationHidden != NAVIGATIONHIDDEN_UNDEFINED
+                && navigationHidden != delta.navigationHidden) {
+            changed |= ActivityInfo.CONFIG_KEYBOARD_HIDDEN;
+        }
         if (delta.orientation != ORIENTATION_UNDEFINED
                 && orientation != delta.orientation) {
             changed |= ActivityInfo.CONFIG_ORIENTATION;
@@ -416,6 +441,7 @@
         dest.writeInt(keyboardHidden);
         dest.writeInt(hardKeyboardHidden);
         dest.writeInt(navigation);
+        dest.writeInt(navigationHidden);
         dest.writeInt(orientation);
         dest.writeInt(screenLayout);
     }
@@ -448,6 +474,7 @@
         keyboardHidden = source.readInt();
         hardKeyboardHidden = source.readInt();
         navigation = source.readInt();
+        navigationHidden = source.readInt();
         orientation = source.readInt();
         screenLayout = source.readInt();
     }
@@ -478,6 +505,8 @@
         if (n != 0) return n;
         n = this.navigation - that.navigation;
         if (n != 0) return n;
+        n = this.navigationHidden - that.navigationHidden;
+        if (n != 0) return n;
         n = this.orientation - that.orientation;
         if (n != 0) return n;
         n = this.screenLayout - that.screenLayout;
@@ -503,6 +532,7 @@
         return ((int)this.fontScale) + this.mcc + this.mnc
                 + this.locale.hashCode() + this.touchscreen
                 + this.keyboard + this.keyboardHidden + this.hardKeyboardHidden
-                + this.navigation + this.orientation + this.screenLayout;
+                + this.navigation + this.navigationHidden
+                + this.orientation + this.screenLayout;
     }
 }
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 0cd4036..e425f3a 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -22,10 +22,11 @@
 import android.database.SQLException;
 import android.os.Debug;
 import android.os.SystemClock;
+import android.os.SystemProperties;
 import android.text.TextUtils;
 import android.util.Config;
-import android.util.Log;
 import android.util.EventLog;
+import android.util.Log;
 
 import java.io.File;
 import java.util.HashMap;
@@ -221,6 +222,10 @@
     // that logging is not enabled.
     /* package */ final boolean mLogStats;
 
+    // System property that enables logging of slow queries. Specify the threshold in ms.
+    private static final String LOG_SLOW_QUERIES_PROPERTY = "db.log.slow_query_threshold";
+    private final int mSlowQueryThreshold;
+
     /**
      * @param closable
      */
@@ -1202,27 +1207,38 @@
             String editTable) {
         long timeStart = 0;
 
-        if (Config.LOGV) {
+        if (Config.LOGV || mSlowQueryThreshold != -1) {
             timeStart = System.currentTimeMillis();
         }
 
         SQLiteCursorDriver driver = new SQLiteDirectCursorDriver(this, sql, editTable);
 
+        Cursor cursor = null;
         try {
-            return driver.query(
+            cursor = driver.query(
                     cursorFactory != null ? cursorFactory : mFactory,
                     selectionArgs);
         } finally {
-            if (Config.LOGV) {
+            if (Config.LOGV || mSlowQueryThreshold != -1) {
+
+                // Force query execution
+                if (cursor != null) {
+                    cursor.moveToFirst();
+                    cursor.moveToPosition(-1);
+                }
+
                 long duration = System.currentTimeMillis() - timeStart;
 
-                Log.v(SQLiteCursor.TAG,
-                      "query (" + duration + " ms): " + driver.toString() + ", args are "
-                              + (selectionArgs != null
-                              ? TextUtils.join(",", selectionArgs)
-                              : "<null>"));
+                if (Config.LOGV || duration >= mSlowQueryThreshold) {
+                    Log.v(SQLiteCursor.TAG,
+                          "query (" + duration + " ms): " + driver.toString() + ", args are "
+                                  + (selectionArgs != null
+                                  ? TextUtils.join(",", selectionArgs)
+                                  : "<null>"));
+                }
             }
         }
+        return cursor;
     }
 
     /**
@@ -1671,6 +1687,7 @@
         mFlags = flags;
         mPath = path;
         mLogStats = "1".equals(android.os.SystemProperties.get("db.logstats"));
+        mSlowQueryThreshold = SystemProperties.getInt(LOG_SLOW_QUERIES_PROPERTY, -1);
 
         mLeakedException = new IllegalStateException(path +
             " SQLiteDatabase created and never closed");
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 9991600..13effe0 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -38,12 +38,12 @@
  * <p>There is no default constructor for this class. Use {@link #open()} to
  * get a Camera object.</p>
  *
- * <p>In order to use the device camera, you must declare the 
- * {@link android.Manifest.permission#CAMERA} permission in your Android 
+ * <p>In order to use the device camera, you must declare the
+ * {@link android.Manifest.permission#CAMERA} permission in your Android
  * Manifest. Also be sure to include the
  * <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">&lt;uses-feature></a>
- * manifest element in order to declare camera features used by your application. 
- * For example, if you use the camera and auto-focus feature, your Manifest 
+ * manifest element in order to declare camera features used by your application.
+ * For example, if you use the camera and auto-focus feature, your Manifest
  * should include the following:</p>
  * <pre> &lt;uses-permission android:name="android.permission.CAMERA" />
  * &lt;uses-feature android:name="android.hardware.camera" />
@@ -52,7 +52,7 @@
  * <p class="caution"><strong>Caution:</strong> Different Android-powered devices
  * may have different hardware specifications, such as megapixel ratings and
  * auto-focus capabilities. In order for your application to be compatible with
- * more devices, you should not make assumptions about the device camera 
+ * more devices, you should not make assumptions about the device camera
  * specifications.</p>
  */
 public class Camera {
@@ -197,7 +197,7 @@
          * The callback that delivers the preview frames.
          *
          * @param data The contents of the preview frame in the format defined
-         *  by {@link android.graphics.PixelFormat}, which can be queried 
+         *  by {@link android.graphics.PixelFormat}, which can be queried
          *  with {@link android.hardware.Camera.Parameters#getPreviewFormat()}.
          *  If {@link android.hardware.Camera.Parameters#setPreviewFormat(int)}
          *             is never called, the default will be the YCbCr_420_SP
@@ -340,11 +340,11 @@
 
     /**
      * Handles the callback for the camera auto focus.
-     * <p>Devices that do not support auto-focus will receive a "fake" 
-     * callback to this interface. If your application needs auto-focus and 
+     * <p>Devices that do not support auto-focus will receive a "fake"
+     * callback to this interface. If your application needs auto-focus and
      * should not be installed on devices <em>without</em> auto-focus, you must
      * declare that your app uses the
-     * {@code android.hardware.camera.autofocus} feature, in the 
+     * {@code android.hardware.camera.autofocus} feature, in the
      * <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">&lt;uses-feature></a>
      * manifest element.</p>
      */
@@ -368,11 +368,11 @@
      * AutoFocusCallback#onAutoFocus(boolean, Camera)} callback will be called
      * immediately.
      * <p>If your application should not be installed
-     * on devices without auto-focus, you must declare that your application 
-     * uses auto-focus with the 
+     * on devices without auto-focus, you must declare that your application
+     * uses auto-focus with the
      * <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">&lt;uses-feature></a>
      * manifest element.</p>
-     * 
+     *
      * @param cb the callback to run
      */
     public final void autoFocus(AutoFocusCallback cb)
@@ -387,7 +387,6 @@
      * this function will cancel it. Whether the auto-focus is in progress
      * or not, this function will return the focus position to the default.
      * If the camera does not support auto-focus, this is a no-op.
-     * @hide
      */
     public final void cancelAutoFocus()
     {
@@ -917,11 +916,11 @@
         }
 
         /**
-         * Sets the image format for preview pictures. 
+         * Sets the image format for preview pictures.
          * <p>If this is never called, the default format will be
          * {@link android.graphics.PixelFormat#YCbCr_420_SP}, which
          * uses the NV21 encoding format.</p>
-         * 
+         *
          * @param pixel_format the desired preview picture format, defined
          *   by one of the {@link android.graphics.PixelFormat} constants.
          *   (E.g., <var>PixelFormat.YCbCr_420_SP</var> (default),
@@ -942,8 +941,8 @@
         /**
          * Returns the image format for preview pictures got from
          * {@link PreviewCallback}.
-         * 
-         * @return the {@link android.graphics.PixelFormat} int representing 
+         *
+         * @return the {@link android.graphics.PixelFormat} int representing
          *         the preview picture format.
          */
         public int getPreviewFormat() {
diff --git a/core/java/android/pim/vcard/ContactStruct.java b/core/java/android/pim/vcard/ContactStruct.java
index 0064bf2..06b0636 100644
--- a/core/java/android/pim/vcard/ContactStruct.java
+++ b/core/java/android/pim/vcard/ContactStruct.java
@@ -15,6 +15,7 @@
  */
 package android.pim.vcard;
 
+import android.accounts.Account;
 import android.content.ContentProviderOperation;
 import android.content.ContentResolver;
 import android.content.ContentValues;
@@ -416,7 +417,8 @@
     private List<String> mWebsiteList;
     
     private final int mVCardType;
-    
+    private final Account mAccount;
+
     // Each Column of four properties has ISPRIMARY field
     // (See android.provider.Contacts)
     // If false even after the parsing loop, we choose the first entry as a "primary"
@@ -429,9 +431,14 @@
     public ContactStruct() {
         this(VCardConfig.VCARD_TYPE_V21_GENERIC);
     }
-    
+
     public ContactStruct(int vcardType) {
+        this(vcardType, null);
+    }
+
+    public ContactStruct(int vcardType, Account account) {
         mVCardType = vcardType;
+        mAccount = account;
     }
 
     /**
@@ -1021,7 +1028,12 @@
             new ArrayList<ContentProviderOperation>();  
         ContentProviderOperation.Builder builder =
             ContentProviderOperation.newInsert(RawContacts.CONTENT_URI);
-        builder.withValues(new ContentValues());
+        if (mAccount != null) {
+            builder.withValue(RawContacts.ACCOUNT_NAME, mAccount.name);
+            builder.withValue(RawContacts.ACCOUNT_TYPE, mAccount.type);
+        } else {
+            builder.withValues(new ContentValues());
+        }
         operationList.add(builder.build());
 
         {
@@ -1183,7 +1195,7 @@
             builder.withValue(Miscellaneous.BIRTHDAY, mBirthday);
             operationList.add(builder.build());
         }
-        
+
         try {
             resolver.applyBatch(ContactsContract.AUTHORITY, operationList);
         } catch (RemoteException e) {
diff --git a/core/java/android/pim/vcard/VCardDataBuilder.java b/core/java/android/pim/vcard/VCardDataBuilder.java
index fd165e9..d2026d0 100644
--- a/core/java/android/pim/vcard/VCardDataBuilder.java
+++ b/core/java/android/pim/vcard/VCardDataBuilder.java
@@ -15,6 +15,7 @@
  */
 package android.pim.vcard;
 
+import android.accounts.Account;
 import android.util.CharsetUtils;
 import android.util.Log;
 
@@ -59,7 +60,8 @@
     private String mTargetCharset;
     private boolean mStrictLineBreakParsing;
     
-    private int mVCardType;
+    final private int mVCardType;
+    final private Account mAccount;
     
     // Just for testing.
     private long mTimePushIntoContentResolver;
@@ -67,21 +69,22 @@
     private List<EntryHandler> mEntryHandlers = new ArrayList<EntryHandler>();
     
     public VCardDataBuilder() {
-        this(null, null, false, VCardConfig.VCARD_TYPE_V21_GENERIC);
+        this(null, null, false, VCardConfig.VCARD_TYPE_V21_GENERIC, null);
     }
 
     /**
      * @hide 
      */
     public VCardDataBuilder(int vcardType) {
-        this(null, null, false, vcardType);
+        this(null, null, false, vcardType, null);
     }
 
     /**
      * @hide 
      */
-    public VCardDataBuilder(String charset, boolean strictLineBreakParsing, int vcardType) {
-        this(null, charset, strictLineBreakParsing, vcardType);
+    public VCardDataBuilder(String charset,
+            boolean strictLineBreakParsing, int vcardType, Account account) {
+        this(null, charset, strictLineBreakParsing, vcardType, account);
     }
     
     /**
@@ -90,7 +93,8 @@
     public VCardDataBuilder(String sourceCharset,
             String targetCharset,
             boolean strictLineBreakParsing,
-            int vcardType) {
+            int vcardType,
+            Account account) {
         if (sourceCharset != null) {
             mSourceCharset = sourceCharset;
         } else {
@@ -103,6 +107,7 @@
         }
         mStrictLineBreakParsing = strictLineBreakParsing;
         mVCardType = vcardType;
+        mAccount = account;
     }
     
     public void addEntryHandler(EntryHandler entryHandler) {
@@ -136,7 +141,7 @@
             Log.e(LOG_TAG, "This is not VCARD!");
         }
 
-        mCurrentContactStruct = new ContactStruct(mVCardType);
+        mCurrentContactStruct = new ContactStruct(mVCardType, mAccount);
     }
 
     public void endRecord() {
diff --git a/core/java/android/preference/DialogPreference.java b/core/java/android/preference/DialogPreference.java
index 666efae..cc48aeb 100644
--- a/core/java/android/preference/DialogPreference.java
+++ b/core/java/android/preference/DialogPreference.java
@@ -31,6 +31,9 @@
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.view.inputmethod.InputMethodManager;
 import android.widget.TextView;
 
 /**
@@ -297,10 +300,32 @@
         if (state != null) {
             dialog.onRestoreInstanceState(state);
         }
+        if (needInputMethod()) {
+            requestInputMethod(dialog);
+        }
         dialog.setOnDismissListener(this);
         dialog.show();
     }
-    
+
+    /**
+     * Returns whether the preference needs to display a soft input method when the dialog
+     * is displayed. Default is false. Subclasses should override this method if they need
+     * the soft input method brought up automatically.
+     * @hide
+     */
+    protected boolean needInputMethod() {
+        return false;
+    }
+
+    /**
+     * Sets the required flags on the dialog window to enable input method window to show up.
+     */
+    private void requestInputMethod(Dialog dialog) {
+        Window window = dialog.getWindow();
+        window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE |
+                WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
+    }
+
     /**
      * Creates the content view for the dialog (if a custom content view is
      * required). By default, it inflates the dialog layout resource if it is
diff --git a/core/java/android/preference/EditTextPreference.java b/core/java/android/preference/EditTextPreference.java
index a12704f..84ee950 100644
--- a/core/java/android/preference/EditTextPreference.java
+++ b/core/java/android/preference/EditTextPreference.java
@@ -169,6 +169,13 @@
         return mEditText;
     }
 
+    /** @hide */
+    @Override
+    protected boolean needInputMethod() {
+        // We want the input method to show, if possible, when dialog is displayed
+        return true;
+    }
+
     @Override
     protected Parcelable onSaveInstanceState() {
         final Parcelable superState = super.onSaveInstanceState();
diff --git a/core/java/android/provider/Calendar.java b/core/java/android/provider/Calendar.java
index d57155c..1de971b 100644
--- a/core/java/android/provider/Calendar.java
+++ b/core/java/android/provider/Calendar.java
@@ -506,6 +506,13 @@
          * <P>Type: INTEGER (boolean, readonly)</P>
          */
         public static final String CAN_INVITE_OTHERS = "canInviteOthers";
+
+        /**
+         * The owner account for this calendar, based on the calendar (foreign
+         * key into the calendars table).
+         * <P>Type: String</P>
+         */
+        public static final String OWNER_ACCOUNT = "ownerAccount";
     }
 
     /**
diff --git a/core/java/android/provider/Contacts.java b/core/java/android/provider/Contacts.java
index 181a529..d87018d 100644
--- a/core/java/android/provider/Contacts.java
+++ b/core/java/android/provider/Contacts.java
@@ -533,7 +533,7 @@
             Uri photoUri = Uri.withAppendedPath(person, Contacts.Photos.CONTENT_DIRECTORY);
             Cursor cursor = cr.query(photoUri, new String[]{Photos.DATA}, null, null, null);
             try {
-                if (!cursor.moveToNext()) {
+                if (cursor == null || !cursor.moveToNext()) {
                     return null;
                 }
                 byte[] data = cursor.getBlob(0);
@@ -542,7 +542,7 @@
                 }
                 return new ByteArrayInputStream(data);
             } finally {
-                cursor.close();
+                if (cursor != null) cursor.close();
             }
         }
 
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index b0ac7f4..6eaf9dd 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -1039,6 +1039,7 @@
             public static final int TYPE_WORK_MOBILE = 17;
             public static final int TYPE_WORK_PAGER = 18;
             public static final int TYPE_ASSISTANT = 19;
+            public static final int TYPE_MMS = 20;
 
             /**
              * The phone number as the user entered it.
@@ -1529,7 +1530,7 @@
          * called on a raw contact, it is marked for deletion and removed from its
          * aggregate contact. The sync adaptor deletes the raw contact on the server and
          * then calls ContactResolver.delete once more, this time setting the the
-         * {@link ContactsContract#CALLER_IS_SYNCADAPTER} query parameter to finalize 
+         * {@link ContactsContract#CALLER_IS_SYNCADAPTER} query parameter to finalize
          * the data removal.
          * <P>Type: INTEGER</P>
          */
@@ -1686,6 +1687,13 @@
         public static final String UNGROUPED_VISIBLE = "ungrouped_visible";
 
         /**
+         * Read-only flag indicating if this {@link #SHOULD_SYNC} or any
+         * {@link Groups#SHOULD_SYNC} under this account have been marked as
+         * unsynced.
+         */
+        public static final String ANY_UNSYNCED = "any_unsynced";
+
+        /**
          * Read-only count of {@link Contacts} from a specific source that have
          * no {@link CommonDataKinds.GroupMembership} entries.
          * <p>
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 0bbd1fc..6d03095 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2758,11 +2758,19 @@
 
         /**
          * Controls whether Gmail will discard uphill operations that repeatedly fail. Value must be
-         * an integer where non-zero means true. Defaults to 1.
+         * an integer where non-zero means true. Defaults to 1. This flag controls Donut devices.
          */
         public static final String GMAIL_DISCARD_ERROR_UPHILL_OP = "gmail_discard_error_uphill_op";
 
         /**
+         * Controls whether Gmail will discard uphill operations that repeatedly fail. Value must be
+         * an integer where non-zero means true. Defaults to 1. This flag controls Eclair and
+         * future devices.
+         */
+        public static final String GMAIL_DISCARD_ERROR_UPHILL_OP_NEW =
+            "gmail_discard_error_uphill_op_new";
+
+        /**
          * Controls how many attempts Gmail will try to upload an uphill operations before it
          * abandons the operation. Defaults to 20.
          */
diff --git a/core/java/android/server/BluetoothA2dpService.java b/core/java/android/server/BluetoothA2dpService.java
index 9c687e2..be8c777 100644
--- a/core/java/android/server/BluetoothA2dpService.java
+++ b/core/java/android/server/BluetoothA2dpService.java
@@ -27,6 +27,7 @@
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothUuid;
 import android.bluetooth.IBluetoothA2dp;
+import android.bluetooth.ParcelUuid;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -42,7 +43,6 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Set;
-import java.util.UUID;
 
 public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
     private static final String TAG = "BluetoothA2dpService";
@@ -188,15 +188,9 @@
     }
 
     private boolean isSinkDevice(BluetoothDevice device) {
-        String uuids[] = mBluetoothService.getRemoteUuids(device.getAddress());
-        UUID uuid;
-        if (uuids != null) {
-            for (String deviceUuid: uuids) {
-                uuid = UUID.fromString(deviceUuid);
-                if (BluetoothUuid.isAudioSink(uuid)) {
-                    return true;
-                }
-            }
+        ParcelUuid[] uuids = mBluetoothService.getRemoteUuids(device.getAddress());
+        if (uuids != null && BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.AudioSink)) {
+            return true;
         }
         return false;
     }
@@ -229,18 +223,14 @@
             for (String path: paths) {
                 String address = mBluetoothService.getAddressFromObjectPath(path);
                 BluetoothDevice device = mAdapter.getRemoteDevice(address);
-                String []uuids = mBluetoothService.getRemoteUuids(address);
-                if (uuids != null)
-                    for (String uuid: uuids) {
-                        UUID remoteUuid = UUID.fromString(uuid);
-                        if (BluetoothUuid.isAudioSink(remoteUuid) ||
-                            BluetoothUuid.isAudioSource(remoteUuid) ||
-                            BluetoothUuid.isAdvAudioDist(remoteUuid)) {
-                            addAudioSink(device);
-                            break;
-                        }
+                ParcelUuid[] remoteUuids = mBluetoothService.getRemoteUuids(address);
+                if (remoteUuids != null)
+                    if (BluetoothUuid.containsAnyUuid(remoteUuids,
+                            new ParcelUuid[] {BluetoothUuid.AudioSink,
+                                                BluetoothUuid.AdvAudioDist})) {
+                        addAudioSink(device);
                     }
-            }
+                }
         }
         mAudioManager.setParameters(BLUETOOTH_ENABLED+"=true");
     }
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index 1ed5c49..ba53307 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -21,6 +21,7 @@
 import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothUuid;
+import android.bluetooth.ParcelUuid;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Handler;
@@ -28,7 +29,6 @@
 import android.util.Log;
 
 import java.util.HashMap;
-import java.util.UUID;
 
 /**
  * TODO: Move this to
@@ -501,7 +501,7 @@
         }
 
         boolean authorized = false;
-        UUID uuid = UUID.fromString(deviceUuid);
+        ParcelUuid uuid = ParcelUuid.fromString(deviceUuid);
         // Bluez sends the UUID of the local service being accessed, _not_ the
         // remote service
         if (mBluetoothService.isEnabled() &&
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index de0cad7..c0e4f34 100644
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -24,11 +24,12 @@
 
 package android.server;
 
-import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.IBluetooth;
+import android.bluetooth.ParcelUuid;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -51,7 +52,6 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.Map;
 
 public class BluetoothService extends IBluetooth.Stub {
@@ -967,22 +967,26 @@
 
 
     /**
-     * Gets the remote features encoded as bit mask.
+     * Gets the UUIDs supported by the remote device
      *
-     * Note: This method may be obsoleted soon.
-     *
-     * @return String array of 128bit UUIDs
+     * @return array of 128bit ParcelUuids
      */
-    public synchronized String[] getRemoteUuids(String address) {
+    public synchronized ParcelUuid[] getRemoteUuids(String address) {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
             return null;
         }
         String value = getRemoteDeviceProperty(address, "UUIDs");
-        String[] uuids = null;
+        if (value == null) return null;
+
+        String[] uuidStrings = null;
         // The UUIDs are stored as a "," separated string.
-        if (value != null)
-             uuids = value.split(",");
+        uuidStrings = value.split(",");
+        ParcelUuid[] uuids = new ParcelUuid[uuidStrings.length];
+
+        for (int i = 0; i < uuidStrings.length; i++) {
+            uuids[i] = ParcelUuid.fromString(uuidStrings[i]);
+        }
         return uuids;
     }
 
@@ -990,16 +994,17 @@
      * Gets the rfcomm channel associated with the UUID.
      *
      * @param address Address of the remote device
-     * @param uuid UUID of the service attribute
+     * @param uuid ParcelUuid of the service attribute
      *
      * @return rfcomm channel associated with the service attribute
      */
-    public int getRemoteServiceChannel(String address, String uuid) {
+    public int getRemoteServiceChannel(String address, ParcelUuid uuid) {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
             return BluetoothDevice.ERROR;
         }
-        return getDeviceServiceChannelNative(getObjectPathFromAddress(address), uuid, 0x0004);
+        return getDeviceServiceChannelNative(getObjectPathFromAddress(address), uuid.toString(),
+                0x0004);
     }
 
     public synchronized boolean setPin(String address, byte[] pin) {
@@ -1148,11 +1153,11 @@
                        mBondState.getAttempt(address),
                        getRemoteName(address));
             if (bondState == BluetoothDevice.BOND_BONDED) {
-                String[] uuids = getRemoteUuids(address);
+                ParcelUuid[] uuids = getRemoteUuids(address);
                 if (uuids == null) {
                     pw.printf("\tuuids = null\n");
                 } else {
-                    for (String uuid : uuids) {
+                    for (ParcelUuid uuid : uuids) {
                         pw.printf("\t" + uuid + "\n");
                     }
                 }
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index cd5cf10..da8d62c0 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -321,7 +321,7 @@
          * Called as the user performs touch-screen interaction with the
          * window that is currently showing this wallpaper.  Note that the
          * events you receive here are driven by the actual application the
-         * user is interacting with, so if it is slow you will get viewer
+         * user is interacting with, so if it is slow you will get fewer
          * move events.
          */
         public void onTouchEvent(MotionEvent event) {
diff --git a/core/java/android/service/wallpaper/WallpaperSettingsActivity.java b/core/java/android/service/wallpaper/WallpaperSettingsActivity.java
new file mode 100644
index 0000000..501947da
--- /dev/null
+++ b/core/java/android/service/wallpaper/WallpaperSettingsActivity.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2009 Google Inc.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.service.wallpaper;
+
+import android.content.res.Resources;
+import android.os.Bundle;
+import android.preference.PreferenceActivity;
+
+/**
+ * Base class for activities that will be used to configure the settings of
+ * a wallpaper.  You should derive from this class to allow it to select the
+ * proper theme of the activity depending on how it is being used.
+ */
+public class WallpaperSettingsActivity extends PreferenceActivity {
+    /**
+     * This boolean extra in the launch intent indicates that the settings
+     * are being used while the wallpaper is in preview mode.
+     */
+    final public static String EXTRA_PREVIEW_MODE
+            = "android.service.wallpaper.PREVIEW_MODE";
+    
+    @Override
+    protected void onCreate(Bundle icicle) {
+        if (false) {
+            Resources.Theme theme = getTheme();
+            if (getIntent().getBooleanExtra(EXTRA_PREVIEW_MODE, false)) {
+                theme.applyStyle(com.android.internal.R.style.PreviewWallpaperSettings, true);
+            } else {
+                theme.applyStyle(com.android.internal.R.style.ActiveWallpaperSettings, true);
+            }
+        }
+        super.onCreate(icicle);
+    }
+}
diff --git a/core/java/android/speech/IRecognitionListener.aidl b/core/java/android/speech/IRecognitionListener.aidl
new file mode 100644
index 0000000..2da2258
--- /dev/null
+++ b/core/java/android/speech/IRecognitionListener.aidl
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.speech;
+
+import android.os.Bundle;
+import android.speech.RecognitionResult;
+
+/**
+ * Listener for speech recognition events, used with RecognitionService.
+ *  This gives you both the final recognition results, as well as various
+ *  intermediate events that can be used to show visual feedback to the user.
+ *  {@hide}
+ */
+interface IRecognitionListener {
+    /** Called when the endpointer is ready for the user to start speaking. */
+    void onReadyForSpeech(in Bundle noiseParams);
+
+    /** The user has started to speak. */
+    void onBeginningOfSpeech();
+
+    /** The sound level in the audio stream has changed. */
+    void onRmsChanged(in float rmsdB);
+
+    /**
+     * More sound has been received. Buffer is a byte buffer containing
+     * a sequence of 16-bit shorts. 
+     */
+    void onBufferReceived(in byte[] buffer);
+
+    /** Called after the user stops speaking. */
+    void onEndOfSpeech();
+
+    /**
+     * A network or recognition error occurred. The code is defined in
+     * {@link android.speech.RecognitionResult}
+     */
+    void onError(in int error);
+
+    /** 
+     * Called when recognition results are ready.
+     * @param results: an ordered list of the most likely results (N-best list).
+     * @param key: a key associated with the results. The same results can
+     * be retrieved asynchronously later using the key, if available. 
+     */
+    void onResults(in List<RecognitionResult> results, long key);
+}
diff --git a/core/java/android/speech/IRecognitionService.aidl b/core/java/android/speech/IRecognitionService.aidl
new file mode 100644
index 0000000..a18c380
--- /dev/null
+++ b/core/java/android/speech/IRecognitionService.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.speech;
+
+import android.content.Intent;
+import android.speech.IRecognitionListener;
+import android.speech.RecognitionResult;
+
+// A Service interface to speech recognition. Call startListening when
+// you want to begin capturing audio; RecognitionService will automatically
+// determine when the user has finished speaking, stream the audio to the
+// recognition servers, and notify you when results are ready.
+/** {@hide} */
+interface IRecognitionService {
+    // Start listening for speech. Can only call this from one thread at once.
+    // see RecognizerIntent.java for constants used to specify the intent.
+    void startListening(in Intent recognizerIntent,
+        in IRecognitionListener listener);
+        
+    List<RecognitionResult> getRecognitionResults(in long key);
+
+    void cancel();
+}
diff --git a/core/java/android/speech/RecognitionResult.aidl b/core/java/android/speech/RecognitionResult.aidl
new file mode 100644
index 0000000..59e53ab
--- /dev/null
+++ b/core/java/android/speech/RecognitionResult.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.speech;
+
+parcelable RecognitionResult;
diff --git a/core/java/android/speech/RecognitionResult.java b/core/java/android/speech/RecognitionResult.java
new file mode 100644
index 0000000..95715ee
--- /dev/null
+++ b/core/java/android/speech/RecognitionResult.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.speech;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * RecognitionResult is a passive object that stores a single recognized query
+ * and its search result.
+ * 
+ * TODO: Revisit and improve this class, reconciling the different types of actions and
+ * the different ways they are represented. Maybe we should have a separate result object
+ * for each type, and put them (type/value) in bundle?
+ * {@hide}
+ */
+public class RecognitionResult implements Parcelable {
+    /**
+     * Status of the recognize request.
+     */
+    public static final int NETWORK_TIMEOUT = 1; // Network operation timed out.
+
+    public static final int NETWORK_ERROR = 2; // Other network related errors.
+
+    public static final int AUDIO_ERROR = 3; // Audio recording error.
+
+    public static final int SERVER_ERROR = 4; // Server sends error status.
+
+    public static final int CLIENT_ERROR = 5; // Other client side errors.
+
+    public static final int SPEECH_TIMEOUT = 6; // No speech input
+
+    public static final int NO_MATCH = 7; // No recognition result matched.
+
+    public static final int SERVICE_BUSY = 8; // RecognitionService busy.
+
+    /**
+     * Type of the recognition results.
+     */
+    public static final int RAW_RECOGNITION_RESULT = 0;
+
+    public static final int WEB_SEARCH_RESULT = 1;
+
+    public static final int CONTACT_RESULT = 2;
+    
+    public static final int ACTION_RESULT = 3;
+
+    /**
+     * A factory method to create a raw RecognitionResult
+     * 
+     * @param sentence the recognized text.
+     */
+    public static RecognitionResult newRawRecognitionResult(String sentence) {
+        return new RecognitionResult(RAW_RECOGNITION_RESULT, sentence, null, null);
+    }
+
+    /**
+     * A factory method to create a RecognitionResult for contacts.
+     * 
+     * @param contact the contact name.
+     * @param phoneType the phone type.
+     * @param callAction whether this result included a command to "call", or
+     *            just the contact name.
+     */
+    public static RecognitionResult newContactResult(String contact, int phoneType,
+            boolean callAction) {
+        return new RecognitionResult(CONTACT_RESULT, contact, phoneType, callAction);
+    }
+
+    /**
+     * A factory method to create a RecognitionResult for a web search query.
+     * 
+     * @param query the query string.
+     * @param html the html page of the search result.
+     * @param url the url that performs the search with the query.
+     */
+    public static RecognitionResult newWebResult(String query, String html, String url) {
+        return new RecognitionResult(WEB_SEARCH_RESULT, query, html, url);
+    }
+    
+    /**
+     * A factory method to create a RecognitionResult for an action.
+     * 
+     * @param action the action type
+     * @param query the query string associated with that action.
+     */
+    public static RecognitionResult newActionResult(int action, String query) {
+        return new RecognitionResult(ACTION_RESULT, action, query);
+    }
+
+    public static final Parcelable.Creator<RecognitionResult> CREATOR =
+            new Parcelable.Creator<RecognitionResult>() {
+
+                public RecognitionResult createFromParcel(Parcel in) {
+                    return new RecognitionResult(in);
+                }
+        
+                public RecognitionResult[] newArray(int size) {
+                    return new RecognitionResult[size];
+                }
+            };
+
+    /**
+     * Result type.
+     */
+    public final int mResultType;
+
+    /**
+     * The recognized string when mResultType is WEB_SEARCH_RESULT. The name of
+     * the contact when mResultType is CONTACT_RESULT. The relevant query when
+     * mResultType is ACTION_RESULT.
+     */
+    public final String mText;
+
+    /**
+     * The HTML result page for the query. If this is null, then the application
+     * must use the url field to get the HTML result page.
+     */
+    public final String mHtml;
+
+    /**
+     * The url to get the result page for the query string. The application must
+     * use this url instead of performing the search with the query.
+     */
+    public final String mUrl;
+
+    /**
+     * Phone number type. This is valid only when mResultType == CONTACT_RESULT.
+     */
+    public final int mPhoneType;
+    
+    /**
+     * Action type.  This is valid only when mResultType == ACTION_RESULT.
+     */
+    public final int mAction;
+
+    /**
+     * Whether a contact recognition result included a command to "call". This
+     * is valid only when mResultType == CONTACT_RESULT.
+     */
+    public final boolean mCallAction;
+
+    private RecognitionResult(int type, int action, String query) {
+        mResultType = type;
+        mAction = action;
+        mText = query;
+        mHtml = null;
+        mUrl = null;
+        mPhoneType = -1;
+        mCallAction = false;
+    }
+    
+    private RecognitionResult(int type, String query, String html, String url) {
+        mResultType = type;
+        mText = query;
+        mHtml = html;
+        mUrl = url;
+        mPhoneType = -1;
+        mAction = -1;
+        mCallAction = false;
+    }
+
+    private RecognitionResult(int type, String query, int phoneType, boolean callAction) {
+        mResultType = type;
+        mText = query;
+        mPhoneType = phoneType;
+        mHtml = null;
+        mUrl = null;
+        mAction = -1;
+        mCallAction = callAction;
+    }
+
+    private RecognitionResult(Parcel in) {
+        mResultType = in.readInt();
+        mText = in.readString();
+        mHtml = in.readString();
+        mUrl = in.readString();
+        mPhoneType = in.readInt();
+        mAction = in.readInt();
+        mCallAction = (in.readInt() == 1);
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(mResultType);
+        out.writeString(mText);
+        out.writeString(mHtml);
+        out.writeString(mUrl);
+        out.writeInt(mPhoneType);
+        out.writeInt(mAction);
+        out.writeInt(mCallAction ? 1 : 0);
+    }
+
+    @Override
+    public String toString() {
+        String resultType[] = {
+                "RAW", "WEB", "CONTACT", "ACTION"
+        };
+        return "[type=" + resultType[mResultType] + ", text=" + mText + ", mUrl=" + mUrl
+                + ", html=" + mHtml + ", mAction=" + mAction + ", mCallAction=" + mCallAction + "]";
+    }
+
+    public int describeContents() {
+        // no special description
+        return 0;
+    }
+}
diff --git a/core/java/android/speech/RecognitionServiceUtil.java b/core/java/android/speech/RecognitionServiceUtil.java
new file mode 100644
index 0000000..4207543
--- /dev/null
+++ b/core/java/android/speech/RecognitionServiceUtil.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.speech;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.speech.RecognitionResult;
+import android.util.Log;
+
+import java.util.List;
+
+/**
+ * Utils for Google's network-based speech recognizer, which lets you perform
+ * speech-to-text translation through RecognitionService. IRecognitionService
+ * and IRecognitionListener are the core interfaces; you begin recognition
+ * through IRecognitionService and subscribe to callbacks about when the user
+ * stopped speaking, results come in, errors, etc. through IRecognitionListener.
+ * RecognitionServiceUtil includes default IRecognitionListener and
+ * ServiceConnection implementations to reduce the amount of boilerplate.
+ *
+ * The Service provides no user interface. See RecognitionActivity if you
+ * want the standard voice search UI.
+ *
+ * Below is a small skeleton of how to use the recognizer:
+ *
+ * ServiceConnection conn = new RecognitionServiceUtil.Connection();
+ * mContext.bindService(RecognitionServiceUtil.sDefaultIntent,
+ *     conn, Context.BIND_AUTO_CREATE);
+ * IRecognitionListener listener = new RecognitionServiceWrapper.NullListener() {
+ *         public void onResults(List<String> results) {
+ *             // Do something with recognition transcripts
+ *         }
+ *     }
+ *
+ * // Must wait for conn.mService to be populated, then call below
+ * conn.mService.startListening(null, listener);
+ *
+ * {@hide}
+ */
+public class RecognitionServiceUtil {
+    public static final Intent sDefaultIntent = new Intent(
+            RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
+
+    // Recognize request parameters
+    public static final String USE_LOCATION = "useLocation";
+    public static final String CONTACT_AUTH_TOKEN = "contactAuthToken";
+    
+    // Bundles
+    public static final String NOISE_LEVEL = "NoiseLevel";
+    public static final String SIGNAL_NOISE_RATIO = "SignalNoiseRatio";
+
+    private RecognitionServiceUtil() {}
+
+    /**
+     * IRecognitionListener which does nothing in response to recognition
+     * callbacks. You can subclass from this and override only the methods
+     * whose events you want to respond to.
+     */
+    public static class NullListener extends IRecognitionListener.Stub {
+        public void onReadyForSpeech(Bundle bundle) {}
+        public void onBeginningOfSpeech() {}
+        public void onRmsChanged(float rmsdB) {}
+        public void onBufferReceived(byte[] buf) {}
+        public void onEndOfSpeech() {}
+        public void onError(int error) {}
+        public void onResults(List<RecognitionResult> results, long key) {}
+    }
+
+    /**
+     * Basic ServiceConnection which just records mService variable.
+     */
+    public static class Connection implements ServiceConnection {
+        public IRecognitionService mService;
+
+        public synchronized void onServiceConnected(ComponentName name, IBinder service) {
+            mService = IRecognitionService.Stub.asInterface(service);
+        }
+
+        public void onServiceDisconnected(ComponentName name) {
+            mService = null;
+        }
+    }
+}
diff --git a/core/java/android/text/InputType.java b/core/java/android/text/InputType.java
index d50684a..14b8308 100644
--- a/core/java/android/text/InputType.java
+++ b/core/java/android/text/InputType.java
@@ -128,6 +128,15 @@
      */
     public static final int TYPE_TEXT_FLAG_IME_MULTI_LINE = 0x00040000;
     
+    /**
+     * Flag for {@link #TYPE_CLASS_TEXT}: the input method does not need to
+     * display any dictionary-based candidates. This is useful for text views that
+     * do not contain words from the language and do not benefit from any
+     * dictionary-based completions or corrections. It overrides the
+     * {@link #TYPE_TEXT_FLAG_AUTO_CORRECT} value when set.
+     */
+    public static final int TYPE_TEXT_FLAG_NO_SUGGESTIONS = 0x00080000;
+
     // ----------------------------------------------------------------------
     
     /**
diff --git a/core/java/android/text/method/QwertyKeyListener.java b/core/java/android/text/method/QwertyKeyListener.java
index 172e9ac..f736f85 100644
--- a/core/java/android/text/method/QwertyKeyListener.java
+++ b/core/java/android/text/method/QwertyKeyListener.java
@@ -401,16 +401,12 @@
     private static SparseArray<String> PICKER_SETS =
                         new SparseArray<String>();
     static {
-        PICKER_SETS.put('!', "\u00A1");
-        PICKER_SETS.put('<', "\u00AB");
-        PICKER_SETS.put('>', "\u00BB");
-        PICKER_SETS.put('?', "\u00BF");
         PICKER_SETS.put('A', "\u00C0\u00C1\u00C2\u00C4\u00C6\u00C3\u00C5\u0104\u0100");
         PICKER_SETS.put('C', "\u00C7\u0106\u010C");
         PICKER_SETS.put('D', "\u010E");
         PICKER_SETS.put('E', "\u00C8\u00C9\u00CA\u00CB\u0118\u011A\u0112");
         PICKER_SETS.put('L', "\u0141");
-        PICKER_SETS.put('I', "\u00CC\u00CD\u00CE\u00CF\u012A");
+        PICKER_SETS.put('I', "\u00CC\u00CD\u00CE\u00CF\u012A\u0130");
         PICKER_SETS.put('N', "\u00D1\u0143\u0147");
         PICKER_SETS.put('O', "\u00D8\u0152\u00D5\u00D2\u00D3\u00D4\u00D6\u014C");
         PICKER_SETS.put('R', "\u0158");
@@ -423,7 +419,7 @@
         PICKER_SETS.put('c', "\u00E7\u0107\u010D");
         PICKER_SETS.put('d', "\u010F");
         PICKER_SETS.put('e', "\u00E8\u00E9\u00EA\u00EB\u0119\u011B\u0113");
-        PICKER_SETS.put('i', "\u00EC\u00ED\u00EE\u00EF\u012B");
+        PICKER_SETS.put('i', "\u00EC\u00ED\u00EE\u00EF\u012B\u0131");
         PICKER_SETS.put('l', "\u0142");
         PICKER_SETS.put('n', "\u00F1\u0144\u0148");
         PICKER_SETS.put('o', "\u00F8\u0153\u00F5\u00F2\u00F3\u00F4\u00F6\u014D");
@@ -435,6 +431,34 @@
         PICKER_SETS.put('z', "\u017A\u017C\u017E");
         PICKER_SETS.put(KeyCharacterMap.PICKER_DIALOG_INPUT,
                              "\u2026\u00A5\u2022\u00AE\u00A9\u00B1[]{}\\");
+        PICKER_SETS.put('/', "\\");
+
+        // From packages/inputmethods/LatinIME/res/xml/kbd_symbols.xml
+
+        PICKER_SETS.put('1', "\u00b9\u00bd\u2153\u00bc\u215b");
+        PICKER_SETS.put('2', "\u00b2\u2154");
+        PICKER_SETS.put('3', "\u00b3\u00be\u215c");
+        PICKER_SETS.put('4', "\u2074");
+        PICKER_SETS.put('5', "\u215d");
+        PICKER_SETS.put('7', "\u215e");
+        PICKER_SETS.put('0', "\u207f\u2205");
+        PICKER_SETS.put('$', "\u00a2\u00a3\u20ac\u00a5\u20a3\u20a4\u20b1");
+        PICKER_SETS.put('%', "\u2030");
+        PICKER_SETS.put('*', "\u2020\u2021");
+        PICKER_SETS.put('-', "\u2013\u2014");
+        PICKER_SETS.put('+', "\u00b1");
+        PICKER_SETS.put('(', "[{<");
+        PICKER_SETS.put(')', "]}>");
+        PICKER_SETS.put('!', "\u00a1");
+        PICKER_SETS.put('"', "\u201c\u201d\u00ab\u00bb\u02dd");
+        PICKER_SETS.put('?', "\u00bf");
+        PICKER_SETS.put(',', "\u201a\u201e");
+
+        // From packages/inputmethods/LatinIME/res/xml/kbd_symbols_shift.xml
+
+        PICKER_SETS.put('=', "\u2260\u2248\u221e");
+        PICKER_SETS.put('<', "\u2264\u00ab\u2039");
+        PICKER_SETS.put('>', "\u2265\u00bb\u203a");
     };
 
     private boolean showCharacterPicker(View view, Editable content, char c,
diff --git a/core/java/android/text/util/Rfc822InputFilter.java b/core/java/android/text/util/Rfc822InputFilter.java
new file mode 100644
index 0000000..8c8b7fc
--- /dev/null
+++ b/core/java/android/text/util/Rfc822InputFilter.java
@@ -0,0 +1,58 @@
+package android.text.util;
+
+import android.text.InputFilter;
+import android.text.Spanned;
+import android.text.SpannableStringBuilder;
+
+/**
+ * Implements special address cleanup rules:
+ * The first space key entry following an "@" symbol that is followed by any combination
+ * of letters and symbols, including one+ dots and zero commas, should insert an extra
+ * comma (followed by the space).
+ *
+ * @hide
+ */
+public class Rfc822InputFilter implements InputFilter {
+
+    public CharSequence filter(CharSequence source, int start, int end, Spanned dest,
+        int dstart, int dend) {
+
+        // quick check - did they enter a single space?
+        if (end-start != 1 || source.charAt(start) != ' ') {
+            return null;
+        }
+
+        // determine if the characters before the new space fit the pattern
+        // follow backwards and see if we find a comma, dot, or @
+        int scanBack = dstart;
+        boolean dotFound = false;
+        while (scanBack > 0) {
+            char c = dest.charAt(--scanBack);
+            switch (c) {
+                case '.':
+                    dotFound = true;    // one or more dots are req'd
+                    break;
+                case ',':
+                    return null;
+                case '@':
+                    if (!dotFound) {
+                        return null;
+                    }
+                    // we have found a comma-insert case.  now just do it
+                    // in the least expensive way we can.
+                    if (source instanceof Spanned) {
+                        SpannableStringBuilder sb = new SpannableStringBuilder(",");
+                        sb.append(source);
+                        return sb;
+                    } else {
+                        return ", ";
+                    }
+                default:
+                    // just keep going
+            }
+        }
+
+        // no termination cases were found, so don't edit the input
+        return null;
+    }
+}
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index 94acd3f..e5985c1 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -458,11 +458,12 @@
     public final View createView(String name, String prefix, AttributeSet attrs)
             throws ClassNotFoundException, InflateException {
         Constructor constructor = sConstructorMap.get(name);
+        Class clazz = null;
 
         try {
             if (constructor == null) {
                 // Class not found in the cache, see if it's real, and try to add it
-                Class clazz = mContext.getClassLoader().loadClass(
+                clazz = mContext.getClassLoader().loadClass(
                         prefix != null ? (prefix + name) : name);
                 
                 if (mFilter != null && clazz != null) {
@@ -480,7 +481,7 @@
                     Boolean allowedState = mFilterMap.get(name);
                     if (allowedState == null) {
                         // New class -- remember whether it is allowed
-                        Class clazz = mContext.getClassLoader().loadClass(
+                        clazz = mContext.getClassLoader().loadClass(
                                 prefix != null ? (prefix + name) : name);
                         
                         boolean allowed = clazz != null && mFilter.onLoadClass(clazz);
@@ -511,7 +512,7 @@
         } catch (Exception e) {
             InflateException ie = new InflateException(attrs.getPositionDescription()
                     + ": Error inflating class "
-                    + (constructor == null ? "<unknown>" : constructor.getClass().getName()));
+                    + (clazz == null ? "<unknown>" : clazz.getName()));
             ie.initCause(e);
             throw ie;
         }
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 8c12656..f67c4aa 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -500,6 +500,12 @@
          */
         public static final int FLAG_SHOW_WALLPAPER = 0x00100000;
         
+        /** Window flag: when set as a window is being added or made
+         * visible, once the window has been shown then the system will
+         * poke the power manager's user activity (as if the user had woken
+         * up the device) to turn the screen on. */
+        public static final int FLAG_TURN_SCREEN_ON = 0x00200000;
+        
         /** Window flag: special flag to limit the size of the window to be
          * original size ([320x480] x density). Used to create window for applications
          * running under compatibility mode.
diff --git a/core/java/android/webkit/HTML5VideoViewProxy.java b/core/java/android/webkit/HTML5VideoViewProxy.java
index 5a164f8..c10355c 100644
--- a/core/java/android/webkit/HTML5VideoViewProxy.java
+++ b/core/java/android/webkit/HTML5VideoViewProxy.java
@@ -17,8 +17,18 @@
 package android.webkit;
 
 import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
 import android.media.MediaPlayer;
 import android.media.MediaPlayer.OnPreparedListener;
+import android.media.MediaPlayer.OnCompletionListener;
+import android.media.MediaPlayer.OnErrorListener;
+import android.net.http.EventHandler;
+import android.net.http.Headers;
+import android.net.http.RequestHandle;
+import android.net.http.RequestQueue;
+import android.net.http.SslCertificate;
+import android.net.http.SslError;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
@@ -30,182 +40,389 @@
 import android.view.ViewGroup;
 import android.webkit.ViewManager.ChildView;
 import android.widget.AbsoluteLayout;
+import android.widget.ImageView;
 import android.widget.MediaController;
 import android.widget.VideoView;
 
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
 import java.util.HashMap;
+import java.util.Map;
 
 /**
  * <p>Proxy for HTML5 video views.
  */
-class HTML5VideoViewProxy extends Handler {
+class HTML5VideoViewProxy extends Handler
+                          implements MediaPlayer.OnPreparedListener,
+                          MediaPlayer.OnCompletionListener {
     // Logging tag.
     private static final String LOGTAG = "HTML5VideoViewProxy";
 
     // Message Ids for WebCore thread -> UI thread communication.
     private static final int INIT              = 100;
     private static final int PLAY              = 101;
+    private static final int SET_POSTER        = 102;
+    private static final int SEEK              = 103;
+    private static final int PAUSE             = 104;
 
+    // Message Ids to be handled on the WebCore thread
+    private static final int PREPARED          = 200;
+    private static final int ENDED             = 201;
+
+    // The C++ MediaPlayerPrivateAndroid object.
+    int mNativePointer;
+    // The handler for WebCore thread messages;
+    private Handler mWebCoreHandler;
     // The WebView instance that created this view.
     private WebView mWebView;
     // The ChildView instance used by the ViewManager.
     private ChildView mChildView;
-    // The VideoView instance. Note that we could
-    // also access this via mChildView.mView but it would
-    // always require cast, so it is more convenient to store
-    // it here as well.
-    private HTML5VideoView mVideoView;
+    // The poster image to be shown when the video is not playing.
+    private ImageView mPosterView;
+    // The poster downloader.
+    private PosterDownloader mPosterDownloader;
+    // The seek position.
+    private int mSeekPosition;
+    // A helper class to control the playback. This executes on the UI thread!
+    private static final class VideoPlayer {
+        // The proxy that is currently playing (if any).
+        private static HTML5VideoViewProxy mCurrentProxy;
+        // The VideoView instance. This is a singleton for now, at least until
+        // http://b/issue?id=1973663 is fixed.
+        private static VideoView mVideoView;
 
-    // A VideoView subclass that responds to double-tap
-    // events by going fullscreen.
-    class HTML5VideoView extends VideoView {
-        // Used to save the layout parameters if the view
-        // is changed to fullscreen.
-        private AbsoluteLayout.LayoutParams mEmbeddedLayoutParams;
-        // Flag that denotes whether the view is fullscreen or not.
-        private boolean mIsFullscreen;
-        // Used to save the current playback position when
-        // transitioning to/from fullscreen.
-        private int mPlaybackPosition;
-        // The callback object passed to the host application. This callback
-        // is invoked when the host application dismisses our VideoView
-        // (e.g. the user presses the back key).
-        private WebChromeClient.CustomViewCallback mCallback =
-                new WebChromeClient.CustomViewCallback() {
-            public void onCustomViewHidden() {
-                playEmbedded();
-            }
-        };
+        private static final WebChromeClient.CustomViewCallback mCallback =
+            new WebChromeClient.CustomViewCallback() {
+                public void onCustomViewHidden() {
+                    // At this point the videoview is pretty much destroyed.
+                    // It listens to SurfaceHolder.Callback.SurfaceDestroyed event
+                    // which happens when the video view is detached from its parent
+                    // view. This happens in the WebChromeClient before this method
+                    // is invoked.
+                    mCurrentProxy.playbackEnded();
+                    mCurrentProxy = null;
+                    mVideoView = null;
+                }
+            };
 
-        // The OnPreparedListener, used to automatically resume
-        // playback when transitioning to/from fullscreen.
-        private MediaPlayer.OnPreparedListener mPreparedListener =
-                new MediaPlayer.OnPreparedListener() {
-            public void onPrepared(MediaPlayer mp) {
-                resumePlayback();
-            }
-        };
-
-        HTML5VideoView(Context context) {
-            super(context);
-        }
-
-        void savePlaybackPosition() {
-            if (isPlaying()) {
-                mPlaybackPosition = getCurrentPosition();
-            }
-        }
-
-        void resumePlayback() {
-            seekTo(mPlaybackPosition);
-            start();
-            setOnPreparedListener(null);
-        }
-
-        void playEmbedded() {
-            // Attach to the WebView.
-            mChildView.attachViewOnUIThread(mEmbeddedLayoutParams);
-            // Make sure we're visible
-            setVisibility(View.VISIBLE);
-            // Set the onPrepared listener so we start
-            // playing when the video view is reattached
-            // and its surface is recreated.
-            setOnPreparedListener(mPreparedListener);
-            mIsFullscreen = false;
-        }
-
-        void playFullScreen() {
-            WebChromeClient client = mWebView.getWebChromeClient();
-            if (client == null) {
+        public static void play(String url, int time, HTML5VideoViewProxy proxy,
+                WebChromeClient client) {
+            if (mCurrentProxy != null) {
+                // Some other video is already playing. Notify the caller that its playback ended.
+                proxy.playbackEnded();
                 return;
             }
-            // Save the current layout params.
-            mEmbeddedLayoutParams =
-                    (AbsoluteLayout.LayoutParams) getLayoutParams();
-            // Detach from the WebView.
-            mChildView.removeViewOnUIThread();
-            // Attach to the browser UI.
-            client.onShowCustomView(this, mCallback);
-            // Set the onPrepared listener so we start
-            // playing when after the video view is reattached
-            // and its surface is recreated.
-            setOnPreparedListener(mPreparedListener);
-            mIsFullscreen = true;
+            mCurrentProxy = proxy;
+            mVideoView = new VideoView(proxy.getContext());
+            mVideoView.setWillNotDraw(false);
+            mVideoView.setMediaController(new MediaController(proxy.getContext()));
+            mVideoView.setVideoURI(Uri.parse(url));
+            mVideoView.setOnCompletionListener(proxy);
+            mVideoView.setOnPreparedListener(proxy);
+            mVideoView.seekTo(time);
+            mVideoView.start();
+            client.onShowCustomView(mVideoView, mCallback);
         }
 
-        @Override
-        public boolean onTouchEvent(MotionEvent ev) {
-            // TODO: implement properly (i.e. detect double tap)
-            if (mIsFullscreen || !isPlaying()) {
-                return super.onTouchEvent(ev);
+        public static void seek(int time, HTML5VideoViewProxy proxy) {
+            if (mCurrentProxy == proxy && time >= 0 && mVideoView != null) {
+                mVideoView.seekTo(time);
             }
-            playFullScreen();
-            return true;
         }
 
-        @Override
-        public void onDetachedFromWindow() {
-            super.onDetachedFromWindow();
-            savePlaybackPosition();
+        public static void pause(HTML5VideoViewProxy proxy) {
+            if (mCurrentProxy == proxy && mVideoView != null) {
+                mVideoView.pause();
+            }
+        }
+    }
+
+    // A bunch event listeners for our VideoView
+    // MediaPlayer.OnPreparedListener
+    public void onPrepared(MediaPlayer mp) {
+        Message msg = Message.obtain(mWebCoreHandler, PREPARED);
+        Map<String, Object> map = new HashMap<String, Object>();
+        map.put("dur", new Integer(mp.getDuration()));
+        map.put("width", new Integer(mp.getVideoWidth()));
+        map.put("height", new Integer(mp.getVideoHeight()));
+        msg.obj = map;
+        mWebCoreHandler.sendMessage(msg);
+    }
+
+    // MediaPlayer.OnCompletionListener;
+    public void onCompletion(MediaPlayer mp) {
+        playbackEnded();
+    }
+
+    public void playbackEnded() {
+        Message msg = Message.obtain(mWebCoreHandler, ENDED);
+        mWebCoreHandler.sendMessage(msg);
+    }
+
+    // Handler for the messages from WebCore thread to the UI thread.
+    @Override
+    public void handleMessage(Message msg) {
+        // This executes on the UI thread.
+        switch (msg.what) {
+            case INIT: {
+                mPosterView = new ImageView(mWebView.getContext());
+                mChildView.mView = mPosterView;
+                break;
+            }
+            case PLAY: {
+                String url = (String) msg.obj;
+                WebChromeClient client = mWebView.getWebChromeClient();
+                if (client != null) {
+                    VideoPlayer.play(url, mSeekPosition, this, client);
+                }
+                break;
+            }
+            case SET_POSTER: {
+                Bitmap poster = (Bitmap) msg.obj;
+                mPosterView.setImageBitmap(poster);
+                break;
+            }
+            case SEEK: {
+                Integer time = (Integer) msg.obj;
+                mSeekPosition = time;
+                VideoPlayer.seek(mSeekPosition, this);
+                break;
+            }
+            case PAUSE: {
+                VideoPlayer.pause(this);
+                break;
+            }
+        }
+    }
+
+    // Everything below this comment executes on the WebCore thread, except for
+    // the EventHandler methods, which are called on the network thread.
+
+    // A helper class that knows how to download posters
+    private static final class PosterDownloader implements EventHandler {
+        // The request queue. This is static as we have one queue for all posters.
+        private static RequestQueue mRequestQueue;
+        private static int mQueueRefCount = 0;
+        // The poster URL
+        private String mUrl;
+        // The proxy we're doing this for.
+        private final HTML5VideoViewProxy mProxy;
+        // The poster bytes. We only touch this on the network thread.
+        private ByteArrayOutputStream mPosterBytes;
+        // The request handle. We only touch this on the WebCore thread.
+        private RequestHandle mRequestHandle;
+        // The response status code.
+        private int mStatusCode;
+        // The response headers.
+        private Headers mHeaders;
+        // The handler to handle messages on the WebCore thread.
+        private Handler mHandler;
+
+        public PosterDownloader(String url, HTML5VideoViewProxy proxy) {
+            mUrl = url;
+            mProxy = proxy;
+            mHandler = new Handler();
+        }
+        // Start the download. Called on WebCore thread.
+        public void start() {
+            retainQueue();
+            mRequestHandle = mRequestQueue.queueRequest(mUrl, "GET", null, this, null, 0);
+        }
+        // Cancel the download if active and release the queue. Called on WebCore thread.
+        public void cancelAndReleaseQueue() {
+            if (mRequestHandle != null) {
+                mRequestHandle.cancel();
+                mRequestHandle = null;
+            }
+            releaseQueue();
+        }
+        // EventHandler methods. Executed on the network thread.
+        public void status(int major_version,
+                int minor_version,
+                int code,
+                String reason_phrase) {
+            mStatusCode = code;
+        }
+
+        public void headers(Headers headers) {
+            mHeaders = headers;
+        }
+
+        public void data(byte[] data, int len) {
+            if (mPosterBytes == null) {
+                mPosterBytes = new ByteArrayOutputStream();
+            }
+            mPosterBytes.write(data, 0, len);
+        }
+
+        public void endData() {
+            if (mStatusCode == 200) {
+                if (mPosterBytes.size() > 0) {
+                    Bitmap poster = BitmapFactory.decodeByteArray(
+                            mPosterBytes.toByteArray(), 0, mPosterBytes.size());
+                    if (poster != null) {
+                        mProxy.doSetPoster(poster);
+                    }
+                }
+                cleanup();
+            } else if (mStatusCode >= 300 && mStatusCode < 400) {
+                // We have a redirect.
+                mUrl = mHeaders.getLocation();
+                if (mUrl != null) {
+                    mHandler.post(new Runnable() {
+                       public void run() {
+                           if (mRequestHandle != null) {
+                               mRequestHandle.setupRedirect(mUrl, mStatusCode,
+                                       new HashMap<String, String>());
+                           }
+                       }
+                    });
+                }
+            }
+        }
+
+        public void certificate(SslCertificate certificate) {
+            // Don't care.
+        }
+
+        public void error(int id, String description) {
+            cleanup();
+        }
+
+        public boolean handleSslErrorRequest(SslError error) {
+            // Don't care. If this happens, data() will never be called so
+            // mPosterBytes will never be created, so no need to call cleanup.
+            return false;
+        }
+        // Tears down the poster bytes stream. Called on network thread.
+        private void cleanup() {
+            if (mPosterBytes != null) {
+                try {
+                    mPosterBytes.close();
+                } catch (IOException ignored) {
+                    // Ignored.
+                } finally {
+                    mPosterBytes = null;
+                }
+            }
+        }
+
+        // Queue management methods. Called on WebCore thread.
+        private void retainQueue() {
+            if (mRequestQueue == null) {
+                mRequestQueue = new RequestQueue(mProxy.getContext());
+            }
+            mQueueRefCount++;
+        }
+
+        private void releaseQueue() {
+            if (mQueueRefCount == 0) {
+                return;
+            }
+            if (--mQueueRefCount == 0) {
+                mRequestQueue.shutdown();
+                mRequestQueue = null;
+            }
         }
     }
 
     /**
      * Private constructor.
-     * @param context is the application context.
+     * @param webView is the WebView that hosts the video.
+     * @param nativePtr is the C++ pointer to the MediaPlayerPrivate object.
      */
-    private HTML5VideoViewProxy(WebView webView) {
+    private HTML5VideoViewProxy(WebView webView, int nativePtr) {
         // This handler is for the main (UI) thread.
         super(Looper.getMainLooper());
         // Save the WebView object.
         mWebView = webView;
+        // Save the native ptr
+        mNativePointer = nativePtr;
+        // create the message handler for this thread
+        createWebCoreHandler();
     }
 
-    @Override
-    public void handleMessage(Message msg) {
-        // This executes on the UI thread.
-        switch (msg.what) {
-            case INIT:
-                // Create the video view and set a default controller.
-                mVideoView = new HTML5VideoView(mWebView.getContext());
-                // This is needed because otherwise there will be a black square
-                // stuck on the screen.
-                mVideoView.setWillNotDraw(false);
-                mVideoView.setMediaController(new MediaController(mWebView.getContext()));
-                mChildView.mView = mVideoView;
-                break;
-            case PLAY:
-                if (mVideoView == null) {
-                    return;
+    private void createWebCoreHandler() {
+        mWebCoreHandler = new Handler() {
+            @Override
+            public void handleMessage(Message msg) {
+                switch (msg.what) {
+                    case PREPARED: {
+                        Map<String, Object> map = (Map<String, Object>) msg.obj;
+                        Integer duration = (Integer) map.get("dur");
+                        Integer width = (Integer) map.get("width");
+                        Integer height = (Integer) map.get("height");
+                        nativeOnPrepared(duration.intValue(), width.intValue(),
+                                height.intValue(), mNativePointer);
+                        break;
+                    }
+                    case ENDED:
+                        nativeOnEnded(mNativePointer);
+                        break;
                 }
-                HashMap<String, Object> map =
-                        (HashMap<String, Object>) msg.obj;
-                String url = (String) map.get("url");
-                mVideoView.setVideoURI(Uri.parse(url));
-                mVideoView.start();
-                break;
-        }
+            }
+        };
     }
 
-    /**
-     * Play a video stream.
-     * @param url is the URL of the video stream.
-     * @param webview is the WebViewCore that is requesting the playback.
-     */
-    public void play(String url) {
-         // We need to know the webview that is requesting the playback.
-        Message message = obtainMessage(PLAY);
-        HashMap<String, Object> map = new HashMap();
-        map.put("url", url);
-        message.obj = map;
+    private void doSetPoster(Bitmap poster) {
+        if (poster == null) {
+            return;
+        }
+        // Send the bitmap over to the UI thread.
+        Message message = obtainMessage(SET_POSTER);
+        message.obj = poster;
         sendMessage(message);
     }
 
+    public Context getContext() {
+        return mWebView.getContext();
+    }
+
+    // The public methods below are all called from WebKit only.
+    /**
+     * Play a video stream.
+     * @param url is the URL of the video stream.
+     */
+    public void play(String url) {
+        if (url == null) {
+            return;
+        }
+        Message message = obtainMessage(PLAY);
+        message.obj = url;
+        sendMessage(message);
+    }
+
+    /**
+     * Seek into the video stream.
+     * @param  time is the position in the video stream.
+     */
+    public void seek(int time) {
+        Message message = obtainMessage(SEEK);
+        message.obj = new Integer(time);
+        sendMessage(message);
+    }
+
+    /**
+     * Pause the playback.
+     */
+    public void pause() {
+        Message message = obtainMessage(PAUSE);
+        sendMessage(message);
+    }
+
+    /**
+     * Create the child view that will cary the poster.
+     */
     public void createView() {
         mChildView = mWebView.mViewManager.createView();
         sendMessage(obtainMessage(INIT));
     }
 
+    /**
+     * Attach the poster view.
+     * @param x, y are the screen coordinates where the poster should be hung.
+     * @param width, height denote the size of the poster.
+     */
     public void attachView(int x, int y, int width, int height) {
         if (mChildView == null) {
             return;
@@ -213,11 +430,36 @@
         mChildView.attachView(x, y, width, height);
     }
 
+    /**
+     * Remove the child view and, thus, the poster.
+     */
     public void removeView() {
         if (mChildView == null) {
             return;
         }
         mChildView.removeView();
+        // This is called by the C++ MediaPlayerPrivate dtor.
+        // Cancel any active poster download.
+        if (mPosterDownloader != null) {
+            mPosterDownloader.cancelAndReleaseQueue();
+        }
+    }
+
+    /**
+     * Load the poster image.
+     * @param url is the URL of the poster image.
+     */
+    public void loadPoster(String url) {
+        if (url == null) {
+            return;
+        }
+        // Cancel any active poster download.
+        if (mPosterDownloader != null) {
+            mPosterDownloader.cancelAndReleaseQueue();
+        }
+        // Load the poster asynchronously
+        mPosterDownloader = new PosterDownloader(url, this);
+        mPosterDownloader.start();
     }
 
     /**
@@ -226,7 +468,10 @@
      *
      * @return a new HTML5VideoViewProxy object.
      */
-    public static HTML5VideoViewProxy getInstance(WebViewCore webViewCore) {
-        return new HTML5VideoViewProxy(webViewCore.getWebView());
+    public static HTML5VideoViewProxy getInstance(WebViewCore webViewCore, int nativePtr) {
+        return new HTML5VideoViewProxy(webViewCore.getWebView(), nativePtr);
     }
+
+    private native void nativeOnPrepared(int duration, int width, int height, int nativePointer);
+    private native void nativeOnEnded(int nativePointer);
 }
diff --git a/core/java/android/webkit/PluginActivity.java b/core/java/android/webkit/PluginActivity.java
index f9e3080..cda7b59 100644
--- a/core/java/android/webkit/PluginActivity.java
+++ b/core/java/android/webkit/PluginActivity.java
@@ -49,10 +49,10 @@
         final int npp = intent.getIntExtra(INTENT_EXTRA_NPP_INSTANCE, -1);
         // Retrieve the PluginStub implemented in packageName.className
         PluginStub stub =
-                PluginUtil.getPluginStub(this, packageName, className, npp);
+                PluginUtil.getPluginStub(this, packageName, className);
 
         if (stub != null) {
-            View pluginView = stub.getFullScreenView(this);
+            View pluginView = stub.getFullScreenView(npp, this);
             if (pluginView != null) {
                 setContentView(pluginView);
             } else {
diff --git a/core/java/android/webkit/PluginStub.java b/core/java/android/webkit/PluginStub.java
index c24da8d..3887d44 100644
--- a/core/java/android/webkit/PluginStub.java
+++ b/core/java/android/webkit/PluginStub.java
@@ -19,32 +19,29 @@
 import android.view.View;
 
 /**
- * This abstract class is used to implement plugins in a WebView. A plugin
+ * This interface is used to implement plugins in a WebView. A plugin
  * package may extend this class and implement the abstract functions to create
  * embedded or fullscreeen views displayed in a WebView. The PluginStub
  * implementation will be provided the same NPP instance that is created
  * through the native interface.
  */
-public abstract class PluginStub {
-    /**
-     * Construct a new PluginStub implementation for the given NPP instance.
-     * @param npp The native NPP instance.
-     */
-    public PluginStub(int npp) { }
+public interface PluginStub {
 
     /**
      * Return a custom embedded view to draw the plugin.
+     * @param NPP The native NPP instance.
      * @param context The current application's Context.
      * @return A custom View that will be managed by WebView.
      */
-    public abstract View getEmbeddedView(Context context);
+    public abstract View getEmbeddedView(int NPP, Context context);
 
     /**
      * Return a custom full-screen view to be displayed when the user requests
      * a plugin display as full-screen. Note that the application may choose not
      * to display this View as completely full-screen.
+     * @param NPP The native NPP instance.
      * @param context The current application's Context.
      * @return A custom View that will be managed by the application.
      */
-    public abstract View getFullScreenView(Context context);
+    public abstract View getFullScreenView(int NPP, Context context);
 }
diff --git a/core/java/android/webkit/PluginUtil.java b/core/java/android/webkit/PluginUtil.java
index c0a7375..8fdbd67 100644
--- a/core/java/android/webkit/PluginUtil.java
+++ b/core/java/android/webkit/PluginUtil.java
@@ -32,19 +32,16 @@
      * @param className the fully qualified name of a subclass of PluginStub
      */
     /* package */
-    static PluginStub getPluginStub(Context context, String packageName,
-            String className, int NPP) {
+    static PluginStub getPluginStub(Context context, String packageName, 
+            String className) {
         try {
             Context pluginContext = context.createPackageContext(packageName,
                     Context.CONTEXT_INCLUDE_CODE |
                     Context.CONTEXT_IGNORE_SECURITY);
             ClassLoader pluginCL = pluginContext.getClassLoader();
 
-            Class<?> stubClass =
-                    pluginCL.loadClass(className);
-            Constructor<?> stubConstructor =
-                    stubClass.getConstructor(int.class);
-            Object stubObject = stubConstructor.newInstance(NPP);
+            Class<?> stubClass = pluginCL.loadClass(className);
+            Object stubObject = stubClass.newInstance();
 
             if (stubObject instanceof PluginStub) {
                 return (PluginStub) stubObject;
diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java
index 95b3a12..39a2470 100644
--- a/core/java/android/webkit/WebTextView.java
+++ b/core/java/android/webkit/WebTextView.java
@@ -16,6 +16,8 @@
 
 package android.webkit;
 
+import com.android.internal.widget.EditableInputConnection;
+
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Color;
@@ -38,6 +40,7 @@
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputMethodManager;
@@ -346,6 +349,16 @@
 
     @Override
     protected void onSelectionChanged(int selStart, int selEnd) {
+        // This code is copied from TextView.onDraw().  That code does not get
+        // executed, however, because the WebTextView does not draw, allowing
+        // webkit's drawing to show through.
+        InputMethodManager imm = InputMethodManager.peekInstance();
+        if (imm != null && imm.isActive(this)) {
+            Spannable sp = (Spannable) getText();
+            int candStart = EditableInputConnection.getComposingSpanStart(sp);
+            int candEnd = EditableInputConnection.getComposingSpanEnd(sp);
+            imm.updateSelection(this, selStart, selEnd, candStart, candEnd);
+        }
         if (!mFromWebKit && mWebView != null) {
             if (DebugFlags.WEB_TEXT_VIEW) {
                 Log.v(LOGTAG, "onSelectionChanged selStart=" + selStart
@@ -430,18 +443,26 @@
             mGotTouchDown = true;
             break;
         case MotionEvent.ACTION_MOVE:
+            int slop = ViewConfiguration.get(mContext).getScaledTouchSlop();
             Spannable buffer = getText();
             int initialScrollX = Touch.getInitialScrollX(this, buffer);
             int initialScrollY = Touch.getInitialScrollY(this, buffer);
             super.onTouchEvent(event);
-            if (mScrollX != initialScrollX
-                    || mScrollY != initialScrollY) {
+            if (Math.abs(mScrollX - initialScrollX) > slop
+                    || Math.abs(mScrollY - initialScrollY) > slop) {
                 if (mWebView != null) {
                     mWebView.scrollFocusedTextInput(mScrollX, mScrollY);
                 }
                 mScrolled = true;
                 return true;
             }
+            if (Math.abs((int) event.getX() - mDragStartX) < slop
+                    && Math.abs((int) event.getY() - mDragStartY) < slop) {
+                // If the user has not scrolled further than slop, we should not
+                // send the drag.  Instead, do nothing, and when the user lifts
+                // their finger, we will change the selection.
+                return true;
+            }
             if (mWebView != null) {
                 // Only want to set the initial state once.
                 if (!mDragSent) {
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 081f67a..ddee26d 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -420,6 +420,7 @@
     private static final int STD_SPEED = 480;  // pixels per second
     // time for the longest scroll animation
     private static final int MAX_DURATION = 750;   // milliseconds
+    private static final int SLIDE_TITLE_DURATION = 300;   // milliseconds
     private Scroller mScroller;
 
     private boolean mWrapContent;
@@ -2416,10 +2417,18 @@
         if ((dx | dy) == 0) {
             return false;
         }
-
-        if (true && animate) {
+        // mobile sites prefer to scroll to (0, 1), thus the + 1 below
+        boolean slideTitle = getVisibleTitleHeight() > 0
+            && y <= getTitleHeight() + 1;
+        if (DebugFlags.WEB_VIEW) {
+            Log.v(LOGTAG, "pinScrollTo slideTitle=" + slideTitle
+                    + " getVisibleTitleHeight()=" + getVisibleTitleHeight()
+                    + " animationDuration=" + animationDuration + " y=" + y);
+        }
+        if (slideTitle || animate) {
             //        Log.d(LOGTAG, "startScroll: " + dx + " " + dy);
-
+            if (slideTitle && animationDuration < SLIDE_TITLE_DURATION)
+                animationDuration = SLIDE_TITLE_DURATION;
             mScroller.startScroll(mScrollX, mScrollY, dx, dy,
                     animationDuration > 0 ? animationDuration : computeDuration(dx, dy));
             invalidate();
@@ -2899,6 +2908,8 @@
                 getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
 
         if (isTextView) {
+            if (mWebTextView == null) return;
+
             imm.showSoftInput(mWebTextView, 0);
             // Now we need to fake a touch event to place the cursor where the
             // user touched.
@@ -4791,8 +4802,11 @@
                             mMaxZoomScale = restoreState.mMaxScale;
                         }
                         setNewZoomScale(mLastScale, false);
-                        setContentScrollTo(restoreState.mScrollX,
-                                restoreState.mScrollY);
+                        if (getVisibleTitleHeight() == 0
+                                || restoreState.mScrollY != 0) {
+                            setContentScrollTo(restoreState.mScrollX,
+                                    restoreState.mScrollY);
+                        }
                         if (useWideViewport
                                 && settings.getLoadWithOverviewMode()) {
                             if (restoreState.mViewScale == 0
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 5f2d65e..ac3334c 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -34,6 +34,7 @@
 import android.view.KeyEvent;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
+import android.view.View;
 
 import java.util.ArrayList;
 import java.util.Map;
@@ -2060,84 +2061,32 @@
         }
     }
 
-    // This class looks like a SurfaceView to native code. In java, we can
-    // assume the passed in SurfaceView is this class so we can talk to the
-    // ViewManager through the ChildView.
-    private class SurfaceViewProxy extends SurfaceView
-            implements SurfaceHolder.Callback {
-        private final ViewManager.ChildView mChildView;
-        private int mPointer;
-        private final boolean mIsFixedSize;
-        SurfaceViewProxy(Context context, ViewManager.ChildView childView,
-                int pointer, int pixelFormat, boolean isFixedSize) {
-            super(context);
-            setWillNotDraw(false); // this prevents the black box artifact
-            getHolder().addCallback(this);
-            getHolder().setFormat(pixelFormat);
-            mChildView = childView;
-            mChildView.mView = this;
-            mPointer = pointer;
-            mIsFixedSize = isFixedSize;
-        }
-        void destroy() {
-            mPointer = 0;
-            mChildView.removeView();
-        }
-        void attach(int x, int y, int width, int height) {
-            mChildView.attachView(x, y, width, height);
-
-            if (mIsFixedSize) {
-                getHolder().setFixedSize(width, height);
-            }
-        }
-
-        // SurfaceHolder.Callback methods
-        public void surfaceCreated(SurfaceHolder holder) {
-            if (mPointer != 0) {
-                nativeSurfaceChanged(mPointer, 0, 0, 0, 0);
-            }
-        }
-        public void surfaceChanged(SurfaceHolder holder, int format, int width,
-                int height) {
-            if (mPointer != 0) {
-                nativeSurfaceChanged(mPointer, 1, format, width, height);
-            }
-        }
-        public void surfaceDestroyed(SurfaceHolder holder) {
-            if (mPointer != 0) {
-                nativeSurfaceChanged(mPointer, 2, 0, 0, 0);
-            }
-        }
-    }
-
-    // PluginWidget functions for mainting SurfaceViews for the Surface drawing
+    // PluginWidget functions for creating SurfaceViews for the Surface drawing
     // model.
-    private SurfaceView createSurface(int nativePointer, int pixelFormat,
-                                      boolean isFixedSize) {
+    private ViewManager.ChildView createSurface(String packageName, String className,
+            int npp, int x, int y, int width, int height) {
         if (mWebView == null) {
             return null;
         }
-        return new SurfaceViewProxy(mContext, mWebView.mViewManager.createView(),
-                                    nativePointer, pixelFormat, isFixedSize);
+        PluginStub stub = PluginUtil.getPluginStub(mWebView.getContext(), packageName, className);
+        if (stub == null) {
+            Log.e(LOGTAG, "Unable to find plugin class (" + className + 
+                    ") in the apk (" + packageName + ")");
+            return null;
+        }
+        
+        View pluginView = stub.getEmbeddedView(npp, mWebView.getContext());
+        
+        ViewManager.ChildView view = mWebView.mViewManager.createView();
+        view.mView = pluginView;
+        view.attachView(x, y, width, height);
+        return view;
     }
-
-    private void destroySurface(SurfaceView surface) {
-        SurfaceViewProxy proxy = (SurfaceViewProxy) surface;
-        proxy.destroy();
+    
+    private void destroySurface(ViewManager.ChildView childView) {
+        childView.removeView();
     }
 
-    private void attachSurface(SurfaceView surface, int x, int y,
-            int width, int height) {
-        SurfaceViewProxy proxy = (SurfaceViewProxy) surface;
-        proxy.attach(x, y, width, height);
-    }
-
-    // Callback for the SurfaceHolder.Callback. Called for all the surface
-    // callbacks. The state parameter is one of Created(0), Changed(1),
-    // Destroyed(2).
-    private native void nativeSurfaceChanged(int pointer, int state, int format,
-            int width, int height);
-
     private native void nativePause();
     private native void nativeResume();
     private native void nativeFreeMemory();
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index 4566c4c..953dd92 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -1325,7 +1325,7 @@
         final int maxHeight = mPopup.getMaxAvailableHeight(
                 getDropDownAnchorView(), mDropDownVerticalOffset, ignoreBottomDecorations);
 
-        if (mDropDownAlwaysVisible) {
+        if (mDropDownAlwaysVisible || mDropDownHeight == ViewGroup.LayoutParams.FILL_PARENT) {
             // getMaxAvailableHeight() subtracts the padding, so we put it back,
             // to get the available height for the whole window
             int padding = 0;
diff --git a/core/java/android/widget/ZoomButtonsController.java b/core/java/android/widget/ZoomButtonsController.java
index 760b8ff..e55fbb8 100644
--- a/core/java/android/widget/ZoomButtonsController.java
+++ b/core/java/android/widget/ZoomButtonsController.java
@@ -249,7 +249,7 @@
         lp.height = LayoutParams.WRAP_CONTENT;
         lp.width = LayoutParams.FILL_PARENT;
         lp.type = LayoutParams.TYPE_APPLICATION_PANEL;
-        lp.format = PixelFormat.TRANSPARENT;
+        lp.format = PixelFormat.TRANSLUCENT;
         lp.windowAnimations = com.android.internal.R.style.Animation_ZoomButtons;
         mContainerLayoutParams = lp;
 
diff --git a/core/java/com/android/internal/widget/ContactHeaderWidget.java b/core/java/com/android/internal/widget/ContactHeaderWidget.java
index fe01866..4ec597c 100644
--- a/core/java/com/android/internal/widget/ContactHeaderWidget.java
+++ b/core/java/com/android/internal/widget/ContactHeaderWidget.java
@@ -42,6 +42,7 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.CheckBox;
+import android.widget.FasttrackBadgeWidget;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.TextView;
@@ -64,15 +65,13 @@
     private TextView mDisplayNameView;
     private TextView mPhoneticNameView;
     private CheckBox mStarredView;
-    private ImageView mPhotoView;
+    private FasttrackBadgeWidget mPhotoView;
     private ImageView mPresenceView;
     private TextView mStatusView;
     private int mNoPhotoResource;
     private QueryHandler mQueryHandler;
 
-    protected long mContactId;
     protected Uri mContactUri;
-    protected Uri mStatusUri;
 
     protected String[] mExcludeMimes = null;
 
@@ -94,6 +93,8 @@
         Contacts.STARRED,
         Contacts.PHOTO_ID,
         Contacts.PRESENCE_STATUS,
+        Contacts._ID,
+        Contacts.LOOKUP_KEY,
     };
     protected static final int HEADER_DISPLAY_NAME_COLUMN_INDEX = 0;
     //TODO: We need to figure out how we're going to get the phonetic name.
@@ -101,6 +102,8 @@
     protected static final int HEADER_STARRED_COLUMN_INDEX = 1;
     protected static final int HEADER_PHOTO_ID_COLUMN_INDEX = 2;
     protected static final int HEADER_PRESENCE_STATUS_COLUMN_INDEX = 3;
+    protected static final int HEADER_CONTACT_ID_COLUMN_INDEX = 4;
+    protected static final int HEADER_LOOKUP_KEY_COLUMN_INDEX = 5;
 
     //Projection used for finding the most recent social status.
     protected static final String[] SOCIAL_PROJECTION = new String[] {
@@ -113,18 +116,29 @@
     //Projection used for looking up contact id from phone number
     protected static final String[] PHONE_LOOKUP_PROJECTION = new String[] {
         PhoneLookup._ID,
+        PhoneLookup.LOOKUP_KEY,
     };
     protected static final int PHONE_LOOKUP_CONTACT_ID_COLUMN_INDEX = 0;
+    protected static final int PHONE_LOOKUP_CONTACT_LOOKUP_KEY_COLUMN_INDEX = 1;
 
     //Projection used for looking up contact id from email address
     protected static final String[] EMAIL_LOOKUP_PROJECTION = new String[] {
         RawContacts.CONTACT_ID,
+        Contacts.LOOKUP_KEY,
     };
     protected static final int EMAIL_LOOKUP_CONTACT_ID_COLUMN_INDEX = 0;
+    protected static final int EMAIL_LOOKUP_CONTACT_LOOKUP_KEY_COLUMN_INDEX = 1;
 
+    protected static final String[] CONTACT_LOOKUP_PROJECTION = new String[] {
+        Contacts._ID,
+    };
+    protected static final int CONTACT_LOOKUP_ID_COLUMN_INDEX = 0;
 
     private static final int TOKEN_CONTACT_INFO = 0;
     private static final int TOKEN_SOCIAL = 1;
+    private static final int TOKEN_PHONE_LOOKUP = 2;
+    private static final int TOKEN_EMAIL_LOOKUP = 3;
+    private static final int TOKEN_LOOKUP_CONTACT_FOR_SOCIAL_QUERY = 4;
 
     public ContactHeaderWidget(Context context) {
         this(context, null);
@@ -151,8 +165,7 @@
         mStarredView = (CheckBox)findViewById(R.id.star);
         mStarredView.setOnClickListener(this);
 
-        mPhotoView = (ImageView)findViewById(R.id.photo);
-        mPhotoView.setOnClickListener(this);
+        mPhotoView = (FasttrackBadgeWidget) findViewById(R.id.photo);
         mPhotoView.setOnLongClickListener(this);
 
         mPresenceView = (ImageView) findViewById(R.id.presence);
@@ -217,12 +230,46 @@
         @Override
         protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
             try{
-                if (token == TOKEN_CONTACT_INFO) {
-                    bindContactInfo(cursor);
-                    invalidate();
-                } else if (token == TOKEN_SOCIAL) {
-                    bindSocial(cursor);
-                    invalidate();
+                switch (token) {
+                    case TOKEN_CONTACT_INFO: {
+                        bindContactInfo(cursor);
+                        invalidate();
+                        break;
+                    }
+                    case TOKEN_SOCIAL: {
+                        bindSocial(cursor);
+                        invalidate();
+                        break;
+                    }
+                    case TOKEN_PHONE_LOOKUP: {
+                        if (cursor != null && cursor.moveToFirst()) {
+                            long contactId = cursor.getLong(PHONE_LOOKUP_CONTACT_ID_COLUMN_INDEX);
+                            String lookupKey = cursor.getString(
+                                    PHONE_LOOKUP_CONTACT_LOOKUP_KEY_COLUMN_INDEX);
+                            bindFromContactUri(Contacts.getLookupUri(contactId, lookupKey));
+                        } else {
+                            setDisplayName((String) cookie, null);
+                        }
+                        break;
+                    }
+                    case TOKEN_EMAIL_LOOKUP: {
+                        if (cursor != null && cursor.moveToFirst()) {
+                            long contactId = cursor.getLong(EMAIL_LOOKUP_CONTACT_ID_COLUMN_INDEX);
+                            String lookupKey = cursor.getString(
+                                    EMAIL_LOOKUP_CONTACT_LOOKUP_KEY_COLUMN_INDEX);
+                            bindFromContactUri(Contacts.getLookupUri(contactId, lookupKey));
+                        } else {
+                            setDisplayName((String) cookie, null);
+                        }
+                        break;
+                    }
+                    case TOKEN_LOOKUP_CONTACT_FOR_SOCIAL_QUERY: {
+                        if (cursor != null && cursor.moveToFirst()) {
+                            long contactId = cursor.getLong(CONTACT_LOOKUP_ID_COLUMN_INDEX);
+                            startSocialQuery(ContentUris.withAppendedId(
+                                    Activities.CONTENT_CONTACT_STATUS_URI, contactId));
+                        }
+                    }
                 }
             } finally {
                 if (cursor != null) {
@@ -300,33 +347,31 @@
      * Convenience method for binding all available data from an existing
      * contact.
      *
-     * @param contactId the contact id of the contact whose info should be displayed.
+     * @param conatctUri a {Contacts.CONTENT_LOOKUP_URI} style URI.
      */
-    public void bindFromContactId(long contactId) {
-        mContactId = contactId;
-        mContactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, mContactId);
+    public void bindFromContactLookupUri(Uri contactLookupUri) {
+        mContactUri = contactLookupUri;
 
-        bindContactUri(mContactUri);
-        bindSocialUri(ContentUris.withAppendedId(Activities.CONTENT_CONTACT_STATUS_URI, mContactId));
+        // Query for the contactId so we can do the social query.
+        mQueryHandler.startQuery(TOKEN_LOOKUP_CONTACT_FOR_SOCIAL_QUERY, null, contactLookupUri,
+                CONTACT_LOOKUP_PROJECTION, null, null, null);
+
+        startContactQuery(contactLookupUri);
     }
 
     /**
-     * Convenience method for binding {@link Contacts} header details from a
-     * {@link Contacts#CONTENT_URI} reference.
+     * Convenience method for binding all available data from an existing
+     * contact.
+     *
+     * @param conatctUri a {Contacts.CONTENT_URI} style URI.
      */
-    public void bindContactUri(Uri contactUri) {
-        mQueryHandler.startQuery(TOKEN_CONTACT_INFO, null, contactUri, HEADER_PROJECTION,
-                null, null, null);
-    }
+    public void bindFromContactUri(Uri contactUri) {
+        mContactUri = contactUri;
+        long contactId = ContentUris.parseId(contactUri);
 
-    /**
-     * Convenience method for binding {@link Activities} header details from a
-     * {@link Activities#CONTENT_CONTACT_STATUS_URI}.
-     */
-    public void bindSocialUri(Uri contactSocial) {
-        mStatusUri = contactSocial;
-        mQueryHandler.startQuery(TOKEN_SOCIAL, null, mStatusUri, SOCIAL_PROJECTION, null, null,
-                null);
+        startContactQuery(contactUri);
+        startSocialQuery(ContentUris.withAppendedId(
+                Activities.CONTENT_CONTACT_STATUS_URI, contactId));
     }
 
     /**
@@ -338,21 +383,9 @@
      * address, one of them will be chosen to bind to.
      */
     public void bindFromEmail(String emailAddress) {
-        Cursor c = null;
-        try {
-            c = mContentResolver.query(Uri.withAppendedPath(Email.CONTENT_FILTER_EMAIL_URI, Uri
-                    .encode(emailAddress)), EMAIL_LOOKUP_PROJECTION, null, null, null);
-            if (c != null && c.moveToFirst()) {
-                long contactId = c.getLong(EMAIL_LOOKUP_CONTACT_ID_COLUMN_INDEX);
-                bindFromContactId(contactId);
-            } else {
-                setDisplayName(emailAddress, null);
-            }
-        } finally {
-            if (c != null) {
-                c.close();
-            }
-        }
+        mQueryHandler.startQuery(TOKEN_EMAIL_LOOKUP, emailAddress,
+                Uri.withAppendedPath(Email.CONTENT_LOOKUP_URI, Uri.encode(emailAddress)),
+                EMAIL_LOOKUP_PROJECTION, null, null, null);
     }
 
     /**
@@ -364,22 +397,19 @@
      * number, one of them will be chosen to bind to.
      */
     public void bindFromPhoneNumber(String number) {
-        Cursor c = null;
-        try {
-            c = mContentResolver.query(
-                    Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number)),
-                    PHONE_LOOKUP_PROJECTION, null, null, null);
-            if (c != null && c.moveToFirst()) {
-                long contactId = c.getLong(PHONE_LOOKUP_CONTACT_ID_COLUMN_INDEX);
-                bindFromContactId(contactId);
-            } else {
-                setDisplayName(number, null);
-            }
-        } finally {
-            if (c != null) {
-                c.close();
-            }
-        }
+        mQueryHandler.startQuery(TOKEN_PHONE_LOOKUP, number,
+                Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, number),
+                PHONE_LOOKUP_PROJECTION, null, null, null);
+    }
+
+    private void startSocialQuery(Uri contactSocial) {
+        mQueryHandler.startQuery(TOKEN_SOCIAL, null, contactSocial, SOCIAL_PROJECTION, null, null,
+                null);
+    }
+
+    private void startContactQuery(Uri contactUri) {
+        mQueryHandler.startQuery(TOKEN_CONTACT_INFO, null, contactUri, HEADER_PROJECTION,
+                null, null, null);
     }
 
     /**
@@ -390,6 +420,8 @@
 
         // TODO: Bring back phonetic name
         final String displayName = c.getString(HEADER_DISPLAY_NAME_COLUMN_INDEX);
+        final long contactId = c.getLong(HEADER_CONTACT_ID_COLUMN_INDEX);
+        final String lookupKey = c.getString(HEADER_LOOKUP_KEY_COLUMN_INDEX);
         final String phoneticName = null;
         this.setDisplayName(displayName, null);
 
@@ -402,6 +434,7 @@
             photoBitmap = loadPlaceholderPhoto(null);
         }
         mPhotoView.setImageBitmap(photoBitmap);
+        mPhotoView.assignContactUri(Contacts.getLookupUri(contactId, lookupKey));
 
         //Set the presence status
         int presence = c.getInt(HEADER_PRESENCE_STATUS_COLUMN_INDEX);
@@ -423,27 +456,11 @@
             return;
         }
 
-        switch (view.getId()) {
-            case R.id.star: {
-                // Toggle "starred" state
-                final ContentValues values = new ContentValues(1);
-                values.put(Contacts.STARRED, mStarredView.isChecked());
-                mContentResolver.update(mContactUri, values, null, null);
-                break;
-            }
-            case R.id.photo: {
-                // Photo launches contact detail action
-                final Intent intent = new Intent(Intents.SHOW_OR_CREATE_CONTACT, mContactUri);
-                final Rect target = getTargetRect(view);
-                intent.putExtra(Intents.EXTRA_TARGET_RECT, target);
-                intent.putExtra(Intents.EXTRA_MODE, Intents.MODE_SMALL);
-                if (mExcludeMimes != null) {
-                    // Exclude specific MIME-types when requested
-                    intent.putExtra(Intents.EXTRA_EXCLUDE_MIMES, mExcludeMimes);
-                }
-                mContext.startActivity(intent);
-                break;
-            }
+        if (view.getId() == R.id.star) {
+            // Toggle "starred" state
+            final ContentValues values = new ContentValues(1);
+            values.put(Contacts.STARRED, mStarredView.isChecked());
+            mContentResolver.update(mContactUri, values, null, null);
         }
     }
 
diff --git a/core/java/com/android/internal/widget/RotarySelector.java b/core/java/com/android/internal/widget/RotarySelector.java
new file mode 100644
index 0000000..aff92b8
--- /dev/null
+++ b/core/java/com/android/internal/widget/RotarySelector.java
@@ -0,0 +1,547 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.os.Vibrator;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.animation.AccelerateInterpolator;
+import static android.view.animation.AnimationUtils.currentAnimationTimeMillis;
+import com.android.internal.R;
+
+
+/**
+ * Custom view that presents up to two items that are selectable by rotating a semi-circle from
+ * left to right, or right to left.  Used by incoming call screen, and the lock screen when no
+ * security pattern is set.
+ */
+public class RotarySelector extends View {
+    private static final String LOG_TAG = "RotarySelector";
+    private static final boolean DBG = false;
+
+    // Listener for onDialTrigger() callbacks.
+    private OnDialTriggerListener mOnDialTriggerListener;
+
+    private float mDensity;
+
+    // UI elements
+    private Drawable mBackground;
+    private Drawable mDimple;
+
+    private Drawable mLeftHandleIcon;
+    private Drawable mRightHandleIcon;
+
+    private Drawable mArrowShortLeftAndRight;
+    private Drawable mArrowLongLeft;  // Long arrow starting on the left, pointing clockwise
+    private Drawable mArrowLongRight;  // Long arrow starting on the right, pointing CCW
+
+    // positions of the left and right handle
+    private int mLeftHandleX;
+    private int mRightHandleX;
+
+    // current offset of user's dragging
+    private int mTouchDragOffset = 0;
+
+    // state of the animation used to bring the handle back to its start position when
+    // the user lets go before triggering an action
+    private boolean mAnimating = false;
+    private long mAnimationEndTime;
+    private int mAnimatingDelta;
+    private AccelerateInterpolator mInterpolator;
+
+    /**
+     * True after triggering an action if the user of {@link OnDialTriggerListener} wants to
+     * freeze the UI (until they transition to another screen).
+     */
+    private boolean mFrozen = false;
+
+    /**
+     * If the user is currently dragging something.
+     */
+    private int mGrabbedState = NOTHING_GRABBED;
+    private static final int NOTHING_GRABBED = 0;
+    private static final int LEFT_HANDLE_GRABBED = 1;
+    private static final int RIGHT_HANDLE_GRABBED = 2;
+
+    /**
+     * Whether the user has triggered something (e.g dragging the left handle all the way over to
+     * the right).
+     */
+    private boolean mTriggered = false;
+
+    // Vibration (haptic feedback)
+    private Vibrator mVibrator;
+    private static final long VIBRATE_SHORT = 60;  // msec
+    private static final long VIBRATE_LONG = 100;  // msec
+
+    /**
+     * The drawable for the arrows need to be scrunched this many dips towards the rotary bg below
+     * it.
+     */
+    private static final int ARROW_SCRUNCH_DIP = 6;
+
+    /**
+     * How far inset the left and right circles should be
+     */
+    private static final int EDGE_PADDING_DIP = 9;
+
+    /**
+     * Dimensions of arc in background drawable.
+     */
+    static final int OUTER_ROTARY_RADIUS_DIP = 390;
+    static final int ROTARY_STROKE_WIDTH_DIP = 83;
+    private static final int ANIMATION_DURATION_MILLIS = 300;
+
+    private static final boolean DRAW_CENTER_DIMPLE = false;
+
+    public RotarySelector(Context context) {
+        this(context, null);
+    }
+
+
+    /**
+     * Constructor used when this widget is created from a layout file.
+     */
+    public RotarySelector(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        if (DBG) log("IncomingCallDialWidget constructor...");
+
+        Resources r = getResources();
+        mDensity = r.getDisplayMetrics().density;
+        if (DBG) log("- Density: " + mDensity);
+
+        // Assets (all are BitmapDrawables).
+        mBackground = r.getDrawable(R.drawable.jog_dial_bg_cropped);
+        mDimple = r.getDrawable(R.drawable.jog_dial_dimple);
+
+        mArrowLongLeft = r.getDrawable(R.drawable.jog_dial_arrow_long_left_green);
+        mArrowLongRight = r.getDrawable(R.drawable.jog_dial_arrow_long_right_red);
+        mArrowShortLeftAndRight = r.getDrawable(R.drawable.jog_dial_arrow_short_left_and_right);
+
+        // Arrows:
+        // All arrow assets are the same size (they're the full width of
+        // the screen) regardless of which arrows are actually visible.
+        int arrowW = mArrowShortLeftAndRight.getIntrinsicWidth();
+        int arrowH = mArrowShortLeftAndRight.getIntrinsicHeight();
+        mArrowShortLeftAndRight.setBounds(0, 0, arrowW, arrowH);
+        mArrowLongLeft.setBounds(0, 0, arrowW, arrowH);
+        mArrowLongRight.setBounds(0, 0, arrowW, arrowH);
+
+        mInterpolator = new AccelerateInterpolator();
+    }
+
+    /**
+     * Sets the left handle icon to a given resource.
+     *
+     * The resource should refer to a Drawable object, or use 0 to remove
+     * the icon.
+     *
+     * @param resId the resource ID.
+     */
+    public void setLeftHandleResource(int resId) {
+        Drawable d = null;
+        if (resId != 0) {
+            d = getResources().getDrawable(resId);
+        }
+        setLeftHandleDrawable(d);
+    }
+
+    /**
+     * Sets the left handle icon to a given Drawable.
+     *
+     * @param d the Drawable to use as the icon, or null to remove the icon.
+     */
+    public void setLeftHandleDrawable(Drawable d) {
+        mLeftHandleIcon = d;
+        invalidate();
+    }
+
+    /**
+     * Sets the right handle icon to a given resource.
+     *
+     * The resource should refer to a Drawable object, or use 0 to remove
+     * the icon.
+     *
+     * @param resId the resource ID.
+     */
+    public void setRightHandleResource(int resId) {
+        Drawable d = null;
+        if (resId != 0) {
+            d = getResources().getDrawable(resId);
+        }
+        setRightHandleDrawable(d);
+    }
+
+    /**
+     * Sets the right handle icon to a given Drawable.
+     *
+     * @param d the Drawable to use as the icon, or null to remove the icon.
+     */
+    public void setRightHandleDrawable(Drawable d) {
+        mRightHandleIcon = d;
+        invalidate();
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        final int width = MeasureSpec.getSize(widthMeasureSpec);  // screen width
+
+        final int arrowH = mArrowShortLeftAndRight.getIntrinsicHeight();
+        final int backgroundH = mBackground.getIntrinsicHeight();
+
+        // by making the height less than arrow + bg, arrow and bg will be scrunched together,
+        // overlaying somewhat (though on transparent portions of the drawable).
+        // this works because the arrows are drawn from the top, and the rotary bg is drawn
+        // from the bottom.
+        final int arrowScrunch = (int) (ARROW_SCRUNCH_DIP * mDensity);
+        setMeasuredDimension(width, backgroundH + arrowH - arrowScrunch);
+    }
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+
+        mLeftHandleX = (int) (EDGE_PADDING_DIP * mDensity) + mDimple.getIntrinsicWidth() / 2;
+        mRightHandleX =
+                getWidth() - (int) (EDGE_PADDING_DIP * mDensity) - mDimple.getIntrinsicWidth() / 2;
+    }
+
+//    private Paint mPaint = new Paint();
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+        if (DBG) {
+            log(String.format("onDraw: mAnimating=%s, mTouchDragOffset=%d, mGrabbedState=%d," +
+                    "mFrozen=%s",
+                    mAnimating, mTouchDragOffset, mGrabbedState, mFrozen));
+        }
+
+        final int height = getHeight();
+
+        // update animating state before we draw anything
+        if (mAnimating && !mFrozen) {
+            long millisLeft = mAnimationEndTime - currentAnimationTimeMillis();
+            if (DBG) log("millisleft for animating: " + millisLeft);
+            if (millisLeft <= 0) {
+                reset();
+            } else {
+                float interpolation = mInterpolator.getInterpolation(
+                        (float) millisLeft / ANIMATION_DURATION_MILLIS);
+                mTouchDragOffset = (int) (mAnimatingDelta * interpolation);
+            }
+        }
+
+
+        // Background:
+        final int backgroundW = mBackground.getIntrinsicWidth();
+        final int backgroundH = mBackground.getIntrinsicHeight();
+        final int backgroundY = height - backgroundH;
+        if (DBG) log("- Background INTRINSIC: " + backgroundW + " x " + backgroundH);
+        mBackground.setBounds(0, backgroundY,
+                              backgroundW, backgroundY + backgroundH);
+        if (DBG) log("  Background BOUNDS: " + mBackground.getBounds());
+        mBackground.draw(canvas);
+
+
+        // Draw the correct arrow(s) depending on the current state:
+        Drawable currentArrow;
+        switch (mGrabbedState) {
+            case NOTHING_GRABBED:
+                currentArrow  = mArrowShortLeftAndRight;
+                break;
+            case LEFT_HANDLE_GRABBED:
+                currentArrow = mArrowLongLeft;
+                break;
+            case RIGHT_HANDLE_GRABBED:
+                currentArrow = mArrowLongRight;
+                break;
+            default:
+                throw new IllegalStateException("invalid mGrabbedState: " + mGrabbedState);
+        }
+        currentArrow.draw(canvas);
+
+        // debug: draw circle that should match the outer arc (good sanity check)
+//        mPaint.setColor(Color.RED);
+//        mPaint.setStyle(Paint.Style.STROKE);
+//        float or = OUTER_ROTARY_RADIUS_DIP * mDensity;
+//        canvas.drawCircle(getWidth() / 2, or + mBackground.getBounds().top, or, mPaint);
+
+        final int outerRadius = (int) (mDensity * OUTER_ROTARY_RADIUS_DIP);
+        final int innerRadius =
+                (int) ((OUTER_ROTARY_RADIUS_DIP - ROTARY_STROKE_WIDTH_DIP) * mDensity);
+        final int bgTop = mBackground.getBounds().top;
+        {
+            final int xOffset = mLeftHandleX + mTouchDragOffset;
+            final int drawableY = getYOnArc(
+                    mBackground,
+                    innerRadius,
+                    outerRadius,
+                    xOffset);
+
+            drawCentered(mDimple, canvas, xOffset, drawableY + bgTop);
+            drawCentered(mLeftHandleIcon, canvas, xOffset, drawableY + bgTop);
+        }
+
+        if (DRAW_CENTER_DIMPLE) {
+            final int xOffset = getWidth() / 2 + mTouchDragOffset;
+            final int drawableY = getYOnArc(
+                    mBackground,
+                    innerRadius,
+                    outerRadius,
+                    xOffset);
+
+            drawCentered(mDimple, canvas, xOffset, drawableY + bgTop);
+        }
+
+        {
+            final int xOffset = mRightHandleX + mTouchDragOffset;
+            final int drawableY = getYOnArc(
+                    mBackground,
+                    innerRadius,
+                    outerRadius,
+                    xOffset);
+
+            drawCentered(mDimple, canvas, xOffset, drawableY + bgTop);
+            drawCentered(mRightHandleIcon, canvas, xOffset, drawableY + bgTop);
+        }
+
+        if (mAnimating) invalidate();
+    }
+
+    /**
+     * Assuming drawable is a bounding box around a piece of an arc drawn by two concentric circles
+     * (as the background drawable for the rotary widget is), and given an x coordinate along the
+     * drawable, return the y coordinate of a point on the arc that is between the two concentric
+     * circles.  The resulting y combined with the incoming x is a point along the circle in
+     * between the two concentric circles.
+     *
+     * @param drawable The drawable.
+     * @param innerRadius The radius of the circle that intersects the drawable at the bottom two
+     *        corders of the drawable (top two corners in terms of drawing coordinates).
+     * @param outerRadius The radius of the circle who's top most point is the top center of the
+     *        drawable (bottom center in terms of drawing coordinates).
+     * @param x The distance along the x axis of the desired point.
+     * @return The y coordinate, in drawing coordinates, that will place (x, y) along the circle
+     *        in between the two concentric circles.
+     */
+    private int getYOnArc(Drawable drawable, int innerRadius, int outerRadius, int x) {
+
+        // the hypotenuse
+        final int halfWidth = (outerRadius - innerRadius) / 2;
+        final int middleRadius = innerRadius + halfWidth;
+
+        // the bottom leg of the triangle
+        final int triangleBottom = (drawable.getIntrinsicWidth() / 2) - x;
+
+        // "Our offense is like the pythagorean theorem: There is no answer!" - Shaquille O'Neal
+        final int triangleY =
+                (int) Math.sqrt(middleRadius * middleRadius - triangleBottom * triangleBottom);
+
+        // convert to drawing coordinates:
+        // middleRadius - triangleY =
+        //   the vertical distance from the outer edge of the circle to the desired point
+        // from there we add the distance from the top of the drawable to the middle circle
+        return middleRadius - triangleY + halfWidth;
+    }
+
+    /**
+     * Handle touch screen events.
+     *
+     * @param event The motion event.
+     * @return True if the event was handled, false otherwise.
+     */
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        if (mAnimating || mFrozen) {
+            return true;
+        }
+
+        final int eventX = (int) event.getX();
+        final int hitWindow = mDimple.getIntrinsicWidth();
+
+        final int action = event.getAction();
+        switch (action) {
+            case MotionEvent.ACTION_DOWN:
+                if (DBG) log("touch-down");
+                mTriggered = false;
+                if (mGrabbedState != NOTHING_GRABBED) {
+                    reset();
+                    invalidate();
+                }
+                if (eventX < mLeftHandleX + hitWindow) {
+                    mTouchDragOffset = eventX - mLeftHandleX;
+                    mGrabbedState = LEFT_HANDLE_GRABBED;
+                    invalidate();
+                    vibrate(VIBRATE_SHORT);
+                } else if (eventX > mRightHandleX - hitWindow) {
+                    mTouchDragOffset = eventX - mRightHandleX;
+                    mGrabbedState = RIGHT_HANDLE_GRABBED;
+                    invalidate();
+                    vibrate(VIBRATE_SHORT);
+                }
+                break;
+
+            case MotionEvent.ACTION_MOVE:
+                if (DBG) log("touch-move");
+                if (mGrabbedState == LEFT_HANDLE_GRABBED) {
+                    mTouchDragOffset = eventX - mLeftHandleX;
+                    invalidate();
+                    if (eventX >= mRightHandleX - EDGE_PADDING_DIP && !mTriggered) {
+                        mTriggered = true;
+                        mFrozen = dispatchTriggerEvent(OnDialTriggerListener.LEFT_HANDLE);
+                    }
+                } else if (mGrabbedState == RIGHT_HANDLE_GRABBED) {
+                    mTouchDragOffset = eventX - mRightHandleX;
+                    invalidate();
+                    if (eventX <= mLeftHandleX + EDGE_PADDING_DIP && !mTriggered) {
+                        mTriggered = true;
+                        mFrozen = dispatchTriggerEvent(OnDialTriggerListener.RIGHT_HANDLE);
+                    }
+                }
+                break;
+            case MotionEvent.ACTION_UP:
+                if (DBG) log("touch-up");
+                // handle animating back to start if they didn't trigger
+                if (mGrabbedState == LEFT_HANDLE_GRABBED
+                        && Math.abs(eventX - mLeftHandleX) > 5) {
+                    mAnimating = true;
+                    mAnimationEndTime = currentAnimationTimeMillis() + ANIMATION_DURATION_MILLIS;
+                    mAnimatingDelta = eventX - mLeftHandleX;
+                } else if (mGrabbedState == RIGHT_HANDLE_GRABBED
+                        && Math.abs(eventX - mRightHandleX) > 5) {
+                    mAnimating = true;
+                    mAnimationEndTime = currentAnimationTimeMillis() + ANIMATION_DURATION_MILLIS;
+                    mAnimatingDelta = eventX - mRightHandleX;
+                }
+
+                mTouchDragOffset = 0;
+                mGrabbedState = NOTHING_GRABBED;
+                invalidate();
+                break;
+            case MotionEvent.ACTION_CANCEL:
+                if (DBG) log("touch-cancel");
+                reset();
+                invalidate();
+                break;
+        }
+        return true;
+    }
+
+    private void reset() {
+        mAnimating = false;
+        mTouchDragOffset = 0;
+        mGrabbedState = NOTHING_GRABBED;
+        mTriggered = false;
+    }
+
+    /**
+     * Triggers haptic feedback.
+     */
+    private synchronized void vibrate(long duration) {
+        if (mVibrator == null) {
+            mVibrator = (android.os.Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
+        }
+        mVibrator.vibrate(duration);
+    }
+
+    /**
+     * Sets the bounds of the specified Drawable so that it's centered
+     * on the point (x,y), then draws it onto the specified canvas.
+     * TODO: is there already a utility method somewhere for this?
+     */
+    private static void drawCentered(Drawable d, Canvas c, int x, int y) {
+        int w = d.getIntrinsicWidth();
+        int h = d.getIntrinsicHeight();
+
+        // if (DBG) log("--> drawCentered: " + x + " , " + y + "; intrinsic " + w + " x " + h);
+        d.setBounds(x - (w / 2), y - (h / 2),
+                    x + (w / 2), y + (h / 2));
+        d.draw(c);
+    }
+
+
+    /**
+     * Registers a callback to be invoked when the dial
+     * is "triggered" by rotating it one way or the other.
+     *
+     * @param l the OnDialTriggerListener to attach to this view
+     */
+    public void setOnDialTriggerListener(OnDialTriggerListener l) {
+        mOnDialTriggerListener = l;
+    }
+
+    /**
+     * Dispatches a trigger event to our listener.
+     */
+    private boolean dispatchTriggerEvent(int whichHandle) {
+        vibrate(VIBRATE_LONG);
+        if (mOnDialTriggerListener != null) {
+            return mOnDialTriggerListener.onDialTrigger(this, whichHandle);
+        }
+        return false;
+    }
+
+    /**
+     * Interface definition for a callback to be invoked when the dial
+     * is "triggered" by rotating it one way or the other.
+     */
+    public interface OnDialTriggerListener {
+        /**
+         * The dial was triggered because the user grabbed the left handle,
+         * and rotated the dial clockwise.
+         */
+        public static final int LEFT_HANDLE = 1;
+
+        /**
+         * The dial was triggered because the user grabbed the right handle,
+         * and rotated the dial counterclockwise.
+         */
+        public static final int RIGHT_HANDLE = 2;
+
+        /**
+         * @hide
+         * The center handle is currently unused.
+         */
+        public static final int CENTER_HANDLE = 3;
+
+        /**
+         * Called when the dial is triggered.
+         *
+         * @param v The view that was triggered
+         * @param whichHandle  Which "dial handle" the user grabbed,
+         *        either {@link #LEFT_HANDLE}, {@link #RIGHT_HANDLE}, or
+         *        {@link #CENTER_HANDLE}.
+         * @return Whether the widget should freeze (e.g when the action goes to another screen,
+         *         you want the UI to stay put until the transition occurs).
+         */
+        boolean onDialTrigger(View v, int whichHandle);
+    }
+
+
+    // Debugging / testing code
+
+    private void log(String msg) {
+        Log.d(LOG_TAG, msg);
+    }
+}
diff --git a/core/jni/android_server_BluetoothA2dpService.cpp b/core/jni/android_server_BluetoothA2dpService.cpp
index a185d8d..ba13519 100644
--- a/core/jni/android_server_BluetoothA2dpService.cpp
+++ b/core/jni/android_server_BluetoothA2dpService.cpp
@@ -133,23 +133,13 @@
     LOGV(__FUNCTION__);
     if (nat) {
         const char *c_path = env->GetStringUTFChars(path, NULL);
-        DBusError err;
-        dbus_error_init(&err);
 
-        DBusMessage *reply =
-                dbus_func_args_timeout(env, nat->conn, -1, c_path,
-                               "org.bluez.AudioSink", "Connect",
-                                DBUS_TYPE_INVALID);
+        bool ret = dbus_func_args_async(env, nat->conn, -1, NULL, NULL, nat,
+                                    c_path, "org.bluez.AudioSink", "Connect",
+                                    DBUS_TYPE_INVALID);
+
         env->ReleaseStringUTFChars(path, c_path);
-
-        if (!reply && dbus_error_is_set(&err)) {
-            LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
-            return JNI_FALSE;
-        } else if (!reply) {
-            LOGE("DBus reply is NULL in function %s", __FUNCTION__);
-            return JNI_FALSE;
-        }
-        return JNI_TRUE;
+        return ret ? JNI_TRUE : JNI_FALSE;
     }
 #endif
     return JNI_FALSE;
@@ -161,23 +151,13 @@
     LOGV(__FUNCTION__);
     if (nat) {
         const char *c_path = env->GetStringUTFChars(path, NULL);
-        DBusError err;
-        dbus_error_init(&err);
 
-        DBusMessage *reply =
-              dbus_func_args_timeout(env, nat->conn, -1, c_path,
-                                     "org.bluez.AudioSink", "Disconnect",
-                                     DBUS_TYPE_INVALID);
+        bool ret = dbus_func_args_async(env, nat->conn, -1, NULL, NULL, nat,
+                                    c_path, "org.bluez.AudioSink", "Disconnect",
+                                    DBUS_TYPE_INVALID);
+
         env->ReleaseStringUTFChars(path, c_path);
-
-        if (!reply && dbus_error_is_set(&err)) {
-            LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
-            return JNI_FALSE;
-        } else if (!reply) {
-            LOGE("DBus reply is NULL in function %s", __FUNCTION__);
-            return JNI_FALSE;
-        }
-        return JNI_TRUE;
+        return ret ? JNI_TRUE : JNI_FALSE;
     }
 #endif
     return JNI_FALSE;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 53e0125..c4536be 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -52,6 +52,23 @@
     <protected-broadcast android:name="android.intent.action.NEW_OUTGOING_CALL" />
     <protected-broadcast android:name="android.intent.action.REBOOT" />
 
+    <protected-broadcast android:name="android.bluetooth.adapter.action.STATE_CHANGED" />
+    <protected-broadcast android:name="android.bluetooth.adapter.action.SCAN_MODE_CHANGED" />
+    <protected-broadcast android:name="android.bluetooth.adapter.action.DISCOVERY_STARTED" />
+    <protected-broadcast android:name="android.bluetooth.adapter.action.DISCOVERY_FINISHED" />
+    <protected-broadcast android:name="android.bluetooth.adapter.action.LOCAL_NAME_CHANGED" />
+    <protected-broadcast android:name="android.bluetooth.device.action.FOUND" />
+    <protected-broadcast android:name="android.bluetooth.device.action.DISAPPEARED" />
+    <protected-broadcast android:name="android.bluetooth.device.action.CLASS_CHANGED" />
+    <protected-broadcast android:name="android.bluetooth.device.action.ACL_CONNECTED" />
+    <protected-broadcast android:name="android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED" />
+    <protected-broadcast android:name="android.bluetooth.device.action.ACL_DISCONNECTED" />
+    <protected-broadcast android:name="android.bluetooth.device.action.NAME_CHANGED" />
+    <protected-broadcast android:name="android.bluetooth.device.action.BOND_STATE_CHANGED" />
+    <protected-broadcast android:name="android.bluetooth.device.action.NAME_FAILED" />
+    <protected-broadcast android:name="android.bluetooth.device.action.PAIRING_REQUEST" />
+    <protected-broadcast android:name="android.bluetooth.device.action.PAIRING_CANCEL" />
+
     <!-- ====================================== -->
     <!-- Permissions for things that cost money -->
     <!-- ====================================== -->
diff --git a/core/res/res/drawable-hdpi/ic_emergency.png b/core/res/res/drawable-hdpi/ic_emergency.png
index a2dd372..b4465ff 100644
--- a/core/res/res/drawable-hdpi/ic_emergency.png
+++ b/core/res/res/drawable-hdpi/ic_emergency.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/title_bar_medium.png b/core/res/res/drawable-hdpi/title_bar_medium.png
new file mode 100644
index 0000000..c13dd26
--- /dev/null
+++ b/core/res/res/drawable-hdpi/title_bar_medium.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/title_bar_medium.png b/core/res/res/drawable-mdpi/title_bar_medium.png
new file mode 100644
index 0000000..9d01f79
--- /dev/null
+++ b/core/res/res/drawable-mdpi/title_bar_medium.png
Binary files differ
diff --git a/core/res/res/drawable/ic_jog_dial_answer.png b/core/res/res/drawable/ic_jog_dial_answer.png
new file mode 100644
index 0000000..e2bc483
--- /dev/null
+++ b/core/res/res/drawable/ic_jog_dial_answer.png
Binary files differ
diff --git a/core/res/res/drawable/ic_jog_dial_decline.png b/core/res/res/drawable/ic_jog_dial_decline.png
new file mode 100644
index 0000000..81c76b5
--- /dev/null
+++ b/core/res/res/drawable/ic_jog_dial_decline.png
Binary files differ
diff --git a/core/res/res/drawable/ic_jog_dial_silence_ringer.png b/core/res/res/drawable/ic_jog_dial_silence_ringer.png
new file mode 100644
index 0000000..6d573e6
--- /dev/null
+++ b/core/res/res/drawable/ic_jog_dial_silence_ringer.png
Binary files differ
diff --git a/core/res/res/drawable/ic_jog_dial_turn_ring_vol_off.png b/core/res/res/drawable/ic_jog_dial_turn_ring_vol_off.png
new file mode 100644
index 0000000..3804c25
--- /dev/null
+++ b/core/res/res/drawable/ic_jog_dial_turn_ring_vol_off.png
Binary files differ
diff --git a/core/res/res/drawable/ic_jog_dial_turn_ring_vol_on.png b/core/res/res/drawable/ic_jog_dial_turn_ring_vol_on.png
new file mode 100644
index 0000000..62f8e15
--- /dev/null
+++ b/core/res/res/drawable/ic_jog_dial_turn_ring_vol_on.png
Binary files differ
diff --git a/core/res/res/drawable/ic_jog_dial_unlock.png b/core/res/res/drawable/ic_jog_dial_unlock.png
new file mode 100644
index 0000000..e697d91
--- /dev/null
+++ b/core/res/res/drawable/ic_jog_dial_unlock.png
Binary files differ
diff --git a/core/res/res/drawable/jog_dial_arrow_long_left_green.png b/core/res/res/drawable/jog_dial_arrow_long_left_green.png
new file mode 100644
index 0000000..334a8e0
--- /dev/null
+++ b/core/res/res/drawable/jog_dial_arrow_long_left_green.png
Binary files differ
diff --git a/core/res/res/drawable/jog_dial_arrow_long_left_yellow.png b/core/res/res/drawable/jog_dial_arrow_long_left_yellow.png
new file mode 100644
index 0000000..2e011ca3
--- /dev/null
+++ b/core/res/res/drawable/jog_dial_arrow_long_left_yellow.png
Binary files differ
diff --git a/core/res/res/drawable/jog_dial_arrow_long_middle_yellow.png b/core/res/res/drawable/jog_dial_arrow_long_middle_yellow.png
new file mode 100644
index 0000000..323745e
--- /dev/null
+++ b/core/res/res/drawable/jog_dial_arrow_long_middle_yellow.png
Binary files differ
diff --git a/core/res/res/drawable/jog_dial_arrow_long_right_red.png b/core/res/res/drawable/jog_dial_arrow_long_right_red.png
new file mode 100644
index 0000000..1e97c9a
--- /dev/null
+++ b/core/res/res/drawable/jog_dial_arrow_long_right_red.png
Binary files differ
diff --git a/core/res/res/drawable/jog_dial_arrow_long_right_yellow.png b/core/res/res/drawable/jog_dial_arrow_long_right_yellow.png
new file mode 100644
index 0000000..3536e58
--- /dev/null
+++ b/core/res/res/drawable/jog_dial_arrow_long_right_yellow.png
Binary files differ
diff --git a/core/res/res/drawable/jog_dial_arrow_short_left.png b/core/res/res/drawable/jog_dial_arrow_short_left.png
new file mode 100644
index 0000000..4a4ab3ae
--- /dev/null
+++ b/core/res/res/drawable/jog_dial_arrow_short_left.png
Binary files differ
diff --git a/core/res/res/drawable/jog_dial_arrow_short_left_and_right.png b/core/res/res/drawable/jog_dial_arrow_short_left_and_right.png
new file mode 100644
index 0000000..987cfa7
--- /dev/null
+++ b/core/res/res/drawable/jog_dial_arrow_short_left_and_right.png
Binary files differ
diff --git a/core/res/res/drawable/jog_dial_arrow_short_right.png b/core/res/res/drawable/jog_dial_arrow_short_right.png
new file mode 100644
index 0000000..ee79875
--- /dev/null
+++ b/core/res/res/drawable/jog_dial_arrow_short_right.png
Binary files differ
diff --git a/core/res/res/drawable/jog_dial_bg_cropped.png b/core/res/res/drawable/jog_dial_bg_cropped.png
new file mode 100644
index 0000000..60d93d2
--- /dev/null
+++ b/core/res/res/drawable/jog_dial_bg_cropped.png
Binary files differ
diff --git a/core/res/res/drawable/jog_dial_dimple.png b/core/res/res/drawable/jog_dial_dimple.png
new file mode 100644
index 0000000..85d3a43
--- /dev/null
+++ b/core/res/res/drawable/jog_dial_dimple.png
Binary files differ
diff --git a/core/res/res/layout/contact_header.xml b/core/res/res/layout/contact_header.xml
index 8d7e470..e800dfa 100644
--- a/core/res/res/layout/contact_header.xml
+++ b/core/res/res/layout/contact_header.xml
@@ -19,17 +19,17 @@
     android:layout_width="fill_parent"
     android:layout_height="wrap_content"
     android:orientation="horizontal"
-    android:background="@drawable/title_bar_tall"
+    android:background="@drawable/title_bar_medium"
     android:paddingRight="5dip"
     android:gravity="center_vertical">
     
-    <ImageView android:id="@+id/photo"
-        android:layout_width="56dip"
-        android:layout_height="62dip"
+    <android.widget.FasttrackBadgeWidget android:id="@+id/photo"
+        android:layout_alignParentLeft="true"
+        android:layout_centerVertical="true"
         android:layout_marginRight="10dip"
         android:layout_marginLeft="10dip"
-        android:scaleType="fitCenter"
-        android:background="@drawable/fasttrack_badge_middle_large"/>
+        style="@*android:style/Widget.FasttrackBadgeWidget.WindowSmall" />
+    />
     
     <LinearLayout
         android:layout_width="0dip"
diff --git a/core/res/res/layout/keyguard_screen_rotary_unlock.xml b/core/res/res/layout/keyguard_screen_rotary_unlock.xml
new file mode 100644
index 0000000..cf97d04
--- /dev/null
+++ b/core/res/res/layout/keyguard_screen_rotary_unlock.xml
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License")
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- This is the general lock screen which shows information about the
+  state of the device, as well as instructions on how to get past it
+  depending on the state of the device.  It is the same for landscape
+  and portrait.-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+             android:layout_width="fill_parent"
+             android:layout_height="fill_parent"
+             android:id="@+id/root"
+                 >
+
+<RelativeLayout
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:background="#A0000000"
+        >
+
+    <TextView
+        android:id="@+id/carrier"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentTop="true"
+        android:layout_centerHorizontal="true"
+        android:layout_marginTop="20dip"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:textColor="?android:attr/textColorSecondary"
+        />
+
+    <TextView
+        android:id="@+id/time"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/carrier"
+        android:layout_centerHorizontal="true"
+        android:layout_marginTop="25dip"
+        android:textAppearance="?android:attr/textAppearanceLarge"
+        android:textSize="55sp"
+        />
+
+    <TextView
+        android:id="@+id/date"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/time"
+        android:layout_centerHorizontal="true"
+        android:layout_marginTop="-12dip"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        />
+
+    <View
+        android:id="@+id/divider"
+        android:layout_width="fill_parent"
+        android:layout_height="1dip"
+        android:layout_marginTop="10dip"
+        android:layout_below="@id/date"
+        android:background="@android:drawable/divider_horizontal_dark"
+            />
+
+    <TextView
+        android:id="@+id/status1"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/divider"
+        android:layout_centerHorizontal="true"
+        android:layout_marginTop="6dip"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:textColor="?android:attr/textColorSecondary"
+        />
+
+    <TextView
+        android:id="@+id/status2"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/status1"
+        android:layout_centerHorizontal="true"
+        android:layout_marginTop="6dip"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:textColor="?android:attr/textColorSecondary"
+        />
+
+    <TextView
+        android:id="@+id/screenLocked"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/status2"
+        android:layout_centerHorizontal="true"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:textColor="?android:attr/textColorSecondary"
+        android:gravity="center"
+        android:layout_marginTop="12dip"
+        />
+
+    <!-- By having the rotary selector hang below "screen locked" text, we get a layout more
+         robust for different screen sizes.  On wvga, the widget should be flush with the bottom.-->
+    <com.android.internal.widget.RotarySelector
+        android:id="@+id/rotary"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/screenLocked"
+        android:layout_centerHorizontal="true"
+        android:layout_marginTop="24dip"
+        />
+
+    <!-- emergency call button shown when sim is missing or PUKd -->
+    <Button
+        android:id="@+id/emergencyCallButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/screenLocked"
+        android:layout_centerHorizontal="true"
+        android:layout_marginTop="24dip"
+        android:drawableLeft="@drawable/ic_emergency"
+        android:drawablePadding="8dip"
+       />
+
+</RelativeLayout>
+
+</FrameLayout>
\ No newline at end of file
diff --git a/core/res/res/layout/keyguard_screen_unlock_landscape.xml b/core/res/res/layout/keyguard_screen_unlock_landscape.xml
index 929d0a2..6dd2949 100644
--- a/core/res/res/layout/keyguard_screen_unlock_landscape.xml
+++ b/core/res/res/layout/keyguard_screen_unlock_landscape.xml
@@ -21,7 +21,8 @@
      the user how to unlock their device, or make an emergency call.  This
      is the portrait layout.  -->
 
-<com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient
+    xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="horizontal"
     android:layout_width="fill_parent"
     android:layout_height="fill_parent"
@@ -34,31 +35,70 @@
             android:layout_width="0dip"
             android:layout_height="fill_parent"
             android:layout_weight="1.0"
+            android:gravity="center_horizontal"
             >
+        <TextView
+            android:id="@+id/carrier"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="5dip"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="?android:attr/textColorSecondary"
+            />
+        <TextView
+            android:id="@+id/centerDot"
+            android:visibility="gone"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="5dip"
+            android:layout_marginRight="5dip"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="?android:attr/textColorSecondary"
+            android:textSize="17sp"
+            />
+        <TextView
+            android:id="@+id/time"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_centerHorizontal="true"
+            android:layout_marginTop="5dip"
+            android:textAppearance="?android:attr/textAppearanceLarge"
+            android:textSize="35sp"
+            />
+        <TextView
+            android:id="@+id/date"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentTop="true"
+            android:layout_marginTop="-12dip"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="?android:attr/textColorSecondary"
+            android:textSize="17sp"
+            />
 
-        <!-- lock icon next to header text -->
-        <LinearLayout
-                android:orientation="horizontal"
-                android:layout_width="fill_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginTop="3dip"
-                android:gravity="center"
-                >
-            <ImageView android:id="@+id/unlockLockIcon"
-                       android:layout_width="wrap_content"
-                       android:layout_height="wrap_content"
-                       android:layout_marginRight="3dip"
-                       android:baselineAligned="true"
-                       android:gravity="center"
-                       android:src="@android:drawable/ic_lock_idle_lock"
-                    />
 
-            <TextView android:id="@+id/headerText"
-                      android:layout_width="wrap_content"
-                      android:layout_height="wrap_content"
-                      android:gravity="center"
-                      android:textSize="18sp"/>
-        </LinearLayout>
+        <View
+            android:id="@+id/divider"
+            android:layout_width="fill_parent"
+            android:layout_height="1dip"
+            android:layout_centerHorizontal="true"
+            android:background="@android:drawable/divider_horizontal_dark"
+                />
+
+        <!-- lock icon and header message -->
+        <TextView
+            android:id="@+id/headerText"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="12dip"
+            android:layout_centerHorizontal="true"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="?android:attr/textColorSecondary"
+            android:textSize="17sp"
+            android:drawableLeft="@drawable/ic_lock_idle_lock"
+            android:drawablePadding="4dip"
+            android:gravity="center"
+            />
 
 
         <!-- fill space between header and button below -->
@@ -82,7 +122,7 @@
                 <Button android:id="@+id/emergencyCallAlone"
                     android:layout_width="fill_parent"
                     android:layout_height="wrap_content"
-                    android:text="@android:string/lockscreen_emergency_call"
+                    android:text="@string/lockscreen_emergency_call"
                     android:textSize="14sp"
                     android:drawableLeft="@drawable/ic_emergency"
                     android:drawablePadding="8dip"
@@ -105,7 +145,7 @@
                 <Button android:id="@+id/emergencyCallTogether"
                     android:layout_width="fill_parent"
                     android:layout_height="wrap_content"
-                    android:text="@android:string/lockscreen_emergency_call"
+                    android:text="@string/lockscreen_emergency_call"
                     android:textSize="14sp"
                     android:drawableLeft="@drawable/ic_emergency"
                     android:drawablePadding="8dip"
@@ -115,7 +155,7 @@
     </LinearLayout>
 
     <View
-         android:background="@android:drawable/code_lock_left"
+         android:background="@drawable/code_lock_left"
          android:layout_width="2dip"
          android:layout_height="fill_parent" />
 
@@ -124,4 +164,4 @@
          android:layout_width="wrap_content"
          android:layout_height="wrap_content" />
 
-</com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient>
+</com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient>
\ No newline at end of file
diff --git a/core/res/res/layout/keyguard_screen_unlock_portrait.xml b/core/res/res/layout/keyguard_screen_unlock_portrait.xml
index a6c31b6..a5d44fc 100644
--- a/core/res/res/layout/keyguard_screen_unlock_portrait.xml
+++ b/core/res/res/layout/keyguard_screen_unlock_portrait.xml
@@ -23,54 +23,93 @@
 <com.android.internal.widget.LinearLayoutWithDefaultTouchRecepient
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical"
-    android:layout_width="wrap_content"
+    android:layout_width="fill_parent"
     android:layout_height="fill_parent"
+    android:gravity="center_horizontal"
     android:background="#A0000000"
         >
 
-    <!-- lock icon and header message -->
     <LinearLayout
+        android:id="@+id/carrierAndDate"
         android:orientation="horizontal"
-        android:layout_width="fill_parent"
-        android:layout_height="0dip"
-        android:layout_weight="1.0"
-        android:gravity="center"
-            >
-
-        <ImageView android:id="@+id/unlockLockIcon"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="13dip"
+        >
+        <TextView
+            android:id="@+id/carrier"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_marginRight="6dip"
-            android:baselineAligned="true"
-            android:gravity="center"
-            android:src="@android:drawable/ic_lock_idle_lock"
-        />
-
-        <TextView android:id="@+id/headerText"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="?android:attr/textColorSecondary"
+            android:textSize="17sp"
+            />
+        <TextView
+            android:id="@+id/centerDot"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:gravity="center"
-            android:textSize="18sp"/>
+            android:layout_marginLeft="5dip"
+            android:layout_marginRight="5dip"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="?android:attr/textColorSecondary"
+            android:textSize="17sp"
+            />
+        <TextView
+            android:id="@+id/date"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentTop="true"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="?android:attr/textColorSecondary"
+            android:textSize="17sp"
+            />
     </LinearLayout>
 
+    <TextView
+        android:id="@+id/time"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_centerHorizontal="true"
+        android:layout_marginTop="-9dip"
+        android:textAppearance="?android:attr/textAppearanceLarge"
+        android:textSize="48sp"
+        />
+
     <View
-         android:background="@android:drawable/code_lock_top"
-         android:layout_width="fill_parent"
-         android:layout_height="2dip" />
-    <com.android.internal.widget.LockPatternView android:id="@+id/lockPattern"
-         android:layout_width="wrap_content"
-         android:layout_height="wrap_content"
+        android:id="@+id/divider"
+        android:layout_width="fill_parent"
+        android:layout_height="1dip"
+        android:layout_marginTop="-4dip"
+        android:layout_centerHorizontal="true"
+        android:background="@android:drawable/divider_horizontal_dark"
+            />
+
+    <!-- lock icon and header message -->
+    <TextView
+        android:id="@+id/headerText"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="3dip"
+        android:layout_centerHorizontal="true"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:textColor="?android:attr/textColorSecondary"
+        android:textSize="17sp"
+        android:drawableLeft="@drawable/ic_lock_idle_lock"
+        android:drawablePadding="4dip"
+        />
+
+    <com.android.internal.widget.LockPatternView
+        android:id="@+id/lockPattern"
+        android:layout_width="fill_parent"
+        android:layout_height="0dip"
+        android:layout_weight="1"
+        android:layout_marginTop="2dip"
          />
-    <View
-         android:background="@android:drawable/code_lock_bottom"
-         android:layout_width="fill_parent"
-         android:layout_height="8dip" />
 
     <!-- footer -->
     <FrameLayout
         android:layout_width="fill_parent"
-        android:layout_height="0dip"
-        android:layout_weight="1.0"
+        android:layout_height="wrap_content"
         >
 
         <!-- option 1: a single emergency call button -->
@@ -82,8 +121,8 @@
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_centerInParent="true"
-                android:text="@android:string/lockscreen_emergency_call"
-                android:textSize="14sp"
+                android:text="@string/lockscreen_emergency_call"
+                android:textAppearance="?android:attr/textAppearanceSmall"
                 android:drawableLeft="@drawable/ic_emergency"
                 android:drawablePadding="8dip"
                 />
@@ -105,8 +144,8 @@
                 android:layout_marginBottom="4dip"
                 android:layout_marginLeft="4dip"
                 android:layout_marginRight="2dip"
-                android:text="@android:string/lockscreen_emergency_call"
-                android:textSize="14sp"
+                android:text="@string/lockscreen_emergency_call"
+                android:textAppearance="?android:attr/textAppearanceSmall"
                 android:drawableLeft="@drawable/ic_emergency"
                 android:drawablePadding="8dip"
                 />
@@ -118,7 +157,7 @@
                 android:layout_marginBottom="4dip"
                 android:layout_marginLeft="2dip"
                 android:layout_marginRight="4dip"
-                android:textSize="14sp"
+                android:textAppearance="?android:attr/textAppearanceSmall"
                 android:visibility="invisible"
                 />
         </LinearLayout>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index a1a179b..eae838a 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -530,6 +530,11 @@
              lines, the IME should provide multiple lines if it can.  Corresponds to
              {@link android.text.InputType#TYPE_TEXT_FLAG_IME_MULTI_LINE}. -->
         <flag name="textImeMultiLine" value="0x00040001" />
+        <!-- Can be combined with <var>text</var> and its variations to
+             indicate that the IME should not show any
+             dictionary-based word suggestions.  Corresponds to
+             {@link android.text.InputType#TYPE_TEXT_FLAG_NO_SUGGESTIONS}. -->
+        <flag name="textNoSuggestions" value="0x00080001" />
         <!-- Text that will be used as a URI.  Corresponds to
              {@link android.text.InputType#TYPE_CLASS_TEXT} |
              {@link android.text.InputType#TYPE_TEXT_VARIATION_URI}. -->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 7aaf218..365363a 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -504,8 +504,10 @@
         <!-- The keyboard type has changed, for example the user has plugged
              in an external keyboard. -->
         <flag name="keyboard" value="0x0010" />
-        <!-- The keyboard accessibility has changed, for example the user has
-             slid the keyboard out to expose it. -->
+        <!-- The keyboard or navigation accessibility has changed, for example
+             the user has slid the keyboard out to expose it.  Note that
+             inspite of its name, this applied to any accessibility: keyboard
+             or navigation. -->
         <flag name="keyboardHidden" value="0x0020" />
         <!-- The navigation type has changed.  Should never normally happen. -->
         <flag name="navigation" value="0x0040" />
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 560796a..c967c4c 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -18,13 +18,20 @@
 */
 -->
 <resources>
-	<drawable name="screen_background_light">#fff9f9f9</drawable>
+	<drawable name="screen_background_light">#ffffffff</drawable>
 	<drawable name="screen_background_dark">#ff202020</drawable>
     <drawable name="status_bar_closed_default_background">#ff000000</drawable>
     <drawable name="status_bar_opened_default_background">#ff000000</drawable>
     <drawable name="search_bar_default_color">#ff000000</drawable>
     <drawable name="safe_mode_background">#60000000</drawable>
+    <!-- Background drawable that can be used for a transparent activity to
+         be able to display a dark UI: this darkens its background to make
+         a dark (default theme) UI more visible. -->
     <drawable name="screen_background_dark_transparent">#80000000</drawable>
+    <!-- Background drawable that can be used for a transparent activity to
+         be able to display a light UI: this lightens its background to make
+         a light UI more visible. -->
+    <drawable name="screen_background_light_transparent">#80ffffff</drawable>
     <color name="safe_mode_text">#80ffffff</color>
     <color name="white">#ffffffff</color>
     <color name="black">#ff000000</color>
@@ -38,7 +45,7 @@
     <color name="dim_foreground_dark_inverse">#323232</color>
     <color name="dim_foreground_dark_inverse_disabled">#80323232</color>
     <color name="hint_foreground_dark">#808080</color>
-    <color name="background_light">#fff9f9f9</color>
+    <color name="background_light">#ffffffff</color>
     <color name="bright_foreground_light">#ff000000</color>
     <color name="bright_foreground_light_inverse">#ffffffff</color>
     <color name="bright_foreground_light_disabled">#80000000</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 117e139..b710acb6 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -35,6 +35,9 @@
     <!-- The duration (in milliseconds) of a long animation. -->
     <integer name="config_longAnimTime">300</integer>
 
+    <!-- XXXXX NOTE THE FOLLOWING RESOURCES USE THE WRONG NAMING CONVENTION.
+         Please don't copy them, copy anything else. -->
+         
     <!-- This string array should be overridden by the device to present a list of network attributes.  This is used by the connectivity manager to decide which networks can coexist based on the hardward -->
     <!-- An Array of "[type-name],[associated radio-name],[priority]  -->
     <string-array translatable="false" name="networkAttributes">
@@ -53,18 +56,40 @@
         <item>"wifi,1,1"</item>
         <item>"mobile,0,1"</item>
     </string-array>
-
-    <!-- The number of degrees to rotate the display when the keyboard is open. -->
-    <integer name="config_lidOpenRotation">90</integer>
-
-    <!-- The number of degrees to rotate the display when the device is in a dock. -->
-    <integer name="config_dockedRotation">90</integer>
-
+    
     <!-- Flag indicating whether the keyguard should be bypassed when
          the slider is open.  This can be set or unset depending how easily
          the slider can be opened (for example, in a pocket or purse). -->
     <bool name="config_bypass_keyguard_if_slider_open">true</bool>
     
+    <!-- Flag indicating whether the device supports automatic brightness mode. -->
+    <bool name="config_automatic_brightness_available">false</bool>
+    
+    <!-- XXXXXX END OF RESOURCES USING WRONG NAMING CONVENTION -->
+
+    <!-- The number of degrees to rotate the display when the keyboard is open. -->
+    <integer name="config_lidOpenRotation">90</integer>
+
+    <!-- The number of degrees to rotate the display when the device is in a desk dock.
+         A value of -1 means no change in orientation by default. -->
+    <integer name="config_deskDockRotation">-1</integer>
+
+    <!-- The number of degrees to rotate the display when the device is in a car dock.
+         A value of -1 means no change in orientation by default. -->
+    <integer name="config_carDockRotation">-1</integer>
+
+    <!-- Indicate whether the lid state impacts the accessibility of
+         the physical keyboard.  0 means it doesn't, 1 means it is accessible
+         when the lid is open, 2 means it is accessible when the lid is
+         closed.  The default is 1. -->
+    <integer name="config_lidKeyboardAccessibility">1</integer>
+
+    <!-- Indicate whether the lid state impacts the accessibility of
+         the physical keyboard.  0 means it doesn't, 1 means it is accessible
+         when the lid is open, 2 means it is accessible when the lid is
+         closed.  The default is 0. -->
+    <integer name="config_lidNavigationAccessibility">0</integer>
+
     <!-- Vibrator pattern for feedback about a long screen/key press -->
     <integer-array name="config_longPressVibePattern">
         <item>0</item>
@@ -81,6 +106,4 @@
         <item>30</item>
     </integer-array>
     
-    <!-- Flag indicating whether the device supports automatic brightness mode. -->
-    <bool name="config_automatic_brightness_available">false</bool>
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index c4636f3..2bc2a0f 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1168,10 +1168,13 @@
   <public type="style" name="Theme.Wallpaper" />
   <public type="style" name="Theme.Wallpaper.NoTitleBar" />
   <public type="style" name="Theme.Wallpaper.NoTitleBar.Fullscreen" />
+  <public type="style" name="Theme.WallpaperSettings" />
+  <public type="style" name="Theme.Light.WallpaperSettings" />
   
   <!-- Semi-transparent background that can be used when placing a dark
        themed UI on top of some arbitrary background (such as the
        wallpaper).  This darkens the background sufficiently that the UI
        can be seen. -->
   <public type="drawable" name="screen_background_dark_transparent" />
+  <public type="drawable" name="screen_background_light_transparent" />
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 69ddd63..bd79c75 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1962,7 +1962,7 @@
     <string name="allow">Allow</string>
     <string name="deny">Deny</string>
     <string name="permission_request_notification_title">Permission Requested</string>
-    <string name="permission_request_notification_subtitle">for account <xliff:g id="account" example="foo@gmail.com">%s</xliff:g></string>
+    <string name="permission_request_notification_with_subtitle">Permission Requested\nfor account <xliff:g id="account" example="foo@gmail.com">%s</xliff:g></string>
 
     <!-- Label to show for a service that is running because it is an input method. -->
     <string name="input_method_binding_label">Input method</string>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index fae612c..69612e9 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -458,7 +458,6 @@
     
     <style name="Widget.ListView.White" parent="Widget.AbsListView">
         <item name="android:listSelector">@android:drawable/list_selector_background</item>
-        <item name="android:background">@android:color/white</item>
         <item name="android:divider">@android:drawable/divider_horizontal_bright_opaque</item>
     </style>    
 
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 4f76c56..1aa48ee 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -303,6 +303,32 @@
         <item name="android:windowContentOverlay">@null</item>
     </style>
 
+    <!-- Theme for a wallpaper's setting activity that is designed to be on
+         top of a dark background. -->
+    <style name="Theme.WallpaperSettings">
+        <item name="android:windowBackground">@android:drawable/screen_background_dark_transparent</item>
+        <item name="android:windowIsTranslucent">true</item>
+        <item name="android:windowAnimationStyle">@android:style/Animation.Translucent</item>
+    </style>
+
+    <!-- Theme for a wallpaper's setting activity that is designed to be on
+         top of a light background. -->
+    <style name="Theme.Light.WallpaperSettings">
+        <item name="android:windowBackground">@android:drawable/screen_background_light_transparent</item>
+        <item name="android:windowIsTranslucent">true</item>
+        <item name="android:windowAnimationStyle">@android:style/Animation.Translucent</item>
+    </style>
+
+    <!-- Style to apply on top of a wallpaper settings theme when it is being
+         shown on top of the real wallpaper -->
+    <style name="ActiveWallpaperSettings">
+    </style>
+    
+    <!-- Style to apply on top of a wallpaper settings theme when it is being
+         shown on top of the real wallpaper -->
+    <style name="PreviewWallpaperSettings">
+    </style>
+    
     <!-- Default theme for translucent activities, that is windows that allow you
          to see through them to the windows behind.  This sets up the translucent
          flag and appropriate animations for your windows.  -->
diff --git a/data/etc/Android.mk b/data/etc/Android.mk
index a32d8ea..041c5d3 100644
--- a/data/etc/Android.mk
+++ b/data/etc/Android.mk
@@ -32,3 +32,20 @@
 LOCAL_SRC_FILES := $(LOCAL_MODULE)
 
 include $(BUILD_PREBUILT)
+
+########################
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := required_hardware.xml
+
+LOCAL_MODULE_TAGS := user
+
+LOCAL_MODULE_CLASS := ETC
+
+# This will install the file in /system/etc/permissions
+#
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions
+
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+
+include $(BUILD_PREBUILT)
diff --git a/data/etc/android.hardware.camera.flash-autofocus.xml b/data/etc/android.hardware.camera.flash-autofocus.xml
new file mode 100644
index 0000000..55f1900
--- /dev/null
+++ b/data/etc/android.hardware.camera.flash-autofocus.xml
@@ -0,0 +1,23 @@
+<?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.
+-->
+
+<!-- This is the standard set of features for a camera with a flash.  Note
+     that this currently requires having auto-focus as well. -->
+<permissions>
+    <feature name="android.hardware.camera" />
+    <feature name="android.hardware.camera.autofocus" />
+    <feature name="android.hardware.camera.flash" />
+</permissions>
diff --git a/data/etc/android.hardware.sensor.light.xml b/data/etc/android.hardware.sensor.light.xml
new file mode 100644
index 0000000..78b0fec
--- /dev/null
+++ b/data/etc/android.hardware.sensor.light.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+
+<!-- Feature for devices with an ambient light sensor. -->
+<permissions>
+    <feature name="android.hardware.sensor.light" />
+</permissions>
diff --git a/data/etc/android.hardware.sensor.proximity.xml b/data/etc/android.hardware.sensor.proximity.xml
new file mode 100644
index 0000000..d1948de
--- /dev/null
+++ b/data/etc/android.hardware.sensor.proximity.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+
+<!-- Feature for devices with a proximity sensor. -->
+<permissions>
+    <feature name="android.hardware.sensor.proximity" />
+</permissions>
diff --git a/data/etc/android.hardware.telephony.cdma.xml b/data/etc/android.hardware.telephony.cdma.xml
new file mode 100644
index 0000000..72e0485
--- /dev/null
+++ b/data/etc/android.hardware.telephony.cdma.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+
+<!-- This is the standard set of features for a CDMA phone. -->
+<permissions>
+    <feature name="android.hardware.telephony" />
+    <feature name="android.hardware.telephony.cdma" />
+</permissions>
diff --git a/data/etc/android.hardware.telephony.gsm.xml b/data/etc/android.hardware.telephony.gsm.xml
new file mode 100644
index 0000000..ffde433
--- /dev/null
+++ b/data/etc/android.hardware.telephony.gsm.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+
+<!-- This is the standard set of features for a GSM phone. -->
+<permissions>
+    <feature name="android.hardware.telephony" />
+    <feature name="android.hardware.telephony.gsm" />
+</permissions>
diff --git a/data/etc/required_hardware.xml b/data/etc/required_hardware.xml
new file mode 100644
index 0000000..896a148
--- /dev/null
+++ b/data/etc/required_hardware.xml
@@ -0,0 +1,25 @@
+<?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.
+-->
+
+<!-- These are the hardware features that all devices must possess.
+     These are always added for you by the build system, you do not need
+     to add them yourself. -->
+<permissions>
+    <feature name="android.hardware.sensor.compass" />
+    <feature name="android.hardware.sensor.accelerometer" />
+    <feature name="android.hardware.bluetooth" />
+    <feature name="android.hardware.wifi" />
+</permissions>
diff --git a/docs/html/guide/topics/resources/resources-i18n.jd b/docs/html/guide/topics/resources/resources-i18n.jd
index 85b89d1..ff9579f 100755
--- a/docs/html/guide/topics/resources/resources-i18n.jd
+++ b/docs/html/guide/topics/resources/resources-i18n.jd
@@ -441,7 +441,7 @@
 <pre>
 MyApp/
     res/
-        drawable-en-rUS-large-long-port-mdpi-finger-keysexposed-qwerty-dpad-480x320/
+        drawable-en-rUS-large-long-port-mdpi-finger-keysexposed-qwerty-navexposed-dpad-480x320/
 </pre>
 
 <p>More typically, you will only specify a few specific configuration options. You may drop any of the values from the
@@ -575,6 +575,14 @@
         <td><code>nokeys</code>, <code>qwerty</code>, <code>12key</code> </td>
     </tr>
     <tr>
+        <td>Whether the navigation keys are available to the user</td>
+        <td><p><code>navexposed</code>, <code>navhidden</code>
+        </p><p>
+          If the hardware's navigation keys are currently available to
+          the user, the navexposed resources will be used; if they are not
+          available (such as behind a closed lid), navhidden will be used.</p></td>
+    </tr>
+    <tr>
         <td>Primary non-touchscreen<br />
             navigation method</td>
         <td><code>nonav</code>, <code>dpad</code>, <code>trackball</code>, <code>wheel</code> </td>
diff --git a/docs/html/sdk/1.0_r1/requirements.jd b/docs/html/sdk/1.0_r1/requirements.jd
index af06675..4163513 100644
--- a/docs/html/sdk/1.0_r1/requirements.jd
+++ b/docs/html/sdk/1.0_r1/requirements.jd
@@ -14,7 +14,13 @@
 <ul>
   <li>Windows XP or Vista</li>
   <li>Mac OS X 10.4.8 or later (x86 only)</li>
-  <li>Linux (tested on Linux Ubuntu Dapper Drake)</li>
+  <li>Linux (tested on Linux Ubuntu Dapper Drake)
+    <ul>
+      <li>64-bit distributions must be capable of running 32-bit applications. 
+      For information about how to add support for 32-bit applications, see
+      the <a href="installing.html#installnotes">Installation Notes</a>.</li>
+    </ul>
+  </li>
 </ul>
 
 <h4>Supported Development Environments:</h4>
diff --git a/docs/html/sdk/1.0_r2/requirements.jd b/docs/html/sdk/1.0_r2/requirements.jd
index 74d90ef..4f7c093 100644
--- a/docs/html/sdk/1.0_r2/requirements.jd
+++ b/docs/html/sdk/1.0_r2/requirements.jd
@@ -13,7 +13,13 @@
 <ul>
   <li>Windows XP or Vista</li>
   <li>Mac OS X 10.4.8 or later (x86 only)</li>
-  <li>Linux (tested on Linux Ubuntu Dapper Drake)</li>
+  <li>Linux (tested on Linux Ubuntu Dapper Drake)
+    <ul>
+      <li>64-bit distributions must be capable of running 32-bit applications. 
+      For information about how to add support for 32-bit applications, see
+      the <a href="installing.html#installnotes">Installation Notes</a>.</li>
+    </ul>
+  </li>
 </ul>
 
 <h4>Supported Development Environments:</h4>
diff --git a/docs/html/sdk/1.1_r1/requirements.jd b/docs/html/sdk/1.1_r1/requirements.jd
index 95b658b..9d8f9eb 100644
--- a/docs/html/sdk/1.1_r1/requirements.jd
+++ b/docs/html/sdk/1.1_r1/requirements.jd
@@ -11,7 +11,13 @@
 <ul>
   <li>Windows XP (32-bit) or Vista (32- or 64-bit)</li>
   <li>Mac OS X 10.4.8 or later (x86 only)</li>
-  <li>Linux (tested on Linux Ubuntu Dapper Drake)</li>
+  <li>Linux (tested on Linux Ubuntu Dapper Drake)
+    <ul>
+      <li>64-bit distributions must be capable of running 32-bit applications. 
+      For information about how to add support for 32-bit applications, see
+      the <a href="installing.html#installnotes">Installation Notes</a>.</li>
+    </ul>
+  </li>
 </ul>
 
 <h3>Supported Development Environments</h3>
diff --git a/docs/html/sdk/1.5_r1/requirements.jd b/docs/html/sdk/1.5_r1/requirements.jd
index 4ed38a7..c10ccac 100644
--- a/docs/html/sdk/1.5_r1/requirements.jd
+++ b/docs/html/sdk/1.5_r1/requirements.jd
@@ -7,7 +7,13 @@
 <ul>
   <li>Windows XP (32-bit) or Vista (32- or 64-bit)</li>
   <li>Mac OS X 10.4.8 or later (x86 only)</li>
-  <li>Linux (tested on Linux Ubuntu Dapper Drake)</li>
+  <li>Linux (tested on Linux Ubuntu Dapper Drake)
+    <ul>
+      <li>64-bit distributions must be capable of running 32-bit applications. 
+      For information about how to add support for 32-bit applications, see
+      the <a href="installing.html#InstallationNotes">Installation Notes</a>.</li>
+    </ul>
+  </li>
 </ul>
 
 <h3>Supported Development Environments</h3>
diff --git a/docs/html/sdk/1.5_r2/requirements.jd b/docs/html/sdk/1.5_r2/requirements.jd
index 4ed38a7..c10ccac 100644
--- a/docs/html/sdk/1.5_r2/requirements.jd
+++ b/docs/html/sdk/1.5_r2/requirements.jd
@@ -7,7 +7,13 @@
 <ul>
   <li>Windows XP (32-bit) or Vista (32- or 64-bit)</li>
   <li>Mac OS X 10.4.8 or later (x86 only)</li>
-  <li>Linux (tested on Linux Ubuntu Dapper Drake)</li>
+  <li>Linux (tested on Linux Ubuntu Dapper Drake)
+    <ul>
+      <li>64-bit distributions must be capable of running 32-bit applications. 
+      For information about how to add support for 32-bit applications, see
+      the <a href="installing.html#InstallationNotes">Installation Notes</a>.</li>
+    </ul>
+  </li>
 </ul>
 
 <h3>Supported Development Environments</h3>
diff --git a/docs/html/sdk/1.5_r3/requirements.jd b/docs/html/sdk/1.5_r3/requirements.jd
index 5f20cf1..5bcee27 100644
--- a/docs/html/sdk/1.5_r3/requirements.jd
+++ b/docs/html/sdk/1.5_r3/requirements.jd
@@ -10,7 +10,13 @@
 <ul>
   <li>Windows XP (32-bit) or Vista (32- or 64-bit)</li>
   <li>Mac OS X 10.4.8 or later (x86 only)</li>
-  <li>Linux (tested on Linux Ubuntu Dapper Drake)</li>
+  <li>Linux (tested on Linux Ubuntu Dapper Drake)
+    <ul>
+      <li>64-bit distributions must be capable of running 32-bit applications. 
+      For information about how to add support for 32-bit applications, see
+      the <a href="installing.html#InstallationNotes">Installation Notes</a>.</li>
+    </ul>
+  </li>
 </ul>
 
 <h3>Supported Development Environments</h3>
diff --git a/docs/html/sdk/1.6_r1/requirements.jd b/docs/html/sdk/1.6_r1/requirements.jd
index 8e698fa..8cfc049 100644
--- a/docs/html/sdk/1.6_r1/requirements.jd
+++ b/docs/html/sdk/1.6_r1/requirements.jd
@@ -11,7 +11,13 @@
 <ul>
   <li>Windows XP (32-bit) or Vista (32- or 64-bit)</li>
   <li>Mac OS X 10.4.8 or later (x86 only)</li>
-  <li>Linux (tested on Linux Ubuntu Hardy Heron)</li>
+  <li>Linux (tested on Linux Ubuntu Hardy Heron)
+    <ul>
+      <li>64-bit distributions must be capable of running 32-bit applications. 
+      For information about how to add support for 32-bit applications, see
+      the <a href="installing.html#InstallationNotes">Installation Notes</a>.</li>
+    </ul>
+  </li>
 </ul>
 
 <h3>Supported Development Environments</h3>
diff --git a/docs/html/sdk/RELEASENOTES.jd b/docs/html/sdk/RELEASENOTES.jd
index 130a92c..0dcafd3 100644
--- a/docs/html/sdk/RELEASENOTES.jd
+++ b/docs/html/sdk/RELEASENOTES.jd
@@ -24,6 +24,11 @@
 Devices</a> and download new SDK packages (such as platform versions and 
 add-ons) into your environment.</li>
     <li>Improved support for test packages in New Project Wizard</li>
+    <li>The reference documentation now offers a "Filter by API Level" 
+capability that lets you display only the parts of the API that are actually 
+available to your application, based on the <code>android:minSdkVersion</code>
+value the application declares in its manifest. For more information, see
+<a href="{@docRoot}guide/appendix/api-levels.html">Android API Levels</a></li>
   </ul>
 
 <p>For details about the Android platforms included in the SDK &mdash; including
@@ -71,8 +76,8 @@
 
 <h3>Android SDK and AVD Manager</h3>
 
-<p>The SDK offers a new tool called Android AVD Manager that lets you manage
-your SDK and AVD environments more efficiently. </p>
+<p>The SDK offers a new tool called Android SDK and AVD Manager that lets you 
+manage your SDK and AVD environments more efficiently. </p>
 
 <p>Using the tool, you can quickly check what Android platforms, add-ons,
 extras, and documentation packages are available in your SDK environment, what
@@ -181,7 +186,7 @@
 <p>Besides these defaults, You can also create an AVD that overrides the default
 density for each skin, to create any combination of resolution/density (WVGA
 with medium density, for instance).  To do so, use the <code>android</code> tool
-command line to create a new AVD that uses a custom hardare configuration. See
+command line to create a new AVD that uses a custom hardware configuration. See
 <a href="{@docRoot}guide/developing/tools/avd.html#createavd">Creating an
 AVD</a> for more information.</p>
 
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index e82f297..f42788e 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -271,7 +271,8 @@
 
     public void setTileModeXY(Shader.TileMode xmode, Shader.TileMode ymode) {
         final BitmapState state = mBitmapState;
-        if (state.mTileModeX != xmode || state.mTileModeY != ymode) {
+        if (state.mPaint.getShader() == null ||
+                state.mTileModeX != xmode || state.mTileModeY != ymode) {
             state.mTileModeX = xmode;
             state.mTileModeY = ymode;
             mRebuildShader = true;
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index 3266f1e..c6f57d4 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -36,7 +36,6 @@
     private Drawable mCurrDrawable;
     private int mAlpha = 0xFF;
     private ColorFilter mColorFilter;
-    private boolean mDither = DEFAULT_DITHER;
 
     private int mCurIndex = -1;
     private boolean mMutated;
@@ -83,10 +82,10 @@
 
     @Override
     public void setDither(boolean dither) {
-        if (mDither != dither) {
-            mDither = dither;
+        if (mDrawableContainerState.mDither != dither) {
+            mDrawableContainerState.mDither = dither;
             if (mCurrDrawable != null) {
-                mCurrDrawable.setDither(mDither);
+                mCurrDrawable.setDither(mDrawableContainerState.mDither);
             }
         }
     }
@@ -212,7 +211,7 @@
             if (d != null) {
                 d.setVisible(isVisible(), true);
                 d.setAlpha(mAlpha);
-                d.setDither(mDither);
+                d.setDither(mDrawableContainerState.mDither);
                 d.setColorFilter(mColorFilter);
                 d.setState(getState());
                 d.setLevel(getLevel());
@@ -285,6 +284,8 @@
         boolean     mCanConstantState;
 
         boolean     mPaddingChecked = false;
+        
+        boolean     mDither = DEFAULT_DITHER;        
 
         DrawableContainerState(DrawableContainerState orig, DrawableContainer owner,
                 Resources res) {
@@ -323,6 +324,8 @@
                 mOpacity = orig.mOpacity;
                 mHaveStateful = orig.mHaveStateful;
                 mStateful = orig.mStateful;
+                
+                mDither = orig.mDither;
 
             } else {
                 mDrawables = new Drawable[10];
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index 89db4fa..d35c5e3 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -140,6 +140,8 @@
     native void nScriptSetTimeZone(int script, byte[] timeZone);
     native void nScriptSetType(int type, boolean writable, String name, int slot);
     native void nScriptSetRoot(boolean isRoot);
+    native void nScriptSetInvokable(String name, int slot);
+    native void nScriptInvoke(int id, int slot);
 
     native void nScriptCBegin();
     native void nScriptCSetScript(byte[] script, int offset, int length);
diff --git a/graphics/java/android/renderscript/Script.java b/graphics/java/android/renderscript/Script.java
index a402471..35791a3 100644
--- a/graphics/java/android/renderscript/Script.java
+++ b/graphics/java/android/renderscript/Script.java
@@ -25,6 +25,22 @@
     boolean mIsRoot;
     Type[] mTypes;
     boolean[] mWritable;
+    Invokable[] mInvokables;
+
+    public static class Invokable {
+        RenderScript mRS;
+        Script mScript;
+        int mSlot;
+        String mName;
+
+        Invokable() {
+            mSlot = -1;
+        }
+
+        public void execute() {
+            mRS.nScriptInvoke(mScript.mID, mSlot);
+        }
+    }
 
     Script(int id, RenderScript rs) {
         super(rs);
@@ -61,12 +77,15 @@
         Type[] mTypes;
         String[] mNames;
         boolean[] mWritable;
+        int mInvokableCount = 0;
+        Invokable[] mInvokables;
 
         Builder(RenderScript rs) {
             mRS = rs;
             mTypes = new Type[MAX_SLOT];
             mNames = new String[MAX_SLOT];
             mWritable = new boolean[MAX_SLOT];
+            mInvokables = new Invokable[MAX_SLOT];
         }
 
         public void setType(Type t, int slot) {
@@ -79,6 +98,15 @@
             mNames[slot] = name;
         }
 
+        public Invokable addInvokable(String func) {
+            Invokable i = new Invokable();
+            i.mName = func;
+            i.mRS = mRS;
+            i.mSlot = mInvokableCount;
+            mInvokables[mInvokableCount++] = i;
+            return i;
+        }
+
         public void setType(boolean writable, int slot) {
             mWritable[slot] = writable;
         }
@@ -90,11 +118,20 @@
                     mRS.nScriptSetType(mTypes[ct].mID, mWritable[ct], mNames[ct], ct);
                 }
             }
+            for(int ct=0; ct < mInvokableCount; ct++) {
+                mRS.nScriptSetInvokable(mInvokables[ct].mName, ct);
+            }
         }
 
         void transferObject(Script s) {
             s.mIsRoot = mIsRoot;
             s.mTypes = mTypes;
+            s.mInvokables = new Invokable[mInvokableCount];
+            for(int ct=0; ct < mInvokableCount; ct++) {
+                s.mInvokables[ct] = mInvokables[ct];
+                s.mInvokables[ct].mScript = s;
+            }
+            s.mInvokables = null;
         }
 
         public void setRoot(boolean r) {
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index 90b5958..eae6f24 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -891,6 +891,29 @@
 }
 
 static void
+nScriptSetInvoke(JNIEnv *_env, jobject _this, jstring _str, jint slot)
+{
+    RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+    LOG_API("nScriptSetInvoke, con(%p)", con);
+    const char* n = NULL;
+    if (_str) {
+        n = _env->GetStringUTFChars(_str, NULL);
+    }
+    rsScriptSetInvoke(con, n, slot);
+    if (n) {
+        _env->ReleaseStringUTFChars(_str, n);
+    }
+}
+
+static void
+nScriptInvoke(JNIEnv *_env, jobject _this, jint obj, jint slot)
+{
+    RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
+    LOG_API("nScriptInvoke, con(%p), script(%p)", con, (void *)obj);
+    rsScriptInvoke(con, (RsScript)obj, slot);
+}
+
+static void
 nScriptSetRoot(JNIEnv *_env, jobject _this, jboolean isRoot)
 {
     RsContext con = (RsContext)(_env->GetIntField(_this, gContextId));
@@ -1366,6 +1389,8 @@
 {"nScriptSetTimeZone",             "(I[B)V",                               (void*)nScriptSetTimeZone },
 {"nScriptSetType",                 "(IZLjava/lang/String;I)V",             (void*)nScriptSetType },
 {"nScriptSetRoot",                 "(Z)V",                                 (void*)nScriptSetRoot },
+{"nScriptSetInvokable",            "(Ljava/lang/String;I)V",               (void*)nScriptSetInvoke },
+{"nScriptInvoke",                  "(II)V",                                (void*)nScriptInvoke },
 
 {"nScriptCBegin",                  "()V",                                  (void*)nScriptCBegin },
 {"nScriptCSetScript",              "([BII)V",                              (void*)nScriptCSetScript },
diff --git a/include/media/stagefright/SoftwareRenderer.h b/include/media/stagefright/SoftwareRenderer.h
index b61858c..1545493 100644
--- a/include/media/stagefright/SoftwareRenderer.h
+++ b/include/media/stagefright/SoftwareRenderer.h
@@ -45,6 +45,7 @@
 
     void renderCbYCrY(const void *data, size_t size);
     void renderYUV420Planar(const void *data, size_t size);
+    void renderQCOMYUV420SemiPlanar(const void *data, size_t size);
 
     OMX_COLOR_FORMATTYPE mColorFormat;
     sp<ISurface> mISurface;
diff --git a/include/private/ui/SharedBufferStack.h b/include/private/ui/SharedBufferStack.h
index 8b0f154..c02b2e7 100644
--- a/include/private/ui/SharedBufferStack.h
+++ b/include/private/ui/SharedBufferStack.h
@@ -69,12 +69,6 @@
 
 // ----------------------------------------------------------------------------
 
-struct FlatRegion { // 12 bytes
-    static const unsigned int NUM_RECT_MAX = 1;
-    uint32_t    count;
-    uint16_t    rects[4*NUM_RECT_MAX];
-};
-
 // should be 128 bytes (32 longs)
 class SharedBufferStack
 {
@@ -84,6 +78,18 @@
     friend class SharedBufferServer;
 
 public:
+    struct FlatRegion { // 12 bytes
+        static const unsigned int NUM_RECT_MAX = 1;
+        uint32_t    count;
+        uint16_t    rects[4*NUM_RECT_MAX];
+    };
+    
+    struct Statistics { // 4 longs
+        typedef int32_t usecs_t;
+        usecs_t  totalTime;
+        usecs_t  reserved[3];
+    };
+    
     SharedBufferStack();
     void init(int32_t identity);
     status_t setDirtyRegion(int buffer, const Region& reg);
@@ -100,7 +106,8 @@
     volatile int32_t reallocMask;
 
     int32_t     identity;       // surface's identity (const)
-    int32_t     reserved32[13];
+    int32_t     reserved32[9];
+    Statistics  stats;
     FlatRegion  dirtyRegion[NUM_BUFFER_MAX];    // 12*4=48 bytes
 };
 
@@ -223,7 +230,7 @@
     status_t queue(int buf);
     bool needNewBuffer(int buffer) const;
     status_t setDirtyRegion(int buffer, const Region& reg);
-
+    
 private:
     friend struct Condition;
     friend struct DequeueCondition;
@@ -257,6 +264,8 @@
     };
 
     int32_t tail;
+    // statistics...
+    nsecs_t mDequeueTime[NUM_BUFFER_MAX];
 };
 
 // ----------------------------------------------------------------------------
@@ -275,6 +284,9 @@
     
     Region getDirtyRegion(int buffer) const;
 
+    SharedBufferStack::Statistics getStats() const;
+    
+
 private:
     struct UnlockUpdate : public UpdateBase {
         const int lockedBuffer;
diff --git a/include/ui/Surface.h b/include/ui/Surface.h
index 118fb83..2cedeb6 100644
--- a/include/ui/Surface.h
+++ b/include/ui/Surface.h
@@ -212,7 +212,7 @@
 
     
     void setUsage(uint32_t reqUsage);
-    bool getUsage(uint32_t* usage);
+    uint32_t getUsage() const;
     
     // constants
     sp<SurfaceComposerClient>   mClient;
@@ -227,7 +227,6 @@
     // protected by mSurfaceLock
     Rect                        mSwapRectangle;
     uint32_t                    mUsage;
-    int32_t                     mUsageChanged;
     
     // protected by mSurfaceLock. These are also used from lock/unlock
     // but in that case, they must be called form the same thread.
diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h
index e524e2a..17ccad6 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/utils/ResourceTypes.h
@@ -864,6 +864,13 @@
         KEYSHIDDEN_SOFT = 0x0003,
     };
     
+    enum {
+        MASK_NAVHIDDEN = 0x000c,
+        NAVHIDDEN_ANY = 0x0000,
+        NAVHIDDEN_NO = 0x0004,
+        NAVHIDDEN_YES = 0x0008,
+    };
+    
     union {
         struct {
             uint8_t keyboard;
@@ -1011,7 +1018,8 @@
         if (orientation != o.orientation) diffs |= CONFIG_ORIENTATION;
         if (density != o.density) diffs |= CONFIG_DENSITY;
         if (touchscreen != o.touchscreen) diffs |= CONFIG_TOUCHSCREEN;
-        if (((inputFlags^o.inputFlags)&MASK_KEYSHIDDEN) != 0) diffs |= CONFIG_KEYBOARD_HIDDEN;
+        if (((inputFlags^o.inputFlags)&(MASK_KEYSHIDDEN|MASK_NAVHIDDEN)) != 0)
+                diffs |= CONFIG_KEYBOARD_HIDDEN;
         if (keyboard != o.keyboard) diffs |= CONFIG_KEYBOARD;
         if (navigation != o.navigation) diffs |= CONFIG_NAVIGATION;
         if (screenSize != o.screenSize) diffs |= CONFIG_SCREEN_SIZE;
@@ -1082,6 +1090,11 @@
                 if (!(o.inputFlags & MASK_KEYSHIDDEN)) return true;
             }
 
+            if (((inputFlags^o.inputFlags) & MASK_NAVHIDDEN) != 0) {
+                if (!(inputFlags & MASK_NAVHIDDEN)) return false;
+                if (!(o.inputFlags & MASK_NAVHIDDEN)) return true;
+            }
+
             if (keyboard != o.keyboard) {
                 if (!keyboard) return false;
                 if (!o.keyboard) return true;
@@ -1225,6 +1238,18 @@
                     }
                 }
 
+                const int navHidden = inputFlags & MASK_NAVHIDDEN;
+                const int oNavHidden = o.inputFlags & MASK_NAVHIDDEN;
+                if (navHidden != oNavHidden) {
+                    const int reqNavHidden =
+                            requested->inputFlags & MASK_NAVHIDDEN;
+                    if (reqNavHidden) {
+
+                        if (!navHidden) return false;
+                        if (!oNavHidden) return true;
+                    }
+                }
+
                 if ((keyboard != o.keyboard) && requested->keyboard) {
                     return (keyboard);
                 }
@@ -1332,6 +1357,12 @@
                     return false;
                 }
             }
+            const int navHidden = inputFlags&MASK_NAVHIDDEN;
+            const int setNavHidden = settings.inputFlags&MASK_NAVHIDDEN;
+            if (setNavHidden != 0 && navHidden != 0
+                && navHidden != setNavHidden) {
+                return false;
+            }
             if (settings.keyboard != 0 && keyboard != 0
                 && keyboard != settings.keyboard) {
                 return false;
diff --git a/keystore/java/android/security/ServiceCommand.java b/keystore/java/android/security/ServiceCommand.java
index ee80014..9923011 100644
--- a/keystore/java/android/security/ServiceCommand.java
+++ b/keystore/java/android/security/ServiceCommand.java
@@ -49,8 +49,6 @@
 
     public static final int BUFFER_LENGTH = 4096;
 
-    private static final boolean DBG = true;
-
     private String mServiceName;
     private String mTag;
     private InputStream mIn;
@@ -61,7 +59,6 @@
         if (mSocket != null) {
             return true;
         }
-        if (DBG) Log.d(mTag, "connecting...");
         try {
             mSocket = new LocalSocket();
 
@@ -80,7 +77,6 @@
     }
 
     private void disconnect() {
-        if (DBG) Log.d(mTag,"disconnecting...");
         try {
             if (mSocket != null) mSocket.close();
         } catch (IOException ex) { }
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index 4f7500f..add358b 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -2069,7 +2069,7 @@
    }
 }
 
-AudioFlinger::PlaybackThread::TrackBase::~TrackBase()
+AudioFlinger::ThreadBase::TrackBase::~TrackBase()
 {
     if (mCblk) {
         mCblk->~audio_track_cblk_t();   // destroy our shared-structure.
@@ -2081,7 +2081,7 @@
     mClient.clear();
 }
 
-void AudioFlinger::PlaybackThread::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer)
+void AudioFlinger::ThreadBase::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer)
 {
     buffer->raw = 0;
     mFrameCount = buffer->frameCount;
@@ -2089,7 +2089,7 @@
     buffer->frameCount = 0;
 }
 
-bool AudioFlinger::PlaybackThread::TrackBase::step() {
+bool AudioFlinger::ThreadBase::TrackBase::step() {
     bool result;
     audio_track_cblk_t* cblk = this->cblk();
 
@@ -2101,7 +2101,7 @@
     return result;
 }
 
-void AudioFlinger::PlaybackThread::TrackBase::reset() {
+void AudioFlinger::ThreadBase::TrackBase::reset() {
     audio_track_cblk_t* cblk = this->cblk();
 
     cblk->user = 0;
@@ -2112,20 +2112,20 @@
     LOGV("TrackBase::reset");
 }
 
-sp<IMemory> AudioFlinger::PlaybackThread::TrackBase::getCblk() const
+sp<IMemory> AudioFlinger::ThreadBase::TrackBase::getCblk() const
 {
     return mCblkMemory;
 }
 
-int AudioFlinger::PlaybackThread::TrackBase::sampleRate() const {
+int AudioFlinger::ThreadBase::TrackBase::sampleRate() const {
     return (int)mCblk->sampleRate;
 }
 
-int AudioFlinger::PlaybackThread::TrackBase::channelCount() const {
+int AudioFlinger::ThreadBase::TrackBase::channelCount() const {
     return (int)mCblk->channels;
 }
 
-void* AudioFlinger::PlaybackThread::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const {
+void* AudioFlinger::ThreadBase::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const {
     audio_track_cblk_t* cblk = this->cblk();
     int8_t *bufferStart = (int8_t *)mBuffer + (offset-cblk->serverBase)*cblk->frameSize;
     int8_t *bufferEnd = bufferStart + frames * cblk->frameSize;
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index ac2e738..87ad97c 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -297,6 +297,16 @@
 	param const char * name
 	}
 
+ScriptSetInvoke {
+	param const char * name
+	param uint32_t slot
+	}
+
+ScriptInvoke {
+	param RsScript s
+	param uint32_t slot
+	}
+
 ScriptSetRoot {
 	param bool isRoot
 	}
diff --git a/libs/rs/rsScript.cpp b/libs/rs/rsScript.cpp
index fde31a1..99a085d 100644
--- a/libs/rs/rsScript.cpp
+++ b/libs/rs/rsScript.cpp
@@ -27,6 +27,8 @@
     mEnviroment.mClearColor[2] = 0;
     mEnviroment.mClearColor[3] = 1;
     mEnviroment.mClearDepth = 1;
+    mEnviroment.mClearStencil = 0;
+    mEnviroment.mIsRoot = false;
 }
 
 Script::~Script()
@@ -83,10 +85,23 @@
     }
 }
 
+void rsi_ScriptSetInvoke(Context *rsc, const char *name, uint32_t slot)
+{
+    ScriptCState *ss = &rsc->mScriptC;
+    ss->mInvokableNames[slot] = name;
+}
+
+void rsi_ScriptInvoke(Context *rsc, RsScript vs, uint32_t slot)
+{
+    Script *s = static_cast<Script *>(vs);
+    s->mEnviroment.mInvokables[slot]();
+}
+
+
 void rsi_ScriptSetRoot(Context * rsc, bool isRoot)
 {
     ScriptCState *ss = &rsc->mScriptC;
-    ss->mEnviroment.mIsRoot = isRoot;
+    ss->mScript->mEnviroment.mIsRoot = isRoot;
 }
 
 
diff --git a/libs/rs/rsScript.h b/libs/rs/rsScript.h
index 60f83a6..e40531e 100644
--- a/libs/rs/rsScript.h
+++ b/libs/rs/rsScript.h
@@ -34,6 +34,7 @@
 class Script : public ObjectBase
 {
 public:
+    typedef void (* InvokeFunc_t)(void);
 
     Script();
     virtual ~Script();
@@ -52,17 +53,22 @@
         ObjectBaseRef<ProgramFragment> mFragment;
         //ObjectBaseRef<ProgramRaster> mRaster;
         ObjectBaseRef<ProgramFragmentStore> mFragmentStore;
-
+        InvokeFunc_t mInvokables[MAX_SCRIPT_BANKS];
+        const char * mScriptText;
+        uint32_t mScriptTextLength;
     };
     Enviroment_t mEnviroment;
 
     uint32_t mCounstantBufferCount;
 
+
     ObjectBaseRef<Allocation> mSlots[MAX_SCRIPT_BANKS];
     ObjectBaseRef<const Type> mTypes[MAX_SCRIPT_BANKS];
     String8 mSlotNames[MAX_SCRIPT_BANKS];
     bool mSlotWritable[MAX_SCRIPT_BANKS];
 
+
+
     virtual bool run(Context *, uint32_t launchID) = 0;
 };
 
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index 8230cbc..108ae5a 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -82,36 +82,27 @@
 
 ScriptCState::ScriptCState()
 {
+    mScript = NULL;
     clear();
 }
 
 ScriptCState::~ScriptCState()
 {
-    if (mAccScript) {
-        accDeleteScript(mAccScript);
-    }
+    delete mScript;
+    mScript = NULL;
 }
 
 void ScriptCState::clear()
 {
-    memset(&mProgram, 0, sizeof(mProgram));
-
     for (uint32_t ct=0; ct < MAX_SCRIPT_BANKS; ct++) {
         mConstantBufferTypes[ct].clear();
         mSlotNames[ct].setTo("");
+        mInvokableNames[ct].setTo("");
         mSlotWritable[ct] = false;
     }
 
-    memset(&mEnviroment, 0, sizeof(mEnviroment));
-    mEnviroment.mClearColor[0] = 0;
-    mEnviroment.mClearColor[1] = 0;
-    mEnviroment.mClearColor[2] = 0;
-    mEnviroment.mClearColor[3] = 1;
-    mEnviroment.mClearDepth = 1;
-    mEnviroment.mClearStencil = 0;
-    mEnviroment.mIsRoot = false;
-
-    mAccScript = NULL;
+    delete mScript;
+    mScript = new ScriptC();
 
     mInt32Defines.clear();
     mFloatDefines.clear();
@@ -127,9 +118,9 @@
     return NULL;
 }
 
-void ScriptCState::runCompiler(Context *rsc)
+void ScriptCState::runCompiler(Context *rsc, ScriptC *s)
 {
-    mAccScript = accCreateScript();
+    s->mAccScript = accCreateScript();
     String8 tmp;
 
     rsc->appendNameDefines(&tmp);
@@ -139,44 +130,51 @@
     appendTypes(&tmp);
     tmp.append("#line 1\n");
 
-    const char* scriptSource[] = {tmp.string(), mProgram.mScriptText};
-    int scriptLength[] = {tmp.length(), mProgram.mScriptTextLength} ;
-    accScriptSource(mAccScript, sizeof(scriptLength) / sizeof(int), scriptSource, scriptLength);
-    accRegisterSymbolCallback(mAccScript, symbolLookup, NULL);
-    accCompileScript(mAccScript);
-    accGetScriptLabel(mAccScript, "main", (ACCvoid**) &mProgram.mScript);
-    accGetScriptLabel(mAccScript, "init", (ACCvoid**) &mProgram.mInit);
-    rsAssert(mProgram.mScript);
+    const char* scriptSource[] = {tmp.string(), s->mEnviroment.mScriptText};
+    int scriptLength[] = {tmp.length(), s->mEnviroment.mScriptTextLength} ;
+    accScriptSource(s->mAccScript, sizeof(scriptLength) / sizeof(int), scriptSource, scriptLength);
+    accRegisterSymbolCallback(s->mAccScript, symbolLookup, NULL);
+    accCompileScript(s->mAccScript);
+    accGetScriptLabel(s->mAccScript, "main", (ACCvoid**) &s->mProgram.mScript);
+    accGetScriptLabel(s->mAccScript, "init", (ACCvoid**) &s->mProgram.mInit);
+    rsAssert(s->mProgram.mScript);
 
-    if (!mProgram.mScript) {
+    if (!s->mProgram.mScript) {
         ACCchar buf[4096];
         ACCsizei len;
-        accGetScriptInfoLog(mAccScript, sizeof(buf), &len, buf);
+        accGetScriptInfoLog(s->mAccScript, sizeof(buf), &len, buf);
         LOGE(buf);
     }
 
-    if (mProgram.mInit) {
-        mProgram.mInit();
+    if (s->mProgram.mInit) {
+        s->mProgram.mInit();
     }
 
     for (int ct=0; ct < MAX_SCRIPT_BANKS; ct++) {
         if (mSlotNames[ct].length() > 0) {
-            accGetScriptLabel(mAccScript,
+            accGetScriptLabel(s->mAccScript,
                               mSlotNames[ct].string(),
-                              (ACCvoid**) &mProgram.mSlotPointers[ct]);
-            LOGE("var  %s  %p", mSlotNames[ct].string(), mProgram.mSlotPointers[ct]);
+                              (ACCvoid**) &s->mProgram.mSlotPointers[ct]);
         }
     }
 
-    mEnviroment.mFragment.set(rsc->getDefaultProgramFragment());
-    mEnviroment.mVertex.set(rsc->getDefaultProgramVertex());
-    mEnviroment.mFragmentStore.set(rsc->getDefaultProgramFragmentStore());
+    for (int ct=0; ct < MAX_SCRIPT_BANKS; ct++) {
+        if (mInvokableNames[ct].length() > 0) {
+            accGetScriptLabel(s->mAccScript,
+                              mInvokableNames[ct].string(),
+                              (ACCvoid**) &s->mEnviroment.mInvokables[ct]);
+        }
+    }
 
-    if (mProgram.mScript) {
+    s->mEnviroment.mFragment.set(rsc->getDefaultProgramFragment());
+    s->mEnviroment.mVertex.set(rsc->getDefaultProgramVertex());
+    s->mEnviroment.mFragmentStore.set(rsc->getDefaultProgramFragmentStore());
+
+    if (s->mProgram.mScript) {
         const static int pragmaMax = 16;
         ACCsizei pragmaCount;
         ACCchar * str[pragmaMax];
-        accGetPragmas(mAccScript, &pragmaCount, pragmaMax, &str[0]);
+        accGetPragmas(s->mAccScript, &pragmaCount, pragmaMax, &str[0]);
 
         for (int ct=0; ct < pragmaCount; ct+=2) {
             if (!strcmp(str[ct], "version")) {
@@ -188,12 +186,12 @@
                     continue;
                 }
                 if (!strcmp(str[ct+1], "parent")) {
-                    mEnviroment.mVertex.clear();
+                    s->mEnviroment.mVertex.clear();
                     continue;
                 }
                 ProgramVertex * pv = (ProgramVertex *)rsc->lookupName(str[ct+1]);
                 if (pv != NULL) {
-                    mEnviroment.mVertex.set(pv);
+                    s->mEnviroment.mVertex.set(pv);
                     continue;
                 }
                 LOGE("Unreconized value %s passed to stateVertex", str[ct+1]);
@@ -208,12 +206,12 @@
                     continue;
                 }
                 if (!strcmp(str[ct+1], "parent")) {
-                    mEnviroment.mFragment.clear();
+                    s->mEnviroment.mFragment.clear();
                     continue;
                 }
                 ProgramFragment * pf = (ProgramFragment *)rsc->lookupName(str[ct+1]);
                 if (pf != NULL) {
-                    mEnviroment.mFragment.set(pf);
+                    s->mEnviroment.mFragment.set(pf);
                     continue;
                 }
                 LOGE("Unreconized value %s passed to stateFragment", str[ct+1]);
@@ -224,13 +222,13 @@
                     continue;
                 }
                 if (!strcmp(str[ct+1], "parent")) {
-                    mEnviroment.mFragmentStore.clear();
+                    s->mEnviroment.mFragmentStore.clear();
                     continue;
                 }
                 ProgramFragmentStore * pfs =
                     (ProgramFragmentStore *)rsc->lookupName(str[ct+1]);
                 if (pfs != NULL) {
-                    mEnviroment.mFragmentStore.set(pfs);
+                    s->mEnviroment.mFragmentStore.set(pfs);
                     continue;
                 }
                 LOGE("Unreconized value %s passed to stateFragmentStore", str[ct+1]);
@@ -351,33 +349,6 @@
             s.append(";\n");
             LOGD(s);
             str->append(s);
-#if 0
-            for (size_t ct2=0; ct2 < e->getComponentCount(); ct2++) {
-                const Component *c = e->getComponent(ct2);
-                tmp.setTo("#define ");
-                tmp.append(mSlotNames[ct]);
-                tmp.append("_");
-                tmp.append(c->getComponentName());
-                switch (c->getType()) {
-                case Component::FLOAT:
-                    tmp.append(" loadF(");
-                    break;
-                case Component::SIGNED:
-                    sprintf(buf, " loadI%i(", c->getBits());
-                    tmp.append(buf);
-                    break;
-                case Component::UNSIGNED:
-                    sprintf(buf, " loadU%i(", c->getBits());
-                    tmp.append(buf);
-                    break;
-                }
-                sprintf(buf, "%i, %i)\n", ct, ct2);
-                tmp.append(buf);
-
-                LOGD(tmp);
-                str->append(tmp);
-            }
-#endif
         }
     }
 }
@@ -394,15 +365,16 @@
 
 void rsi_ScriptCSetScript(Context * rsc, void *vp)
 {
-    ScriptCState *ss = &rsc->mScriptC;
-    ss->mProgram.mScript = reinterpret_cast<ScriptC::RunScript_t>(vp);
+    rsAssert(0);
+    //ScriptCState *ss = &rsc->mScriptC;
+    //ss->mProgram.mScript = reinterpret_cast<ScriptC::RunScript_t>(vp);
 }
 
 void rsi_ScriptCSetText(Context *rsc, const char *text, uint32_t len)
 {
     ScriptCState *ss = &rsc->mScriptC;
-    ss->mProgram.mScriptText = text;
-    ss->mProgram.mScriptTextLength = len;
+    ss->mScript->mEnviroment.mScriptText = text;
+    ss->mScript->mEnviroment.mScriptTextLength = len;
 }
 
 
@@ -410,14 +382,11 @@
 {
     ScriptCState *ss = &rsc->mScriptC;
 
-    ss->runCompiler(rsc);
+    ScriptC *s = ss->mScript;
+    ss->mScript = NULL;
 
-    ScriptC *s = new ScriptC();
+    ss->runCompiler(rsc, s);
     s->incUserRef();
-    s->mAccScript = ss->mAccScript;
-    ss->mAccScript = NULL;
-    s->mEnviroment = ss->mEnviroment;
-    s->mProgram = ss->mProgram;
     for (int ct=0; ct < MAX_SCRIPT_BANKS; ct++) {
         s->mTypes[ct].set(ss->mConstantBufferTypes[ct].get());
         s->mSlotNames[ct] = ss->mSlotNames[ct];
diff --git a/libs/rs/rsScriptC.h b/libs/rs/rsScriptC.h
index 8aa99ef..355f0c3 100644
--- a/libs/rs/rsScriptC.h
+++ b/libs/rs/rsScriptC.h
@@ -67,17 +67,15 @@
     ScriptCState();
     ~ScriptCState();
 
-    ACCscript* mAccScript;
-
-    ScriptC::Program_t mProgram;
-    Script::Enviroment_t mEnviroment;
+    ScriptC *mScript;
 
     ObjectBaseRef<const Type> mConstantBufferTypes[MAX_SCRIPT_BANKS];
     String8 mSlotNames[MAX_SCRIPT_BANKS];
     bool mSlotWritable[MAX_SCRIPT_BANKS];
+    String8 mInvokableNames[MAX_SCRIPT_BANKS];
 
     void clear();
-    void runCompiler(Context *rsc);
+    void runCompiler(Context *rsc, ScriptC *s);
     void appendVarDefines(String8 *str);
     void appendTypes(String8 *str);
 
diff --git a/libs/surfaceflinger/BlurFilter.cpp b/libs/surfaceflinger/BlurFilter.cpp
index 5dc0ba0..1ffbd5b 100644
--- a/libs/surfaceflinger/BlurFilter.cpp
+++ b/libs/surfaceflinger/BlurFilter.cpp
@@ -111,6 +111,50 @@
     }
 };
 
+template <int FACTOR = 0>
+struct BlurColor888X
+{
+    typedef uint32_t type;
+    int r, g, b;    
+    inline BlurColor888X() { }
+    inline BlurColor888X(uint32_t v) {
+        v = BLUR_RGBA_TO_HOST(v);
+        r = v & 0xFF;
+        g = (v >>  8) & 0xFF;
+        b = (v >> 16) & 0xFF;
+    }
+    inline void clear() { r=g=b=0; }
+    inline uint32_t to(int shift, int last, int dither) const {
+        int R = r;
+        int G = g;
+        int B = b;
+        if  (UNLIKELY(last)) {
+            if (FACTOR>0) {
+                int L = (R+G+G+B)>>2;
+                R += ((L - R) * FACTOR) >> 8;
+                G += ((L - G) * FACTOR) >> 8;
+                B += ((L - B) * FACTOR) >> 8;
+            }
+        }
+        R >>= shift;
+        G >>= shift;
+        B >>= shift;
+        return BLUR_HOST_TO_RGBA((0xFF<<24) | (B<<16) | (G<<8) | R);
+    }    
+    inline BlurColor888X& operator += (const BlurColor888X& rhs) {
+        r += rhs.r;
+        g += rhs.g;
+        b += rhs.b;
+        return *this;
+    }
+    inline BlurColor888X& operator -= (const BlurColor888X& rhs) {
+        r -= rhs.r;
+        g -= rhs.g;
+        b -= rhs.b;
+        return *this;
+    }
+};
+
 struct BlurGray565
 {
     typedef uint16_t type;
@@ -316,7 +360,13 @@
         int kernelSizeUser,
         int repeat)
 {
-    return blurFilter< BlurColor565<0x80> >(image, image, kernelSizeUser, repeat);
+    status_t err = BAD_VALUE;
+    if (image->format == GGL_PIXEL_FORMAT_RGB_565) {
+        err = blurFilter< BlurColor565<0x80> >(image, image, kernelSizeUser, repeat);
+    } else if (image->format == GGL_PIXEL_FORMAT_RGBX_8888) {
+        err = blurFilter< BlurColor888X<0x80> >(image, image, kernelSizeUser, repeat);
+    }
+    return err;
 }
 
 } // namespace android
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index d893f0a..cc913cbd 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -174,6 +174,13 @@
 
     surface = eglCreateWindowSurface(display, config, mNativeWindow.get(), NULL);
 
+    if (mFlags & UPDATE_ON_DEMAND) {
+        // if we have update on demand, we definitely don't need to
+        // preserve the backbuffer, which is usually costly.
+        eglSurfaceAttrib(display, surface,
+                EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED);
+    }
+
     if (eglQuerySurface(display, surface, EGL_SWAP_BEHAVIOR, &dummy) == EGL_TRUE) {
         if (dummy == EGL_BUFFER_PRESERVED) {
             mFlags |= BUFFER_PRESERVED;
diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp
index 1e7f1e6..7387c85 100644
--- a/libs/surfaceflinger/Layer.cpp
+++ b/libs/surfaceflinger/Layer.cpp
@@ -303,7 +303,6 @@
 
     // Index of the back buffer
     const bool backbufferChanged = (front.w != temp.w) || (front.h != temp.h);
-
     if (backbufferChanged) {
         // the size changed, we need to ask our client to request a new buffer
         LOGD_IF(DEBUG_RESIZE,
@@ -318,17 +317,6 @@
         // buffer, it'll get the new size.
         setDrawingSize(temp.w, temp.h);
 
-        // all buffers need reallocation
-        lcblk->reallocate();
-
-        // recompute the visible region
-        // FIXME: ideally we would do that only when we have received
-        // a buffer of the right size
-        flags |= Layer::eVisibleRegion;
-        this->contentDirty = true;
-        
-#if 0 
-        // FIXME: handle freeze lock
         // we're being resized and there is a freeze display request,
         // acquire a freeze lock, so that the screen stays put
         // until we've redrawn at the new size; this is to avoid
@@ -340,7 +328,12 @@
                 mFreezeLock = mFlinger->getFreezeLock();
             }
         }
-#endif
+
+        // recompute the visible region
+        flags |= Layer::eVisibleRegion;
+        this->contentDirty = true;
+        // all buffers need reallocation
+        lcblk->reallocate();
     }
 
     if (temp.sequence != front.sequence) {
@@ -382,6 +375,13 @@
     const Region dirty(lcblk->getDirtyRegion(buf));
     mPostedDirtyRegion = dirty.intersect( newFrontBuffer->getBounds() );
 
+
+    const Layer::State& front(drawingState());
+    if (newFrontBuffer->getWidth() == front.w &&
+        newFrontBuffer->getHeight() ==front.h) {
+        mFreezeLock.clear();
+    }
+
     // FIXME: signal an event if we have more buffers waiting
     // mFlinger->signalEvent();
 
diff --git a/libs/surfaceflinger/LayerBlur.cpp b/libs/surfaceflinger/LayerBlur.cpp
index e14f35b..0ef663f 100644
--- a/libs/surfaceflinger/LayerBlur.cpp
+++ b/libs/surfaceflinger/LayerBlur.cpp
@@ -40,9 +40,9 @@
 
 LayerBlur::LayerBlur(SurfaceFlinger* flinger, DisplayID display,
         const sp<Client>& client, int32_t i)
-     : LayerBaseClient(flinger, display, client, i), mCacheDirty(true),
-     mRefreshCache(true), mCacheAge(0), mTextureName(-1U), 
-     mWidthScale(1.0f), mHeightScale(1.0f)
+: LayerBaseClient(flinger, display, client, i), mCacheDirty(true),
+mRefreshCache(true), mCacheAge(0), mTextureName(-1U), 
+mWidthScale(1.0f), mHeightScale(1.0f)
 {
 }
 
@@ -136,6 +136,13 @@
         // create the texture name the first time
         // can't do that in the ctor, because it runs in another thread.
         glGenTextures(1, &mTextureName);
+        glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES, &mReadFormat);
+        glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE_OES, &mReadType);
+        if (mReadFormat != GL_RGB || mReadType != GL_UNSIGNED_SHORT_5_6_5) {
+            mReadFormat = GL_RGBA;
+            mReadType = GL_UNSIGNED_BYTE;
+            mBlurFormat = GGL_PIXEL_FORMAT_RGBX_8888;
+        }
     }
 
     Region::const_iterator it = clip.begin();
@@ -143,33 +150,39 @@
     if (it != end) {
         glEnable(GL_TEXTURE_2D);
         glBindTexture(GL_TEXTURE_2D, mTextureName);
-    
+
         if (mRefreshCache) {
             mRefreshCache = false;
             mAutoRefreshPending = false;
-            
-            // allocate enough memory for 4-bytes (2 pixels) aligned data
-            const int32_t s = (w + 1) & ~1;
-            uint16_t* const pixels = (uint16_t*)malloc(s*h*2);
+
+            int32_t pixelSize = 4;
+            int32_t s = w;
+            if (mReadType == GL_UNSIGNED_SHORT_5_6_5) {
+                // allocate enough memory for 4-bytes (2 pixels) aligned data
+                s = (w + 1) & ~1;
+                pixelSize = 2;
+            }
+
+            uint16_t* const pixels = (uint16_t*)malloc(s*h*pixelSize);
 
             // This reads the frame-buffer, so a h/w GL would have to
             // finish() its rendering first. we don't want to do that
             // too often. Read data is 4-bytes aligned.
-            glReadPixels(X, Y, w, h, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixels);
-            
+            glReadPixels(X, Y, w, h, mReadFormat, mReadType, pixels);
+
             // blur that texture.
             GGLSurface bl;
             bl.version = sizeof(GGLSurface);
             bl.width = w;
             bl.height = h;
             bl.stride = s;
-            bl.format = GGL_PIXEL_FORMAT_RGB_565;
+            bl.format = mBlurFormat;
             bl.data = (GGLubyte*)pixels;            
             blurFilter(&bl, 8, 2);
 
             if (mFlags & (DisplayHardware::NPOT_EXTENSION)) {
-                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0,
-                        GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixels);
+                glTexImage2D(GL_TEXTURE_2D, 0, mReadFormat, w, h, 0,
+                        mReadFormat, mReadType, pixels);
                 mWidthScale  = 1.0f / w;
                 mHeightScale =-1.0f / h;
                 mYOffset = 0;
@@ -178,10 +191,10 @@
                 GLuint th = 1 << (31 - clz(h));
                 if (tw < w) tw <<= 1;
                 if (th < h) th <<= 1;
-                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tw, th, 0,
-                        GL_RGB, GL_UNSIGNED_SHORT_5_6_5, NULL);
+                glTexImage2D(GL_TEXTURE_2D, 0, mReadFormat, tw, th, 0,
+                        mReadFormat, mReadType, NULL);
                 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, 
-                        GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixels);
+                        mReadFormat, mReadType, pixels);
                 mWidthScale  = 1.0f / tw;
                 mHeightScale =-1.0f / th;
                 mYOffset = th-h;
@@ -189,7 +202,7 @@
 
             free((void*)pixels);
         }
-        
+
         const State& s = drawingState();
         if (UNLIKELY(s.alpha < 0xFF)) {
             const GGLfixed alpha = (s.alpha << 16)/255;
diff --git a/libs/surfaceflinger/LayerBlur.h b/libs/surfaceflinger/LayerBlur.h
index bf36ae4..2e9d7c6 100644
--- a/libs/surfaceflinger/LayerBlur.h
+++ b/libs/surfaceflinger/LayerBlur.h
@@ -59,6 +59,9 @@
     mutable GLfloat mWidthScale;
     mutable GLfloat mHeightScale;
     mutable GLfloat mYOffset;
+    mutable GLint   mReadFormat;
+    mutable GLint   mReadType;
+    mutable uint32_t mBlurFormat;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp
index bbfc54b9..667571b 100644
--- a/libs/surfaceflinger/LayerBuffer.cpp
+++ b/libs/surfaceflinger/LayerBuffer.cpp
@@ -595,6 +595,7 @@
 
     *overlayRef = new OverlayRef(mOverlayHandle, channel,
             mWidth, mHeight, mFormat, mWidthStride, mHeightStride);
+    mLayer.mFlinger->signalEvent();
 }
 
 LayerBuffer::OverlaySource::~OverlaySource()
@@ -607,9 +608,10 @@
 
 void LayerBuffer::OverlaySource::onDraw(const Region& clip) const
 {
+    // this would be where the color-key would be set, should we need it.
     GLclampx red = 0;
     GLclampx green = 0;
-    GLclampx blue = 0x1818;
+    GLclampx blue = 0;
     mLayer.clearWithOpenGL(clip, red, green, blue, 0);
 }
 
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index a352431..31b5128c 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -1521,6 +1521,7 @@
             /*** Layer ***/
             sp<Layer> l = LayerBase::dynamicCast< Layer* >(layer.get());
             if (l != 0) {
+                SharedBufferStack::Statistics stats = l->lcblk->getStats();
                 result.append( l->lcblk->dump("      ") );
                 sp<const Buffer> buf0(l->getBuffer(0));
                 sp<const Buffer> buf1(l->getBuffer(1));
@@ -1539,10 +1540,10 @@
                 snprintf(buffer, SIZE,
                         "      "
                         "format=%2d, [%3ux%3u:%3u] [%3ux%3u:%3u],"
-                        " freezeLock=%p\n",
+                        " freezeLock=%p, dq-q-time=%u us\n",
                         l->pixelFormat(),
                         w0, h0, s0, w1, h1, s1,
-                        l->getFreezeLock().get());
+                        l->getFreezeLock().get(), stats.totalTime);
                 result.append(buffer);
                 buffer[0] = 0;
             }
diff --git a/libs/ui/SharedBufferStack.cpp b/libs/ui/SharedBufferStack.cpp
index 7789a3f..9ad4349 100644
--- a/libs/ui/SharedBufferStack.cpp
+++ b/libs/ui/SharedBufferStack.cpp
@@ -276,6 +276,8 @@
         LOGW("dequeue: tail=%d, head=%d, avail=%d, queued=%d",
                 tail, stack.head, stack.available, stack.queued);
     }
+        
+    const nsecs_t dequeueTime = systemTime(SYSTEM_TIME_THREAD);
 
     //LOGD("[%d] about to dequeue a buffer",
     //        mSharedStack->identity);
@@ -296,6 +298,8 @@
     LOGD_IF(DEBUG_ATOMICS, "dequeued=%d, tail=%d, %s",
             dequeued, tail, dump("").string());
 
+    mDequeueTime[dequeued] = dequeueTime; 
+
     return dequeued;
 }
 
@@ -312,7 +316,7 @@
 status_t SharedBufferClient::lock(int buf)
 {
     LockCondition condition(this, buf);
-    status_t err = waitForCondition(condition);    
+    status_t err = waitForCondition(condition);
     return err;
 }
 
@@ -321,6 +325,9 @@
     QueueUpdate update(this);
     status_t err = updateCondition( update );
     LOGD_IF(DEBUG_ATOMICS, "queued=%d, %s", buf, dump("").string());
+    SharedBufferStack& stack( *mSharedStack );
+    const nsecs_t now = systemTime(SYSTEM_TIME_THREAD);
+    stack.stats.totalTime = ns2us(now - mDequeueTime[buf]);
     return err;
 }
 
@@ -393,5 +400,12 @@
     return stack.getDirtyRegion(buffer);
 }
 
+SharedBufferStack::Statistics SharedBufferServer::getStats() const
+{
+    SharedBufferStack& stack( *mSharedStack );
+    return stack.stats;
+}
+
+
 // ---------------------------------------------------------------------------
 }; // namespace android
diff --git a/libs/ui/Surface.cpp b/libs/ui/Surface.cpp
index c3fbea2..64522fb 100644
--- a/libs/ui/Surface.cpp
+++ b/libs/ui/Surface.cpp
@@ -361,7 +361,6 @@
     const_cast<uint32_t&>(android_native_window_t::flags) = 0;
     // be default we request a hardware surface
     mUsage = GRALLOC_USAGE_HW_RENDER;
-    mUsageChanged = true;
     mNeedFullUpdate = false;
 }
 
@@ -498,14 +497,14 @@
         LOGE("error dequeuing a buffer (%s)", strerror(bufIdx));
         return bufIdx;
     }
-    
-    // FIXME: in case of failure below, we need to undo the dequeue
-    
-    uint32_t usage;
-    const bool usageChanged = getUsage(&usage);
+
+    // below we make sure we AT LEAST have the usage flags we want
+    const uint32_t usage(getUsage());
     const sp<SurfaceBuffer>& backBuffer(mBuffers[bufIdx]);
-    if ((backBuffer == 0) || usageChanged || 
-            mSharedBufferClient->needNewBuffer(bufIdx)) {
+    if (backBuffer == 0 || 
+        ((uint32_t(backBuffer->usage) & usage) != usage) ||
+        mSharedBufferClient->needNewBuffer(bufIdx)) 
+    {
         err = getBufferLocked(bufIdx, usage);
         LOGE_IF(err, "getBufferLocked(%ld, %08x) failed (%s)",
                 bufIdx, usage, strerror(-err));
@@ -600,21 +599,13 @@
 void Surface::setUsage(uint32_t reqUsage)
 {
     Mutex::Autolock _l(mSurfaceLock);
-    if (mUsage != reqUsage) {
-        mUsageChanged = true;
-        mUsage = reqUsage;
-    }
+    mUsage = reqUsage;
 }
 
-bool Surface::getUsage(uint32_t* usage)
+uint32_t Surface::getUsage() const
 {
     Mutex::Autolock _l(mSurfaceLock);
-    *usage = mUsage;
-    if (mUsageChanged) {
-        mUsageChanged = false;
-        return true;
-    }
-    return false;
+    return mUsage;
 }
 
 // ----------------------------------------------------------------------------
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 1dd644b..d6463a1 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -345,6 +345,9 @@
 
     /**
      * Adjusts the volume of a particular stream by one step in a direction.
+     * <p>
+     * This method should only be used by applications that replace the platform-wide
+     * management of audio settings or the main telephony application.
      *
      * @param streamType The stream type to adjust. One of {@link #STREAM_VOICE_CALL},
      * {@link #STREAM_SYSTEM}, {@link #STREAM_RING}, {@link #STREAM_MUSIC} or
@@ -370,6 +373,9 @@
      * active, it will have the highest priority regardless of if the in-call
      * screen is showing. Another example, if music is playing in the background
      * and a call is not active, the music stream will be adjusted.
+     * <p>
+     * This method should only be used by applications that replace the platform-wide
+     * management of audio settings or the main telephony application.
      *
      * @param direction The direction to adjust the volume. One of
      *            {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
@@ -391,6 +397,9 @@
     /**
      * Adjusts the volume of the most relevant stream, or the given fallback
      * stream.
+     * <p>
+     * This method should only be used by applications that replace the platform-wide
+     * management of audio settings or the main telephony application.
      *
      * @param direction The direction to adjust the volume. One of
      *            {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
@@ -541,6 +550,9 @@
      * <p>
      * For a better user experience, applications MUST unmute a muted stream
      * in onPause() and mute is again in onResume() if appropriate.
+     * <p>
+     * This method should only be used by applications that replace the platform-wide
+     * management of audio settings or the main telephony application.
      *
      * @param streamType The stream to be muted/unmuted.
      * @param state The required mute state: true for mute ON, false for mute OFF
@@ -608,6 +620,9 @@
 
     /**
      * Sets the setting for when the vibrate type should vibrate.
+     * <p>
+     * This method should only be used by applications that replace the platform-wide
+     * management of audio settings or the main telephony application.
      *
      * @param vibrateType The type of vibrate. One of
      *            {@link #VIBRATE_TYPE_NOTIFICATION} or
@@ -630,6 +645,9 @@
 
     /**
      * Sets the speakerphone on or off.
+     * <p>
+     * This method should only be used by applications that replace the platform-wide
+     * management of audio settings or the main telephony application.
      *
      * @param on set <var>true</var> to turn on speakerphone;
      *           <var>false</var> to turn it off
@@ -660,6 +678,9 @@
 
     /**
      * Request use of Bluetooth SCO headset for communications.
+     * <p>
+     * This method should only be used by applications that replace the platform-wide
+     * management of audio settings or the main telephony application.
      *
      * @param on set <var>true</var> to use bluetooth SCO for communications;
      *               <var>false</var> to not use bluetooth SCO for communications
@@ -739,6 +760,9 @@
 
     /**
      * Sets the microphone mute on or off.
+     * <p>
+     * This method should only be used by applications that replace the platform-wide
+     * management of audio settings or the main telephony application.
      *
      * @param on set <var>true</var> to mute the microphone;
      *           <var>false</var> to turn mute off
@@ -758,6 +782,13 @@
 
     /**
      * Sets the audio mode.
+     * <p>
+     * The audio mode encompasses audio routing AND the behavior of
+     * the telephony layer. Therefore this method should only be used by applications that
+     * replace the platform-wide management of audio settings or the main telephony application.
+     * In particular, the {@link #MODE_IN_CALL} mode should only be used by the telephony
+     * application when it places a phone call, as it will cause signals from the radio layer
+     * to feed the platform mixer.
      *
      * @param mode  the requested audio mode (NORMAL, RINGTONE, or IN_CALL).
      *              Informs the HAL about the current audio state so that
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index aba40b3..73b6483 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -16,8 +16,7 @@
 
 package android.media;
 
-import android.util.Log;
-
+import java.io.IOException;
 import java.text.ParsePosition;
 import java.text.SimpleDateFormat;
 import java.util.Date;
@@ -25,171 +24,102 @@
 import java.util.Map;
 
 /**
- * Wrapper for native Exif library
- * {@hide}
+ * This is a class for reading and writing Exif tags in a JPEG file.
  */
 public class ExifInterface {
-    private static final String TAG = "ExifInterface";
-    private String mFilename;
-
-    // Constants used for the Orientation Exif tag.
-    public static final int ORIENTATION_UNDEFINED = 0;
-    public static final int ORIENTATION_NORMAL = 1;
-
-    // Constants used for white balance
-    public static final int WHITEBALANCE_AUTO = 0;
-    public static final int WHITEBALANCE_MANUAL = 1;
-
-    // left right reversed mirror
-    public static final int ORIENTATION_FLIP_HORIZONTAL = 2;
-    public static final int ORIENTATION_ROTATE_180 = 3;
-
-    // upside down mirror
-    public static final int ORIENTATION_FLIP_VERTICAL = 4;
-
-    // flipped about top-left <--> bottom-right axis
-    public static final int ORIENTATION_TRANSPOSE = 5;
-
-    // rotate 90 cw to right it
-    public static final int ORIENTATION_ROTATE_90 = 6;
-
-    // flipped about top-right <--> bottom-left axis
-    public static final int ORIENTATION_TRANSVERSE = 7;
-
-    // rotate 270 to right it
-    public static final int ORIENTATION_ROTATE_270 = 8;
 
     // The Exif tag names
     public static final String TAG_ORIENTATION = "Orientation";
-
     public static final String TAG_DATETIME = "DateTime";
     public static final String TAG_MAKE = "Make";
     public static final String TAG_MODEL = "Model";
     public static final String TAG_FLASH = "Flash";
     public static final String TAG_IMAGE_WIDTH = "ImageWidth";
     public static final String TAG_IMAGE_LENGTH = "ImageLength";
-
     public static final String TAG_GPS_LATITUDE = "GPSLatitude";
     public static final String TAG_GPS_LONGITUDE = "GPSLongitude";
-
     public static final String TAG_GPS_LATITUDE_REF = "GPSLatitudeRef";
     public static final String TAG_GPS_LONGITUDE_REF = "GPSLongitudeRef";
     public static final String TAG_WHITE_BALANCE = "WhiteBalance";
 
-    private boolean mSavedAttributes = false;
-    private boolean mHasThumbnail = false;
-    private HashMap<String, String> mCachedAttributes = null;
+    // Constants used for the Orientation Exif tag.
+    public static final int ORIENTATION_UNDEFINED = 0;
+    public static final int ORIENTATION_NORMAL = 1;
+    public static final int ORIENTATION_FLIP_HORIZONTAL = 2;  // left right reversed mirror
+    public static final int ORIENTATION_ROTATE_180 = 3;
+    public static final int ORIENTATION_FLIP_VERTICAL = 4;  // upside down mirror
+    public static final int ORIENTATION_TRANSPOSE = 5;  // flipped about top-left <--> bottom-right axis
+    public static final int ORIENTATION_ROTATE_90 = 6;  // rotate 90 cw to right it
+    public static final int ORIENTATION_TRANSVERSE = 7;  // flipped about top-right <--> bottom-left axis
+    public static final int ORIENTATION_ROTATE_270 = 8;  // rotate 270 to right it
+
+    // Constants used for white balance
+    public static final int WHITEBALANCE_AUTO = 0;
+    public static final int WHITEBALANCE_MANUAL = 1;
 
     static {
         System.loadLibrary("exif");
     }
 
-    private static ExifInterface sExifObj = null;
-    /**
-     * Since the underlying jhead native code is not thread-safe,
-     * ExifInterface should use singleton interface instead of public
-     * constructor.
-     */
-    private static synchronized ExifInterface instance() {
-        if (sExifObj == null) {
-            sExifObj = new ExifInterface();
-        }
+    private String mFilename;
+    private HashMap<String, String> mAttributes;
+    private boolean mHasThumbnail = false;
 
-        return sExifObj;
+    // Because the underlying implementation (jhead) uses static variables,
+    // there can only be one user at a time for the native functions (and
+    // they cannot keep state in the native code across function calls). We
+    // use sLock the serialize the accesses.
+    private static Object sLock = new Object();
+
+    /**
+     * Reads Exif tags from the specified JPEG file.
+     */
+    public ExifInterface(String filename) throws IOException {
+        mFilename = filename;
+        loadAttributes();
     }
 
     /**
-     * The following 3 static methods are handy routines for atomic operation
-     * of underlying jhead library. It retrieves EXIF data and then release
-     * ExifInterface immediately.
+     * Returns the value of the specified tag or {@code null} if there
+     * is no such tag in the file.
+     *
+     * @param tag the name of the tag.
      */
-    public static synchronized HashMap<String, String> loadExifData(String filename) {
-        ExifInterface exif = instance();
-        HashMap<String, String> exifData = null;
-        if (exif != null) {
-            exif.setFilename(filename);
-            exifData = exif.getAttributes();
-        }
-        return exifData;
-    }
-
-    public static synchronized void saveExifData(String filename, HashMap<String, String> exifData) {
-        ExifInterface exif = instance();
-        if (exif != null) {
-            exif.setFilename(filename);
-            exif.saveAttributes(exifData);
-        }
-    }
-
-    public static synchronized byte[] getExifThumbnail(String filename) {
-        ExifInterface exif = instance();
-        if (exif != null) {
-            exif.setFilename(filename);
-            return exif.getThumbnail();
-        }
-        return null;
-    }
-
-    public void setFilename(String filename) {
-        if (mFilename == null || !mFilename.equals(filename)) {
-            mFilename = filename;
-            mCachedAttributes = null;
-        }
+    public String getAttribute(String tag) {
+        return mAttributes.get(tag);
     }
 
     /**
-     * Given a HashMap of Exif tags and associated values, an Exif section in
-     * the JPG file is created and loaded with the tag data. saveAttributes()
-     * is expensive because it involves copying all the JPG data from one file
-     * to another and deleting the old file and renaming the other. It's best
-     * to collect all the attributes to write and make a single call rather
-     * than multiple calls for each attribute. You must call "commitChanges()"
-     * at some point to commit the changes.
+     * Set the value of the specified tag.
+     *
+     * @param tag the name of the tag.
+     * @param value the value of the tag.
      */
-    public void saveAttributes(HashMap<String, String> attributes) {
-        // format of string passed to native C code:
-        // "attrCnt attr1=valueLen value1attr2=value2Len value2..."
-        // example:
-        // "4 attrPtr ImageLength=4 1024Model=6 FooImageWidth=4 1280Make=3 FOO"
-        StringBuilder sb = new StringBuilder();
-        int size = attributes.size();
-        if (attributes.containsKey("hasThumbnail")) {
-            --size;
-        }
-        sb.append(size + " ");
-        for (Map.Entry<String, String> iter : attributes.entrySet()) {
-            String key = iter.getKey();
-            if (key.equals("hasThumbnail")) {
-                // this is a fake attribute not saved as an exif tag
-                continue;
-            }
-            String val = iter.getValue();
-            sb.append(key + "=");
-            sb.append(val.length() + " ");
-            sb.append(val);
-        }
-        String s = sb.toString();
-        saveAttributesNative(mFilename, s);
-        commitChangesNative(mFilename);
-        mSavedAttributes = true;
+    public void setAttribute(String tag, String value) {
+        mAttributes.put(tag, value);
     }
 
     /**
-     * Returns a HashMap loaded with the Exif attributes of the file. The key
-     * is the standard tag name and the value is the tag's value: e.g.
-     * Model -> Nikon. Numeric values are returned as strings.
+     * Initialize mAttributes with the attributes from the file mFilename.
+     *
+     * mAttributes is a HashMap which stores the Exif attributes of the file.
+     * The key is the standard tag name and the value is the tag's value: e.g.
+     * Model -> Nikon. Numeric values are stored as strings.
+     *
+     * This function also initialize mHasThumbnail to indicate whether the
+     * file has a thumbnail inside.
      */
-    public HashMap<String, String> getAttributes() {
-        if (mCachedAttributes != null) {
-            return mCachedAttributes;
-        }
+    private void loadAttributes() {
         // format of string passed from native C code:
         // "attrCnt attr1=valueLen value1attr2=value2Len value2..."
         // example:
         // "4 attrPtr ImageLength=4 1024Model=6 FooImageWidth=4 1280Make=3 FOO"
-        mCachedAttributes = new HashMap<String, String>();
+        mAttributes = new HashMap<String, String>();
 
-        String attrStr = getAttributesNative(mFilename);
+        String attrStr;
+        synchronized (sLock) {
+            attrStr = getAttributesNative(mFilename);
+        }
 
         // get count
         int ptr = attrStr.indexOf(' ');
@@ -215,17 +145,78 @@
             if (attrName.equals("hasThumbnail")) {
                 mHasThumbnail = attrValue.equalsIgnoreCase("true");
             } else {
-                mCachedAttributes.put(attrName, attrValue);
+                mAttributes.put(attrName, attrValue);
             }
         }
-        return mCachedAttributes;
     }
 
     /**
-     * Given a numerical white balance value, return a
-     * human-readable string describing it.
+     * Save the tag data into the JPEG file. This is expensive because it involves
+     * copying all the JPG data from one file to another and deleting the old file
+     * and renaming the other. It's best to use {@link #setAttribute(String,String)} to set all
+     * attributes to write and make a single call rather than multiple calls for
+     * each attribute.
      */
-    public static String whiteBalanceToString(int whitebalance) {
+    public void saveAttributes() throws IOException {
+        // format of string passed to native C code:
+        // "attrCnt attr1=valueLen value1attr2=value2Len value2..."
+        // example:
+        // "4 attrPtr ImageLength=4 1024Model=6 FooImageWidth=4 1280Make=3 FOO"
+        StringBuilder sb = new StringBuilder();
+        int size = mAttributes.size();
+        if (mAttributes.containsKey("hasThumbnail")) {
+            --size;
+        }
+        sb.append(size + " ");
+        for (Map.Entry<String, String> iter : mAttributes.entrySet()) {
+            String key = iter.getKey();
+            if (key.equals("hasThumbnail")) {
+                // this is a fake attribute not saved as an exif tag
+                continue;
+            }
+            String val = iter.getValue();
+            sb.append(key + "=");
+            sb.append(val.length() + " ");
+            sb.append(val);
+        }
+        String s = sb.toString();
+        synchronized (sLock) {
+            saveAttributesNative(mFilename, s);
+            commitChangesNative(mFilename);
+        }
+    }
+
+    /**
+     * Returns true if the JPEG file has a thumbnail.
+     */
+    public boolean hasThumbnail() {
+        return mHasThumbnail;
+    }
+
+    /**
+     * Returns the thumbnail inside the JPEG file, or {@code null} if there is no thumbnail.
+     */
+    public byte[] getThumbnail() {
+        synchronized (sLock) {
+            return getThumbnailNative(mFilename);
+        }
+    }
+
+    /**
+     * Returns a human-readable string describing the white balance value. Returns empty
+     * string if there is no white balance value or it is not recognized.
+     */
+    public String getWhiteBalanceString() {
+        String value = getAttribute(TAG_WHITE_BALANCE);
+        if (value == null) return "";
+
+        int whitebalance;
+        try {
+            whitebalance = Integer.parseInt(value);
+        } catch (NumberFormatException ex) {
+            return "";
+        }
+
         switch (whitebalance) {
             case WHITEBALANCE_AUTO:
                 return "Auto";
@@ -237,12 +228,21 @@
     }
 
     /**
-     * Given a numerical orientation, return a human-readable string describing
-     * the orientation.
+     * Returns a human-readable string describing the orientation value. Returns empty
+     * string if there is no orientation value or it it not recognized.
      */
-    public static String orientationToString(int orientation) {
-        // TODO: this function needs to be localized and use string resource ids
-        // rather than strings
+    public String getOrientationString() {
+        // TODO: this function needs to be localized.
+        String value = getAttribute(TAG_ORIENTATION);
+        if (value == null) return "";
+
+        int orientation;
+        try {
+            orientation = Integer.parseInt(value);
+        } catch (NumberFormatException ex) {
+            return "";
+        }
+
         String orientationString;
         switch (orientation) {
             case ORIENTATION_NORMAL:
@@ -277,48 +277,21 @@
     }
 
     /**
-     * Copies the thumbnail data out of the filename and puts it in the Exif
-     * data associated with the file used to create this object. You must call
-     * "commitChanges()" at some point to commit the changes.
+     * Returns the latitude and longitude value in a float array. The first element is
+     * the latitude, and the second element is the longitude.
      */
-    public boolean appendThumbnail(String thumbnailFileName) {
-        if (!mSavedAttributes) {
-            throw new RuntimeException("Must call saveAttributes "
-                    + "before calling appendThumbnail");
-        }
-        mHasThumbnail = appendThumbnailNative(mFilename, thumbnailFileName);
-        return mHasThumbnail;
-    }
-
-    public boolean hasThumbnail() {
-        if (!mSavedAttributes) {
-            getAttributes();
-        }
-        return mHasThumbnail;
-    }
-
-    public byte[] getThumbnail() {
-        return getThumbnailNative(mFilename);
-    }
-
-    public static float[] getLatLng(HashMap<String, String> exifData) {
-        if (exifData == null) {
-            return null;
-        }
-
-        String latValue = exifData.get(ExifInterface.TAG_GPS_LATITUDE);
-        String latRef = exifData.get(ExifInterface.TAG_GPS_LATITUDE_REF);
-        String lngValue = exifData.get(ExifInterface.TAG_GPS_LONGITUDE);
-        String lngRef = exifData.get(ExifInterface.TAG_GPS_LONGITUDE_REF);
+    public float[] getLatLong() {
+        String latValue = mAttributes.get(ExifInterface.TAG_GPS_LATITUDE);
+        String latRef = mAttributes.get(ExifInterface.TAG_GPS_LATITUDE_REF);
+        String lngValue = mAttributes.get(ExifInterface.TAG_GPS_LONGITUDE);
+        String lngRef = mAttributes.get(ExifInterface.TAG_GPS_LONGITUDE_REF);
         float[] latlng = null;
 
         if (latValue != null && latRef != null
                 && lngValue != null && lngRef != null) {
             latlng = new float[2];
-            latlng[0] = ExifInterface.convertRationalLatLonToFloat(
-                    latValue, latRef);
-            latlng[1] = ExifInterface.convertRationalLatLonToFloat(
-                    lngValue, lngRef);
+            latlng[0] = convertRationalLatLonToFloat(latValue, latRef);
+            latlng[1] = convertRationalLatLonToFloat(lngValue, lngRef);
         }
 
         return latlng;
@@ -327,14 +300,12 @@
     private static SimpleDateFormat sFormatter =
             new SimpleDateFormat("yyyy:MM:dd HH:mm:ss");
 
-    // Returns number of milliseconds since Jan. 1, 1970, midnight GMT.
-    // Returns -1 if the date time information if not available.
-    public static long getDateTime(HashMap<String, String> exifData) {
-        if (exifData == null) {
-            return -1;
-        }
-
-        String dateTimeString = exifData.get(ExifInterface.TAG_DATETIME);
+    /**
+     * Returns number of milliseconds since Jan. 1, 1970, midnight GMT.
+     * Returns -1 if the date time information if not available.
+     */
+    public long getDateTime() {
+        String dateTimeString = mAttributes.get(TAG_DATETIME);
         if (dateTimeString == null) return -1;
 
         ParsePosition pos = new ParsePosition(0);
@@ -347,7 +318,7 @@
         }
     }
 
-    public static float convertRationalLatLonToFloat(
+    private static float convertRationalLatLonToFloat(
             String rationalString, String ref) {
         try {
             String [] parts = rationalString.split(",");
@@ -377,42 +348,6 @@
         }
     }
 
-    public static String convertRationalLatLonToDecimalString(
-            String rationalString, String ref, boolean usePositiveNegative) {
-            float result = convertRationalLatLonToFloat(rationalString, ref);
-
-            String preliminaryResult = String.valueOf(result);
-            if (usePositiveNegative) {
-                String neg = (ref.equals("S") || ref.equals("E")) ? "-" : "";
-                return neg + preliminaryResult;
-            } else {
-                return preliminaryResult + String.valueOf((char) 186) + " "
-                        + ref;
-            }
-    }
-
-    public static String makeLatLongString(double d) {
-        d = Math.abs(d);
-
-        int degrees = (int) d;
-
-        double remainder = d - degrees;
-        int minutes = (int) (remainder * 60D);
-        // really seconds * 1000
-        int seconds = (int) (((remainder * 60D) - minutes) * 60D * 1000D);
-
-        String retVal = degrees + "/1," + minutes + "/1," + seconds + "/1000";
-        return retVal;
-    }
-
-    public static String makeLatStringRef(double lat) {
-        return lat >= 0D ? "N" : "S";
-    }
-
-    public static String makeLonStringRef(double lon) {
-        return lon >= 0D ? "W" : "E";
-    }
-
     private native boolean appendThumbnailNative(String fileName,
             String thumbnailFileName);
 
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index f6d30e0..d9127e7 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -719,16 +719,20 @@
                 values.put(Audio.Media.IS_MUSIC, music);
                 values.put(Audio.Media.IS_PODCAST, podcasts);
             } else if (mFileType == MediaFile.FILE_TYPE_JPEG) {
-                HashMap<String, String> exifData =
-                        ExifInterface.loadExifData(entry.mPath);
-                if (exifData != null) {
-                    float[] latlng = ExifInterface.getLatLng(exifData);
+                ExifInterface exif = null;
+                try {
+                    exif = new ExifInterface(entry.mPath);
+                } catch (IOException ex) {
+                    // exif is null
+                }
+                if (exif != null) {
+                    float[] latlng = exif.getLatLong();
                     if (latlng != null) {
                         values.put(Images.Media.LATITUDE, latlng[0]);
                         values.put(Images.Media.LONGITUDE, latlng[1]);
                     }
 
-                    long time = ExifInterface.getDateTime(exifData);
+                    long time = exif.getDateTime();
                     if (time != -1) {
                         values.put(Images.Media.DATE_TAKEN, time);
                     }
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 22c2f39..ba4c4c7 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -229,6 +229,7 @@
     }
     if (!strncmp(componentName, "OMX.qcom.video.decoder.", 23)) {
         // XXX Required on P....on only.
+        quirks |= kRequiresAllocateBufferOnInputPorts;
         quirks |= kRequiresAllocateBufferOnOutputPorts;
     }
 
diff --git a/media/libstagefright/omx/SoftwareRenderer.cpp b/media/libstagefright/omx/SoftwareRenderer.cpp
index a1c478f..4ed6869 100644
--- a/media/libstagefright/omx/SoftwareRenderer.cpp
+++ b/media/libstagefright/omx/SoftwareRenderer.cpp
@@ -65,6 +65,8 @@
 
 void SoftwareRenderer::render(
         const void *data, size_t size, void *platformPrivate) {
+    static const int OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00;
+
     switch (mColorFormat) {
         case OMX_COLOR_FormatYUV420Planar:
             return renderYUV420Planar(data, size);
@@ -72,6 +74,9 @@
         case OMX_COLOR_FormatCbYCrY:
             return renderCbYCrY(data, size);
 
+        case OMX_QCOM_COLOR_FormatYVU420SemiPlanar:
+            return renderQCOMYUV420SemiPlanar(data, size);
+
         default:
         {
             LOGW("Cannot render color format %ld", mColorFormat);
@@ -242,6 +247,76 @@
     mIndex = 1 - mIndex;
 }
 
+void SoftwareRenderer::renderQCOMYUV420SemiPlanar(
+        const void *data, size_t size) {
+    if (size != (mDecodedHeight * mDecodedWidth * 3) / 2) {
+        LOGE("size is %d, expected %d",
+                size, (mDecodedHeight * mDecodedWidth * 3) / 2);
+    }
+    CHECK(size >= (mDecodedWidth * mDecodedHeight * 3) / 2);
+
+    uint8_t *kAdjustedClip = initClip();
+
+    size_t offset = mIndex * mFrameSize;
+
+    void *dst = (uint8_t *)mMemoryHeap->getBase() + offset;
+
+    uint32_t *dst_ptr = (uint32_t *)dst;
+
+    const uint8_t *src_y = (const uint8_t *)data;
+
+    const uint8_t *src_u =
+        (const uint8_t *)src_y + mDecodedWidth * mDecodedHeight;
+
+    for (size_t y = 0; y < mDecodedHeight; ++y) {
+        for (size_t x = 0; x < mDecodedWidth; x += 2) {
+            signed y1 = (signed)src_y[x] - 16;
+            signed y2 = (signed)src_y[x + 1] - 16;
+
+            signed u = (signed)src_u[x & ~1] - 128;
+            signed v = (signed)src_u[(x & ~1) + 1] - 128;
+
+            signed u_b = u * 517;
+            signed u_g = -u * 100;
+            signed v_g = -v * 208;
+            signed v_r = v * 409;
+
+            signed tmp1 = y1 * 298;
+            signed b1 = (tmp1 + u_b) / 256;
+            signed g1 = (tmp1 + v_g + u_g) / 256;
+            signed r1 = (tmp1 + v_r) / 256;
+
+            signed tmp2 = y2 * 298;
+            signed b2 = (tmp2 + u_b) / 256;
+            signed g2 = (tmp2 + v_g + u_g) / 256;
+            signed r2 = (tmp2 + v_r) / 256;
+
+            uint32_t rgb1 =
+                ((kAdjustedClip[b1] >> 3) << 11)
+                | ((kAdjustedClip[g1] >> 2) << 5)
+                | (kAdjustedClip[r1] >> 3);
+
+            uint32_t rgb2 =
+                ((kAdjustedClip[b2] >> 3) << 11)
+                | ((kAdjustedClip[g2] >> 2) << 5)
+                | (kAdjustedClip[r2] >> 3);
+
+            dst_ptr[x / 2] = (rgb2 << 16) | rgb1;
+        }
+
+        src_y += mDecodedWidth;
+
+        if (y & 1) {
+            src_u += mDecodedWidth;
+        }
+
+        dst_ptr += mDecodedWidth / 2;
+    }
+
+    mISurface->postBuffer(offset);
+    mIndex = 1 - mIndex;
+}
+
 uint8_t *SoftwareRenderer::initClip() {
     static const signed kClipMin = -278;
     static const signed kClipMax = 535;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
index a86ef8f9..ef211b3 100755
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
@@ -406,7 +406,7 @@
   public static final String META_DATA_OTHERS [][] = {
       {"/sdcard/media_api/metaDataTestMedias/3GP/cat.3gp", null, null, null,
           null, null, "20080309T002415.000Z", null,
-          null, null, "1404928", "2", null},
+          null, null, "63916", "2", null},
       {"/sdcard/media_api/metaDataTestMedias/AMR/AMR_NB.amr", null, null, null,
           null, null, null, null,
           null, null, "126540", "1", null},
@@ -424,7 +424,7 @@
           null, null, "2005", "231180", "1", null},
       {"/sdcard/media_api/metaDataTestMedias/MP4/kung_fu_panda_h264.mp4", "2/0", "mp4 album Kung Fu Panda",
           "mp4 artist Kung Fu Panda", null, null, "20080517T091451.000Z", 
-          "41", "Kung Fu Panda", "2008", "77113", "2", "mp4 composer"},
+          "41", "Kung Fu Panda", "2008", "128521", "2", "mp4 composer"},
       {"/sdcard/media_api/metaDataTestMedias/OGG/Ring_Classic_02.ogg", null, "Suspended Animation", 
           "John Petrucci", null, null, "20070510T125223.000Z", 
           null, null, "2005", "231180", "1", null},
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java
index 69e93a1..10796f1 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaRecorderStressTest.java
@@ -16,6 +16,7 @@
 
 package com.android.mediaframeworktest.stress;
 
+
 import com.android.mediaframeworktest.MediaFrameworkTest;
 
 import java.io.BufferedWriter;
@@ -26,6 +27,7 @@
 import android.hardware.Camera;
 import android.media.MediaPlayer;
 import android.media.MediaRecorder;
+import android.os.Looper;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Log;
@@ -54,7 +56,14 @@
     private static final String OUTPUT_FILE_EXT = ".3gp";
     private static final String MEDIA_STRESS_OUTPUT =
         "/sdcard/mediaStressOutput.txt";
-    
+    private Looper mCameraLooper = null;
+    private Looper mRecorderLooper = null;
+    private final Object lock = new Object();
+    private final Object recorderlock = new Object();
+    private static int WAIT_FOR_COMMAND_TO_COMPLETE = 10000;  // Milliseconds.
+    private final CameraErrorCallback mCameraErrorCallback = new CameraErrorCallback();
+    private final RecorderErrorCallback mRecorderErrorCallback = new RecorderErrorCallback();
+
     public MediaRecorderStressTest() {
         super("com.android.mediaframeworktest", MediaFrameworkTest.class);
     }
@@ -63,41 +72,129 @@
         getActivity();
         super.setUp();      
     }
-       
+
+    private final class CameraErrorCallback implements android.hardware.Camera.ErrorCallback {
+        public void onError(int error, android.hardware.Camera camera) {
+            if (error == android.hardware.Camera.CAMERA_ERROR_SERVER_DIED) {
+                assertTrue("Camera test mediaserver died", false);
+            }
+        }
+    }
+
+    private final class RecorderErrorCallback implements MediaRecorder.OnErrorListener {
+        public void onError(MediaRecorder mr, int what, int extra) {
+            // fail the test case no matter what error come up
+            assertTrue("mediaRecorder error", false);
+        }
+    }
+
+    private void initializeCameraMessageLooper() {
+        Log.v(TAG, "start looper");
+        new Thread() {
+            @Override
+            public void run() {
+                // Set up a looper to be used by camera.
+                Looper.prepare();
+                Log.v(TAG, "start loopRun");
+                mCameraLooper = Looper.myLooper();
+                mCamera = Camera.open();
+                synchronized (lock) {
+                    lock.notify();
+                }
+                Looper.loop();
+                Log.v(TAG, "initializeMessageLooper: quit.");
+            }
+        }.start();
+    }
+
+    private void initializeRecorderMessageLooper() {
+        Log.v(TAG, "start looper");
+        new Thread() {
+            @Override
+            public void run() {
+                Looper.prepare();
+                Log.v(TAG, "start loopRun");
+                mRecorderLooper = Looper.myLooper();
+                mRecorder = new MediaRecorder();
+                synchronized (recorderlock) {
+                    recorderlock.notify();
+                }
+                Looper.loop();  // Blocks forever until Looper.quit() is called.
+                Log.v(TAG, "initializeMessageLooper: quit.");
+            }
+        }.start();
+    }
+
+    /*
+     * Terminates the message looper thread.
+     */
+    private void terminateCameraMessageLooper() {
+        mCameraLooper.quit();
+        try {
+            Thread.sleep(1000);
+        } catch (Exception e){
+            Log.v(TAG, e.toString());
+        }
+        mCamera.release();
+    }
+
+    /*
+     * Terminates the message looper thread.
+     */
+    private void terminateRecorderMessageLooper() {
+        mRecorderLooper.quit();
+        try {
+            Thread.sleep(1000);
+        } catch (Exception e){
+            Log.v(TAG, e.toString());
+        }
+        mRecorder.release();
+    }
+
     //Test case for stressing the camera preview.
     @LargeTest
     public void testStressCamera() throws Exception {
-        SurfaceHolder mSurfaceHolder;             
+        SurfaceHolder mSurfaceHolder;
         mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
         File stressOutFile = new File(MEDIA_STRESS_OUTPUT);
         Writer output = new BufferedWriter(new FileWriter(stressOutFile, true));
         output.write("Camera start preview stress:\n");
-        output.write("Total number of loops:" + 
+        output.write("Total number of loops:" +
                 NUMBER_OF_CAMERA_STRESS_LOOPS + "\n");
-        try {        
+        try {
             Log.v(TAG, "Start preview");
             output.write("No of loop: ");
+
             for (int i = 0; i< NUMBER_OF_CAMERA_STRESS_LOOPS; i++){
-                mCamera = Camera.open();
+                synchronized (lock) {
+                    initializeCameraMessageLooper();
+                    try {
+                        lock.wait(WAIT_FOR_COMMAND_TO_COMPLETE);
+                    } catch(Exception e) {
+                        Log.v(TAG, "wait was interrupted.");
+                    }
+                }
+                mCamera.setErrorCallback(mCameraErrorCallback);
                 mCamera.setPreviewDisplay(mSurfaceHolder);
                 mCamera.startPreview();
                 Thread.sleep(WAIT_TIME_CAMERA_TEST);
                 mCamera.stopPreview();
-                mCamera.release();
+                terminateCameraMessageLooper();
                 output.write(" ," + i);
             }
         } catch (Exception e) {
-                Log.v(TAG, e.toString());
+            assertTrue("CameraStressTest", false);
+            Log.v(TAG, e.toString());
         }
         output.write("\n\n");
         output.close();
     }
-    
+
     //Test case for stressing the camera preview.
     @LargeTest
     public void testStressRecorder() throws Exception {
         String filename;
-        SurfaceHolder mSurfaceHolder;             
+        SurfaceHolder mSurfaceHolder;
         mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
         File stressOutFile = new File(MEDIA_STRESS_OUTPUT);
         Writer output = new BufferedWriter(new FileWriter(stressOutFile, true));
@@ -108,12 +205,20 @@
             output.write("No of loop: ");
             Log.v(TAG, "Start preview");
             for (int i = 0; i < NUMBER_OF_RECORDER_STRESS_LOOPS; i++){
+                synchronized (recorderlock) {
+                    initializeRecorderMessageLooper();
+                    try {
+                        recorderlock.wait(WAIT_FOR_COMMAND_TO_COMPLETE);
+                    } catch(Exception e) {
+                        Log.v(TAG, "wait was interrupted.");
+                    }
+                }
                 Log.v(TAG, "counter = " + i);
                 filename = OUTPUT_FILE + i + OUTPUT_FILE_EXT;
                 Log.v(TAG, filename);
-                mRecorder = new MediaRecorder();
+                mRecorder.setOnErrorListener(mRecorderErrorCallback);
                 mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
-                mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);          
+                mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
                 mRecorder.setOutputFile(filename);
                 mRecorder.setVideoFrameRate(20);
                 mRecorder.setVideoSize(176,144);
@@ -125,47 +230,63 @@
                 Log.v(TAG, "prepare");
                 mRecorder.prepare();
                 Log.v(TAG, "before release");
-                Thread.sleep(WAIT_TIME_RECORDER_TEST);  
+                Thread.sleep(WAIT_TIME_RECORDER_TEST);
                 mRecorder.reset();
-                mRecorder.release();
+                terminateRecorderMessageLooper();
                 output.write(", " + i);
             }
         } catch (Exception e) {
-                Log.v(TAG, e.toString());
+            assertTrue("Recorder Stress test", false);
+            Log.v(TAG, e.toString());
         }
         output.write("\n\n");
         output.close();
     }
-    
-    
+
     //Stress test case for switching camera and video recorder preview.
     @LargeTest
     public void testStressCameraSwitchRecorder() throws Exception {
         String filename;
-        SurfaceHolder mSurfaceHolder;             
+        SurfaceHolder mSurfaceHolder;
         mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
         File stressOutFile = new File(MEDIA_STRESS_OUTPUT);
         Writer output = new BufferedWriter(new FileWriter(stressOutFile, true));
         output.write("Camera and video recorder preview switching\n");
         output.write("Total number of loops:"
                 + NUMBER_OF_SWTICHING_LOOPS_BW_CAMERA_AND_RECORDER + "\n");
-        try {    
+        try {
             Log.v(TAG, "Start preview");
             output.write("No of loop: ");
             for (int i = 0; i < NUMBER_OF_SWTICHING_LOOPS_BW_CAMERA_AND_RECORDER; i++){
-                mCamera = Camera.open();
+                synchronized (lock) {
+                    initializeCameraMessageLooper();
+                    try {
+                        lock.wait(WAIT_FOR_COMMAND_TO_COMPLETE);
+                    } catch(Exception e) {
+                        Log.v(TAG, "wait was interrupted.");
+                    }
+                }
+                mCamera.setErrorCallback(mCameraErrorCallback);
                 mCamera.setPreviewDisplay(mSurfaceHolder);
                 mCamera.startPreview();
                 Thread.sleep(WAIT_TIME_CAMERA_TEST);
                 mCamera.stopPreview();
-                mCamera.release();
+                terminateCameraMessageLooper();
                 mCamera = null;
                 Log.v(TAG, "release camera");
                 filename = OUTPUT_FILE + i + OUTPUT_FILE_EXT;
                 Log.v(TAG, filename);
-                mRecorder = new MediaRecorder();
+                synchronized (recorderlock) {
+                    initializeRecorderMessageLooper();
+                    try {
+                        recorderlock.wait(WAIT_FOR_COMMAND_TO_COMPLETE);
+                    } catch(Exception e) {
+                        Log.v(TAG, "wait was interrupted.");
+                    }
+                }
+                mRecorder.setOnErrorListener(mRecorderErrorCallback);
                 mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
-                mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);          
+                mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
                 mRecorder.setOutputFile(filename);
                 mRecorder.setVideoFrameRate(20);
                 mRecorder.setVideoSize(176,144);
@@ -176,23 +297,24 @@
                 Log.v(TAG, "prepare");
                 mRecorder.prepare();
                 Log.v(TAG, "before release");
-                Thread.sleep(WAIT_TIME_CAMERA_TEST);  
-                mRecorder.release();
+                Thread.sleep(WAIT_TIME_CAMERA_TEST);
+                terminateRecorderMessageLooper();
                 Log.v(TAG, "release video recorder");
                 output.write(", " + i);
             }
         } catch (Exception e) {
+            assertTrue("Camer and recorder switch mode", false);
                 Log.v(TAG, e.toString());
         }
         output.write("\n\n");
         output.close();
     }
-    
+
     //Stress test case for record a video and play right away.
     @LargeTest
     public void testStressRecordVideoAndPlayback() throws Exception {
         String filename;
-        SurfaceHolder mSurfaceHolder;             
+        SurfaceHolder mSurfaceHolder;
         mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
         File stressOutFile = new File(MEDIA_STRESS_OUTPUT);
         Writer output = new BufferedWriter(new FileWriter(stressOutFile, true));
@@ -204,10 +326,18 @@
             for (int i = 0; i < NUMBER_OF_RECORDERANDPLAY_STRESS_LOOPS; i++){
                 filename = OUTPUT_FILE + i + OUTPUT_FILE_EXT;
                 Log.v(TAG, filename);
-                mRecorder = new MediaRecorder();
+                synchronized (recorderlock) {
+                    initializeRecorderMessageLooper();
+                    try {
+                        recorderlock.wait(WAIT_FOR_COMMAND_TO_COMPLETE);
+                    } catch(Exception e) {
+                        Log.v(TAG, "wait was interrupted.");
+                    }
+                }
+                mRecorder.setOnErrorListener(mRecorderErrorCallback);
                 mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
                 mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
-                mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);          
+                mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
                 mRecorder.setOutputFile(filename);
                 mRecorder.setVideoFrameRate(20);
                 mRecorder.setVideoSize(352,288);
@@ -216,11 +346,11 @@
                 Log.v(TAG, "mediaRecorder setPreview");
                 mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
                 mRecorder.prepare();
-                mRecorder.start();               
+                mRecorder.start();
                 Thread.sleep(WAIT_TIME_RECORD);
                 Log.v(TAG, "Before stop");
                 mRecorder.stop();
-                mRecorder.release();
+                terminateRecorderMessageLooper();
                 //start the playback
                 MediaPlayer mp = new MediaPlayer();
                 mp.setDataSource(filename);
@@ -232,10 +362,10 @@
                 output.write(", " + i);
             }
         } catch (Exception e) {
+            assertTrue("record and playback", false);
                 Log.v(TAG, e.toString());
         }
         output.write("\n\n");
         output.close();
-    }   
+    }
 }
-
diff --git a/preloaded-classes b/preloaded-classes
index 3da4797..8c5e835 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -724,6 +724,7 @@
 com.ibm.icu4jni.text.NativeDecimalFormat$UNumberFormatAttribute
 com.ibm.icu4jni.text.NativeDecimalFormat$UNumberFormatSymbol
 com.ibm.icu4jni.text.RuleBasedCollator
+com.ibm.icu4jni.util.Resources$DefaultTimeZones
 dalvik.system.DexFile
 dalvik.system.PathClassLoader
 java.beans.PropertyChangeEvent
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 0e60dd6..c6be61d 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -649,11 +649,21 @@
         int N = packages.size();
         for (int a = N-1; a >= 0; a--) {
             PackageInfo pkg = packages.get(a);
-            ApplicationInfo app = pkg.applicationInfo;
-            if (((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0)
-                    || app.backupAgentName == null
-                    || (mPackageManager.checkPermission(android.Manifest.permission.BACKUP_DATA,
-                            pkg.packageName) != PackageManager.PERMISSION_GRANTED)) {
+            try {
+                ApplicationInfo app = pkg.applicationInfo;
+                if (((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0)
+                        || app.backupAgentName == null
+                        || (mPackageManager.checkPermission(android.Manifest.permission.BACKUP_DATA,
+                                pkg.packageName) != PackageManager.PERMISSION_GRANTED)) {
+                    packages.remove(a);
+                }
+                else {
+                    // we will need the shared library path, so look that up and store it here
+                    app = mPackageManager.getApplicationInfo(pkg.packageName,
+                            PackageManager.GET_SHARED_LIBRARY_FILES);
+                    pkg.applicationInfo.sharedLibraryFiles = app.sharedLibraryFiles;
+                }
+            } catch (NameNotFoundException e) {
                 packages.remove(a);
             }
         }
diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java
index 30c25e0..60195b9 100644
--- a/services/java/com/android/server/DockObserver.java
+++ b/services/java/com/android/server/DockObserver.java
@@ -16,6 +16,7 @@
 
 package com.android.server;
 
+import android.content.ActivityNotFoundException;
 import android.content.Context;
 import android.content.Intent;
 import android.os.Handler;
@@ -111,6 +112,30 @@
                 Intent intent = new Intent(Intent.ACTION_DOCK_EVENT);
                 intent.putExtra(Intent.EXTRA_DOCK_STATE, mDockState);
                 mContext.sendStickyBroadcast(intent);
+
+                // Launch a dock activity
+                String category;
+                switch (mDockState) {
+                    case Intent.EXTRA_DOCK_STATE_CAR:
+                        category = Intent.CATEGORY_CAR_DOCK;
+                        break;
+                    case Intent.EXTRA_DOCK_STATE_DESK:
+                        category = Intent.CATEGORY_DESK_DOCK;
+                        break;
+                    default:
+                        category = null;
+                        break;
+                }
+                if (category != null) {
+                    intent = new Intent(Intent.ACTION_MAIN);
+                    intent.addCategory(category);
+                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                    try {
+                        mContext.startActivity(intent);
+                    } catch (ActivityNotFoundException e) {
+                        Log.w(TAG, e.getCause());
+                    }
+                }
             }
         }
     };
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index af60556..f6a1be7 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -1069,13 +1069,13 @@
             return mIntent;
         }
 
-        boolean isInProximity(double latitude, double longitude) {
+        boolean isInProximity(double latitude, double longitude, float accuracy) {
             Location loc = new Location("");
             loc.setLatitude(latitude);
             loc.setLongitude(longitude);
 
             double radius = loc.distanceTo(mLocation);
-            return radius <= mRadius;
+            return radius <= Math.max(mRadius,accuracy);
         }
         
         @Override
@@ -1115,6 +1115,7 @@
             long now = System.currentTimeMillis();
             double latitude = loc.getLatitude();
             double longitude = loc.getLongitude();
+            float accuracy = loc.getAccuracy();
             ArrayList<PendingIntent> intentsToRemove = null;
 
             for (ProximityAlert alert : mProximityAlerts.values()) {
@@ -1124,7 +1125,7 @@
                 if ((expiration == -1) || (now <= expiration)) {
                     boolean entered = mProximitiesEntered.contains(alert);
                     boolean inProximity =
-                        alert.isInProximity(latitude, longitude);
+                        alert.isInProximity(latitude, longitude, accuracy);
                     if (!entered && inProximity) {
                         if (LOCAL_LOGV) {
                             Log.v(TAG, "Entered alert");
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 82cf1bc..45e0ceb 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -3611,9 +3611,18 @@
         mHandler.post(new Runnable() {
             public void run() {
                 mHandler.removeCallbacks(this);
-                PackageInstalledInfo res;
-                synchronized (mInstallLock) {
-                    res = installPackageLI(packageURI, flags, true, installerPackageName);
+                 // Result object to be returned
+                PackageInstalledInfo res = new PackageInstalledInfo();
+                res.returnCode = PackageManager.INSTALL_SUCCEEDED;
+                res.uid = -1;
+                res.pkg = null;
+                res.removedInfo = new PackageRemovedInfo();
+                // Make a temporary copy of file from given packageURI
+                File tmpPackageFile = copyTempInstallFile(packageURI, res);
+                if (tmpPackageFile != null) {
+                    synchronized (mInstallLock) {
+                        installPackageLI(packageURI, flags, true, installerPackageName, tmpPackageFile, res);
+                    }
                 }
                 if (observer != null) {
                     try {
@@ -3828,11 +3837,30 @@
             // Since we failed to install the new package we need to restore the old
             // package that we deleted.
             if(deletedPkg) {
+                File restoreFile = new File(deletedPackage.mPath);
+                if (restoreFile == null) {
+                    Log.e(TAG, "Failed allocating storage when restoring pkg : " + pkgName);
+                    return;
+                }
+                File restoreTmpFile = createTempPackageFile();
+                if (restoreTmpFile == null) {
+                    Log.e(TAG, "Failed creating temp file when restoring pkg :  " + pkgName);
+                    return;
+                }
+                if (!FileUtils.copyFile(restoreFile, restoreTmpFile)) {
+                    Log.e(TAG, "Failed copying temp file when restoring pkg : " + pkgName);
+                    return;
+                }
+                PackageInstalledInfo restoreRes = new PackageInstalledInfo();
+                restoreRes.removedInfo = new PackageRemovedInfo();
                 installPackageLI(
-                        Uri.fromFile(new File(deletedPackage.mPath)),
+                        Uri.fromFile(restoreFile),
                         isForwardLocked(deletedPackage)
                         ? PackageManager.INSTALL_FORWARD_LOCK
-                                : 0, false, oldInstallerPackageName);
+                                : 0, false, oldInstallerPackageName, restoreTmpFile, restoreRes);
+                if (restoreRes.returnCode != PackageManager.INSTALL_SUCCEEDED) {
+                    Log.e(TAG, "Failed restoring pkg : " + pkgName + " after failed upgrade");
+                }
             }
         }
     }
@@ -3995,50 +4023,36 @@
         return new File(mAppInstallDir, publicZipFileName);
     }
 
-    private PackageInstalledInfo installPackageLI(Uri pPackageURI,
-            int pFlags, boolean newInstall, String installerPackageName) {
-        File tmpPackageFile = null;
-        String pkgName = null;
-        boolean forwardLocked = false;
-        boolean replacingExistingPackage = false;
-        // Result object to be returned
-        PackageInstalledInfo res = new PackageInstalledInfo();
-        res.returnCode = PackageManager.INSTALL_SUCCEEDED;
-        res.uid = -1;
-        res.pkg = null;
-        res.removedInfo = new PackageRemovedInfo();
+    private File copyTempInstallFile(Uri pPackageURI,
+            PackageInstalledInfo res) {
+        File tmpPackageFile = createTempPackageFile();
+        int retCode = PackageManager.INSTALL_SUCCEEDED;
+        if (tmpPackageFile == null) {
+            res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+            return null;
+        }
 
-        main_flow: try {
-            tmpPackageFile = createTempPackageFile();
-            if (tmpPackageFile == null) {
-                res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
-                break main_flow;
+        if (pPackageURI.getScheme().equals("file")) {
+            final File srcPackageFile = new File(pPackageURI.getPath());
+            // We copy the source package file to a temp file and then rename it to the
+            // destination file in order to eliminate a window where the package directory
+            // scanner notices the new package file but it's not completely copied yet.
+            if (!FileUtils.copyFile(srcPackageFile, tmpPackageFile)) {
+                Log.e(TAG, "Couldn't copy package file to temp file.");
+                retCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
             }
-            tmpPackageFile.deleteOnExit();  // paranoia
-            if (pPackageURI.getScheme().equals("file")) {
-                final File srcPackageFile = new File(pPackageURI.getPath());
-                // We copy the source package file to a temp file and then rename it to the
-                // destination file in order to eliminate a window where the package directory
-                // scanner notices the new package file but it's not completely copied yet.
-                if (!FileUtils.copyFile(srcPackageFile, tmpPackageFile)) {
-                    Log.e(TAG, "Couldn't copy package file to temp file.");
-                    res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
-                    break main_flow;
-                }
-            } else if (pPackageURI.getScheme().equals("content")) {
-                ParcelFileDescriptor fd;
-                try {
-                    fd = mContext.getContentResolver().openFileDescriptor(pPackageURI, "r");
-                } catch (FileNotFoundException e) {
-                    Log.e(TAG, "Couldn't open file descriptor from download service.");
-                    res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
-                    break main_flow;
-                }
-                if (fd == null) {
-                    Log.e(TAG, "Couldn't open file descriptor from download service (null).");
-                    res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
-                    break main_flow;
-                }
+        } else if (pPackageURI.getScheme().equals("content")) {
+            ParcelFileDescriptor fd = null;
+            try {
+                fd = mContext.getContentResolver().openFileDescriptor(pPackageURI, "r");
+            } catch (FileNotFoundException e) {
+                Log.e(TAG, "Couldn't open file descriptor from download service. Failed with exception " + e);
+                retCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+            }
+            if (fd == null) {
+                Log.e(TAG, "Couldn't open file descriptor from download service (null).");
+                retCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+            } else {
                 if (Config.LOGV) {
                     Log.v(TAG, "Opened file descriptor from download service.");
                 }
@@ -4049,14 +4063,34 @@
                 // scanner notices the new package file but it's not completely copied yet.
                 if (!FileUtils.copyToFile(dlStream, tmpPackageFile)) {
                     Log.e(TAG, "Couldn't copy package stream to temp file.");
-                    res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
-                    break main_flow;
+                    retCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
                 }
-            } else {
-                Log.e(TAG, "Package URI is not 'file:' or 'content:' - " + pPackageURI);
-                res.returnCode = PackageManager.INSTALL_FAILED_INVALID_URI;
-                break main_flow;
             }
+        } else {
+            Log.e(TAG, "Package URI is not 'file:' or 'content:' - " + pPackageURI);
+            retCode = PackageManager.INSTALL_FAILED_INVALID_URI;
+        }
+
+        res.returnCode = retCode;
+        if (retCode != PackageManager.INSTALL_SUCCEEDED) {
+            if (tmpPackageFile != null && tmpPackageFile.exists()) {
+                tmpPackageFile.delete();
+            }
+            return null;
+        }
+        return tmpPackageFile;
+    }
+
+    private void installPackageLI(Uri pPackageURI,
+            int pFlags, boolean newInstall, String installerPackageName,
+            File tmpPackageFile, PackageInstalledInfo res) {
+        String pkgName = null;
+        boolean forwardLocked = false;
+        boolean replacingExistingPackage = false;
+        // Result object to be returned
+        res.returnCode = PackageManager.INSTALL_SUCCEEDED;
+
+        main_flow: try {
             pkgName = PackageParser.parsePackageName(
                     tmpPackageFile.getAbsolutePath(), 0);
             if (pkgName == null) {
@@ -4128,7 +4162,6 @@
                 tmpPackageFile.delete();
             }
         }
-        return res;
     }
     
     private int setPermissionsLI(String pkgName,
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 53ff78e..63bef54 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -665,6 +665,15 @@
                 }
             }
         }
+
+        for (WifiConfiguration.EnterpriseField field :
+                config.enterpriseFields) {
+            value = WifiNative.getNetworkVariableCommand(netId,
+                    field.varName());
+            if (!TextUtils.isEmpty(value)) {
+                field.setValue(value);
+            }
+        }
     }
 
     /**
@@ -877,103 +886,20 @@
                 break setVariables;
             }
 
-            if ((config.eap != null) && !WifiNative.setNetworkVariableCommand(
+            for (WifiConfiguration.EnterpriseField field
+                    : config.enterpriseFields) {
+                String varName = field.varName();
+                String value = field.value();
+                if ((value != null) && !WifiNative.setNetworkVariableCommand(
                     netId,
-                    WifiConfiguration.eapVarName,
-                    config.eap)) {
-                if (DBG) {
-                    Log.d(TAG, config.SSID + ": failed to set eap: "+
-                          config.eap);
+                    varName,
+                    value)) {
+                    if (DBG) {
+                        Log.d(TAG, config.SSID + ": failed to set " + varName +
+                              ": " + value);
+                    }
+                    break setVariables;
                 }
-                break setVariables;
-            }
-
-            if ((config.phase2 != null) && !WifiNative.setNetworkVariableCommand(
-                    netId,
-                    WifiConfiguration.phase2VarName,
-                    config.phase2)) {
-                if (DBG) {
-                    Log.d(TAG, config.SSID + ": failed to set phase2: "+
-                          config.phase2);
-                }
-                break setVariables;
-            }
-
-            if ((config.identity != null) && !WifiNative.setNetworkVariableCommand(
-                    netId,
-                    WifiConfiguration.identityVarName,
-                    config.identity)) {
-                if (DBG) {
-                    Log.d(TAG, config.SSID + ": failed to set identity: "+
-                          config.identity);
-                }
-                break setVariables;
-            }
-
-            if ((config.anonymousIdentity != null) && !WifiNative.setNetworkVariableCommand(
-                    netId,
-                    WifiConfiguration.anonymousIdentityVarName,
-                    config.anonymousIdentity)) {
-                if (DBG) {
-                    Log.d(TAG, config.SSID + ": failed to set anonymousIdentity: "+
-                          config.anonymousIdentity);
-                }
-                break setVariables;
-            }
-
-            if ((config.password != null) && !WifiNative.setNetworkVariableCommand(
-                    netId,
-                    WifiConfiguration.passwordVarName,
-                    config.password)) {
-                if (DBG) {
-                    Log.d(TAG, config.SSID + ": failed to set password: "+
-                          config.password);
-                }
-                break setVariables;
-            }
-
-            if ((config.clientCert != null) && !WifiNative.setNetworkVariableCommand(
-                    netId,
-                    WifiConfiguration.clientCertVarName,
-                    config.clientCert)) {
-                if (DBG) {
-                    Log.d(TAG, config.SSID + ": failed to set clientCert: "+
-                          config.clientCert);
-                }
-                break setVariables;
-            }
-
-            if ((config.caCert != null) && !WifiNative.setNetworkVariableCommand(
-                    netId,
-                    WifiConfiguration.caCertVarName,
-                    config.caCert)) {
-                if (DBG) {
-                    Log.d(TAG, config.SSID + ": failed to set caCert: "+
-                          config.caCert);
-                }
-                break setVariables;
-            }
-
-            if ((config.privateKey != null) && !WifiNative.setNetworkVariableCommand(
-                    netId,
-                    WifiConfiguration.privateKeyVarName,
-                    config.privateKey)) {
-                if (DBG) {
-                    Log.d(TAG, config.SSID + ": failed to set privateKey: "+
-                          config.privateKey);
-                }
-                break setVariables;
-            }
-
-            if ((config.privateKeyPasswd != null) && !WifiNative.setNetworkVariableCommand(
-                    netId,
-                    WifiConfiguration.privateKeyPasswdVarName,
-                    config.privateKeyPasswd)) {
-                if (DBG) {
-                    Log.d(TAG, config.SSID + ": failed to set privateKeyPasswd: "+
-                          config.privateKeyPasswd);
-                }
-                break setVariables;
             }
 
             return netId;
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 8e85a6a..d53f002 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -442,6 +442,8 @@
     // Who is holding the screen on.
     Session mHoldingScreenOn;
 
+    boolean mTurnOnScreen;
+    
     /**
      * Whether the UI is currently running in touch mode (not showing
      * navigational focus because the user is directly pressing the screen).
@@ -1244,12 +1246,6 @@
                             "Skipping hidden or animating token: " + w);
                     continue;
                 }
-                // If this window's app token is ot fullscreen, also irrelevant.
-                if (!w.mAppToken.appFullscreen) {
-                    if (DEBUG_WALLPAPER) Log.v(TAG,
-                            "Skipping non-fullscreen token: " + w);
-                    continue;
-                }
             }
             if (DEBUG_WALLPAPER) Log.v(TAG, "Win " + w + ": readyfordisplay="
                     + w.isReadyForDisplay() + " drawpending=" + w.mDrawPending
@@ -2214,6 +2210,10 @@
                         && !win.mCommitDrawPending && !mDisplayFrozen) {
                     applyEnterAnimationLocked(win);
                 }
+                if (displayed && (win.mAttrs.flags
+                        & WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON) != 0) {
+                    win.mTurnOnScreen = true;
+                }
                 if ((attrChanges&WindowManager.LayoutParams.FORMAT_CHANGED) != 0) {
                     // To change the format, we need to re-build the surface.
                     win.destroySurfaceLocked();
@@ -6485,6 +6485,7 @@
         int mLastLayer;
         boolean mHaveFrame;
         boolean mObscured;
+        boolean mTurnOnScreen;
 
         WindowState mNextOutsideTouch;
 
@@ -7055,7 +7056,7 @@
                         + " attHidden=" + mAttachedHidden
                         + " tok.hiddenRequested="
                         + (mAppToken != null ? mAppToken.hiddenRequested : false)
-                        + " tok.idden="
+                        + " tok.hidden="
                         + (mAppToken != null ? mAppToken.hidden : false)
                         + " animating=" + mAnimating
                         + " tok animating="
@@ -7084,10 +7085,20 @@
                 if (mAttrs.type != TYPE_APPLICATION_STARTING
                         && mAppToken != null) {
                     mAppToken.firstWindowDrawn = true;
-                    if (mAnimation == null && mAppToken.startingData != null) {
+                    
+                    if (mAppToken.startingData != null) {
                         if (DEBUG_STARTING_WINDOW) Log.v(TAG, "Finish starting "
                                 + mToken
                                 + ": first real window is shown, no animation");
+                        // If this initial window is animating, stop it -- we
+                        // will do an animation to reveal it from behind the
+                        // starting window, so there is no need for it to also
+                        // be doing its own stuff.
+                        if (mAnimation != null) {
+                            mAnimation = null;
+                            // Make sure we clean up the animation.
+                            mAnimating = true;
+                        }
                         mFinishedStarting.add(mAppToken);
                         mH.sendEmptyMessage(H.FINISHED_STARTING);
                     }
@@ -7716,10 +7727,11 @@
                         pw.print(" mDestroying="); pw.print(mDestroying);
                         pw.print(" mRemoved="); pw.println(mRemoved);
             }
-            if (mOrientationChanging || mAppFreezing) {
+            if (mOrientationChanging || mAppFreezing || mTurnOnScreen) {
                 pw.print(prefix); pw.print("mOrientationChanging=");
                         pw.print(mOrientationChanging);
-                        pw.print(" mAppFreezing="); pw.println(mAppFreezing);
+                        pw.print(" mAppFreezing="); pw.print(mAppFreezing);
+                        pw.print(" mTurnOnScreen="); pw.println(mTurnOnScreen);
             }
             if (mHScale != 1 || mVScale != 1) {
                 pw.print(prefix); pw.print("mHScale="); pw.print(mHScale);
@@ -9788,6 +9800,12 @@
             Message m = mH.obtainMessage(H.HOLD_SCREEN_CHANGED, holdScreen);
             mH.sendMessage(m);
         }
+        
+        if (mTurnOnScreen) {
+            mPowerManager.userActivity(SystemClock.uptimeMillis(), false,
+                    LocalPowerManager.BUTTON_EVENT, true);
+            mTurnOnScreen = false;
+        }
     }
 
     void requestAnimationLocked(long delay) {
@@ -9809,6 +9827,10 @@
         try {
             if (win.mSurface != null) {
                 win.mSurface.show();
+                if (win.mTurnOnScreen) {
+                    win.mTurnOnScreen = false;
+                    mTurnOnScreen = true;
+                }
             }
             return true;
         } catch (RuntimeException e) {
diff --git a/services/java/com/android/server/status/StatusBarService.java b/services/java/com/android/server/status/StatusBarService.java
index d680b8a..83552dd 100644
--- a/services/java/com/android/server/status/StatusBarService.java
+++ b/services/java/com/android/server/status/StatusBarService.java
@@ -1490,10 +1490,13 @@
 
         /// ---------- Expanded View --------------
         pixelFormat = PixelFormat.TRANSLUCENT;
-        if (false) {
-            bg = mExpandedView.getBackground();
-            if (bg != null) {
-                pixelFormat = bg.getOpacity();
+        bg = mExpandedView.getBackground();
+        if (bg != null) {
+            pixelFormat = bg.getOpacity();
+            if (pixelFormat != PixelFormat.TRANSLUCENT) {
+                // we want good-looking gradients, so we force a 8-bits per
+                // pixel format.
+                pixelFormat = PixelFormat.RGBX_8888;
             }
         }
 
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 4368464..2672c6d 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -129,6 +129,8 @@
             return uri.getSchemeSpecificPart();
         }
 
+        // TODO: We don't check for SecurityException here (requires
+        // READ_PHONE_STATE permission).
         if (scheme.equals("voicemail")) {
             return TelephonyManager.getDefault().getVoiceMailNumber();
         }
@@ -1179,6 +1181,35 @@
     }
 
     /**
+     * isVoiceMailNumber: checks a given number against the voicemail
+     *   number provided by the RIL and SIM card. The caller must have
+     *   the READ_PHONE_STATE credential.
+     *
+     * @param number the number to look up.
+     * @return true if the number is in the list of voicemail. False
+     * otherwise, including if the caller does not have the permission
+     * to read the VM number.
+     * @hide TODO: pending API Council approval
+     */
+    public static boolean isVoiceMailNumber(String number) {
+        String vmNumber;
+
+        try {
+            vmNumber = TelephonyManager.getDefault().getVoiceMailNumber();
+        } catch (SecurityException ex) {
+            return false;
+        }
+
+        // Strip the separators from the number before comparing it
+        // to the list.
+        number = extractNetworkPortion(number);
+
+        // compare tolerates null so we need to make sure that we
+        // don't return true when both are null.
+        return !TextUtils.isEmpty(number) && compare(number, vmNumber);
+    }
+
+    /**
      * Translates any alphabetic letters (i.e. [A-Za-z]) in the
      * specified phone number into the equivalent numeric digits,
      * according to the phone keypad letter mapping described in
diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java
index e1bd1db..01b1746 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfo.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfo.java
@@ -100,10 +100,13 @@
     public Drawable cachedPhoto;
     public boolean isCachedPhotoCurrent;
 
-    // Don't keep checking VM if it's going to throw an exception for this proc.
-    private static boolean sSkipVmCheck = false;
+    private boolean mIsEmergency;
+    private boolean mIsVoiceMail;
 
     public CallerInfo() {
+        // TODO: Move all the basic initialization here?
+        mIsEmergency = false;
+        mIsVoiceMail = false;
     }
 
     /**
@@ -216,38 +219,15 @@
     public static CallerInfo getCallerInfo(Context context, String number) {
         if (TextUtils.isEmpty(number)) {
             return null;
-        } else {
-            // Change the callerInfo number ONLY if it is an emergency number
-            // or if it is the voicemail number.  If it is either, take a
-            // shortcut and skip the query.
-            if (PhoneNumberUtils.isEmergencyNumber(number)) {
-                CallerInfo ci = new CallerInfo();
+        }
 
-                // Note we're setting the phone number here (refer to javadoc
-                // comments at the top of CallerInfo class).
-                ci.phoneNumber = context.getString(
-                        com.android.internal.R.string.emergency_call_dialog_number_for_display);
-                return ci;
-            } else {
-                try {
-                    if (!sSkipVmCheck && PhoneNumberUtils.compare(number,
-                                TelephonyManager.getDefault().getVoiceMailNumber())) {
-                        CallerInfo ci = new CallerInfo();
-
-                        // Note we're setting the phone number here (refer to javadoc
-                        // comments at the top of CallerInfo class).
-                        ci.phoneNumber = TelephonyManager.getDefault().getVoiceMailAlphaTag();
-                        // TODO: FIND ANOTHER ICON
-                        //info.photoResource = android.R.drawable.badge_voicemail;
-                        return ci;
-                    }
-                } catch (SecurityException ex) {
-                    // Don't crash if this process doesn't have permission to
-                    // retrieve VM number.  It's still allowed to look up caller info.
-                    // But don't try it again.
-                    sSkipVmCheck = true;
-                }
-            }
+        // Change the callerInfo number ONLY if it is an emergency number
+        // or if it is the voicemail number.  If it is either, take a
+        // shortcut and skip the query.
+        if (PhoneNumberUtils.isEmergencyNumber(number)) {
+            return new CallerInfo().markAsEmergency(context);
+        } else if (PhoneNumberUtils.isVoiceMailNumber(number)) {
+            return new CallerInfo().markAsVoiceMail();
         }
 
         Uri contactUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
@@ -296,6 +276,73 @@
         return callerID;
     }
 
+    // Accessors
+
+    /**
+     * @return true if the caller info is an emergency number.
+     */
+    public boolean isEmergencyNumber() {
+        return mIsEmergency;
+    }
+
+    /**
+     * @return true if the caller info is a voicemail number.
+     */
+    public boolean isVoiceMailNumber() {
+        return mIsVoiceMail;
+    }
+
+    /**
+     * Mark this CallerInfo as an emergency call.
+     * @param context To lookup the localized 'Emergency Number' string.
+     * @return this instance.
+     */
+    // TODO: Note we're setting the phone number here (refer to
+    // javadoc comments at the top of CallerInfo class) to a localized
+    // string 'Emergency Number'. This is pretty bad because we are
+    // making UI work here instead of just packaging the data. We
+    // should set the phone number to the dialed number and name to
+    // 'Emergency Number' and let the UI make the decision about what
+    // should be displayed.
+    /* package */ CallerInfo markAsEmergency(Context context) {
+        phoneNumber = context.getString(
+            com.android.internal.R.string.emergency_call_dialog_number_for_display);
+        photoResource = com.android.internal.R.drawable.picture_emergency;
+        mIsEmergency = true;
+        return this;
+    }
+
+
+    /**
+     * Mark this CallerInfo as a voicemail call. The voicemail label
+     * is obtained from the telephony manager. Caller must hold the
+     * READ_PHONE_STATE permission otherwise the phoneNumber will be
+     * set to null.
+     * @return this instance.
+     */
+    // TODO: As in the emergency number handling, we end up writing a
+    // string in the phone number field.
+    /* package */ CallerInfo markAsVoiceMail() {
+        mIsVoiceMail = true;
+
+        try {
+            String voiceMailLabel = TelephonyManager.getDefault().getVoiceMailAlphaTag();
+
+            phoneNumber = voiceMailLabel;
+        } catch (SecurityException se) {
+            // Should never happen: if this process does not have
+            // permission to retrieve VM tag, it should not have
+            // permission to retrieve VM number and would not call
+            // this method.
+            // Leave phoneNumber untouched.
+            Log.e(TAG, "Cannot access VoiceMail.", se);
+        }
+        // TODO: There is no voicemail picture?
+        // FIXME: FIND ANOTHER ICON
+        // photoResource = android.R.drawable.badge_voicemail;
+        return this;
+    }
+
     private static String normalize(String s) {
         if (s == null || s.length() > 0) {
             return s;
@@ -303,4 +350,31 @@
             return null;
         }
     }
+
+    /**
+     * @return a string debug representation of this instance.
+     */
+    public String toString() {
+        return new StringBuilder(384)
+                .append("\nname: " + name)
+                .append("\nphoneNumber: " + phoneNumber)
+                .append("\ncnapName: " + cnapName)
+                .append("\nnumberPresentation: " + numberPresentation)
+                .append("\nnamePresentation: " + namePresentation)
+                .append("\ncontactExits: " + contactExists)
+                .append("\nphoneLabel: " + phoneLabel)
+                .append("\nnumberType: " + numberType)
+                .append("\nnumberLabel: " + numberLabel)
+                .append("\nphotoResource: " + photoResource)
+                .append("\nperson_id: " + person_id)
+                .append("\nneedUpdate: " + needUpdate)
+                .append("\ncontactRefUri: " + contactRefUri)
+                .append("\ncontactRingtoneUri: " + contactRefUri)
+                .append("\nshouldSendToVoicemail: " + shouldSendToVoicemail)
+                .append("\ncachedPhoto: " + cachedPhoto)
+                .append("\nisCachedPhotoCurrent: " + isCachedPhotoCurrent)
+                .append("\nemergency: " + mIsEmergency)
+                .append("\nvoicemail " + mIsVoiceMail)
+                .toString();
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
index 3d4f78c..802e79b 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
@@ -37,7 +37,7 @@
 public class CallerInfoAsyncQuery {
 
     private static final boolean DBG = false;
-    private static final String LOG_TAG = "PHONE";
+    private static final String LOG_TAG = "CallerInfoAsyncQuery";
 
     private static final int EVENT_NEW_QUERY = 1;
     private static final int EVENT_ADD_LISTENER = 2;
@@ -47,9 +47,6 @@
 
     private CallerInfoAsyncQueryHandler mHandler;
 
-    // Don't keep checking VM if it's going to throw an exception for this proc.
-    private static boolean sSkipVmCheck = false;
-
     /**
      * Interface for a CallerInfoAsyncQueryHandler result return.
      */
@@ -223,26 +220,11 @@
                 // voicemail number, and adjust other data (including photoResource)
                 // accordingly.
                 if (cw.event == EVENT_EMERGENCY_NUMBER) {
-                    mCallerInfo = new CallerInfo();
                     // Note we're setting the phone number here (refer to javadoc
                     // comments at the top of CallerInfo class).
-                    mCallerInfo.phoneNumber = mQueryContext.getString(com.android.internal
-                            .R.string.emergency_call_dialog_number_for_display);
-                    mCallerInfo.photoResource = com.android.internal.R.drawable.picture_emergency;
-
+                    mCallerInfo = new CallerInfo().markAsEmergency(mQueryContext);
                 } else if (cw.event == EVENT_VOICEMAIL_NUMBER) {
-                    mCallerInfo = new CallerInfo();
-                    try {
-                        // Note we're setting the phone number here (refer to javadoc
-                        // comments at the top of CallerInfo class).
-                        mCallerInfo.phoneNumber =
-                                TelephonyManager.getDefault().getVoiceMailAlphaTag();
-                    } catch (SecurityException ex) {
-                        // Should never happen: if this process does not have
-                        // permission to retrieve VM tag, it should not have
-                        // permission to retrieve VM number and would not generate
-                        // an EVENT_VOICEMAIL_NUMBER.  But if it happens, don't crash.
-                    }
+                    mCallerInfo = new CallerInfo().markAsVoiceMail();
                 } else {
                     mCallerInfo = CallerInfo.getCallerInfo(mQueryContext, mQueryUri, cursor);
                     // Use the number entered by the user for display.
@@ -262,7 +244,7 @@
             //notify the listener that the query is complete.
             if (cw.listener != null) {
                 if (DBG) log("notifying listener: " + cw.listener.getClass().toString() +
-                        " for token: " + token);
+                             " for token: " + token + mCallerInfo);
                 cw.listener.onQueryComplete(token, cw.cookie, mCallerInfo);
             }
         }
@@ -319,23 +301,10 @@
         // check to see if these are recognized numbers, and use shortcuts if we can.
         if (PhoneNumberUtils.isEmergencyNumber(number)) {
             cw.event = EVENT_EMERGENCY_NUMBER;
+        } else if (PhoneNumberUtils.isVoiceMailNumber(number)) {
+            cw.event = EVENT_VOICEMAIL_NUMBER;
         } else {
-            String vmNumber = null;
-            if (!sSkipVmCheck){
-                try {
-                    vmNumber = TelephonyManager.getDefault().getVoiceMailNumber();
-                } catch (SecurityException ex) {
-                    // Don't crash if this process doesn't have permission to
-                    // retrieve VM number.  It's still allowed to look up caller info.
-                    // But don't try it again.
-                    sSkipVmCheck = true;
-                }
-            }
-            if (PhoneNumberUtils.compare(number, vmNumber)) {
-                cw.event = EVENT_VOICEMAIL_NUMBER;
-            } else {
-                cw.event = EVENT_NEW_QUERY;
-            }
+            cw.event = EVENT_NEW_QUERY;
         }
 
         c.mHandler.startQuery (token, cw, contactRef, null, null, null, null);
@@ -390,4 +359,3 @@
         Log.d(LOG_TAG, msg);
     }
 }
-
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
index 806c31d..5bf1a0f 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
@@ -436,7 +436,9 @@
             voiceCallStartedRegistrants.notifyRegistrants (
                     new AsyncResult(null, null, null));
         }
-
+        if (Phone.DEBUG_PHONE) {
+            log("update phone state, old= , new= , " + oldState + state);
+        }
         if (state != oldState) {
             phone.notifyPhoneStateChanged();
         }
@@ -519,27 +521,12 @@
                         return;
                     }
                 } else {
-                    connections[i] = new CdmaConnection(phone.getContext(), dc, this, i);
-
-                    // it's a ringing call
-                    if (connections[i].getCall() == ringingCall) {
-                        newRinging = connections[i];
-                    } else {
-                        // Something strange happened: a call appeared
-                        // which is neither a ringing call or one we created.
-                        // Either we've crashed and re-attached to an existing
-                        // call, or something else (eg, SIM) initiated the call.
-
-                        Log.i(LOG_TAG,"Phantom call appeared " + dc);
-
-                        // If it's a connected call, set the connect time so that
-                        // it's non-zero.  It may not be accurate, but at least
-                        // it won't appear as a Missed Call.
-                        if (dc.state != DriverCall.State.ALERTING
-                                && dc.state != DriverCall.State.DIALING) {
-                            connections[i].connectTime = System.currentTimeMillis();
-                        }
-
+                    if (Phone.DEBUG_PHONE) {
+                        log("pending Mo= , dc= " + pendingMO + dc);
+                    }
+                    // find if the MT call is a new ring or unknown connection
+                    newRinging = checkMtFindNewRinging(dc,i);
+                    if (newRinging == null) {
                         unknownConnectionAppeared = true;
                     }
                 }
@@ -571,9 +558,28 @@
                 // list but kept in the Call list
                 connections[i] = null;
             } else if (conn != null && dc != null) { /* implicit conn.compareTo(dc) */
-                boolean changed;
-                changed = conn.update(dc);
-                hasNonHangupStateChanged = hasNonHangupStateChanged || changed;
+                // Call collision case
+                if (conn.isIncoming != dc.isMT) {
+                    if (dc.isMT == true){
+                        // Mt call takes precedence than Mo,drops Mo
+                        droppedDuringPoll.add(conn);
+                        // find if the MT call is a new ring or unknown connection
+                        newRinging = checkMtFindNewRinging(dc,i);
+                        if (newRinging == null) {
+                            unknownConnectionAppeared = true;
+                        }
+                    } else {
+                        // Call info stored in conn is not consistent with the call info from dc.
+                        // We should follow the rule of MT calls taking precedence over MO calls
+                        // when there is conflict, so here we drop the call info from dc and
+                        // continue to use the call info from conn, and only take a log.
+                        Log.e(LOG_TAG,"Error in RIL, Phantom call appeared " + dc);
+                    }
+                } else {
+                    boolean changed;
+                    changed = conn.update(dc);
+                    hasNonHangupStateChanged = hasNonHangupStateChanged || changed;
+                }
             }
 
             if (REPEAT_POLLING) {
@@ -1028,6 +1034,34 @@
             mIsInEmergencyCall = true;
         }
     }
+    /**
+     * Check the MT call to see if it's a new ring or
+     * a unknown connection.
+     */
+    private Connection checkMtFindNewRinging(DriverCall dc, int i) {
+
+        Connection newRinging = null;
+
+        connections[i] = new CdmaConnection(phone.getContext(), dc, this, i);
+        // it's a ringing call
+        if (connections[i].getCall() == ringingCall) {
+            newRinging = connections[i];
+            if (Phone.DEBUG_PHONE) log("Notify new ring " + dc);
+        } else {
+            // Something strange happened: a call which is neither
+            // a ringing call nor the one we created. It could be the
+            // call collision result from RIL
+            Log.e(LOG_TAG,"Phantom call appeared " + dc);
+            // If it's a connected call, set the connect time so that
+            // it's non-zero.  It may not be accurate, but at least
+            // it won't appear as a Missed Call.
+            if (dc.state != DriverCall.State.ALERTING
+                && dc.state != DriverCall.State.DIALING) {
+                connections[i].connectTime = System.currentTimeMillis();
+            }
+        }
+        return newRinging;
+    }
 
     /**
      * Check if current call is in emergency call
diff --git a/telephony/tests/TelephonyTest/Android.mk b/telephony/tests/TelephonyTest/Android.mk
new file mode 100644
index 0000000..1ef8448
--- /dev/null
+++ b/telephony/tests/TelephonyTest/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_PACKAGE_NAME := telephonytest
+
+include $(BUILD_PACKAGE)
diff --git a/telephony/tests/TelephonyTest/AndroidManifest.xml b/telephony/tests/TelephonyTest/AndroidManifest.xml
new file mode 100644
index 0000000..b2a481b
--- /dev/null
+++ b/telephony/tests/TelephonyTest/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<?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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.telephonytest">
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+        <activity android:label="TelephonyTest"
+                android:name="TelephonyTest">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
+    </application>
+    <instrumentation android:name=".TelephonyUnitTestRunner"
+        android:targetPackage="com.android.telephonytest"
+        android:label="Telephony unit tests InstrumentationRunner">
+    </instrumentation>
+    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+</manifest>
diff --git a/telephony/tests/TelephonyTest/src/com/android/telephonytest/TelephonyUnitTestRunner.java b/telephony/tests/TelephonyTest/src/com/android/telephonytest/TelephonyUnitTestRunner.java
new file mode 100644
index 0000000..9e1af31
--- /dev/null
+++ b/telephony/tests/TelephonyTest/src/com/android/telephonytest/TelephonyUnitTestRunner.java
@@ -0,0 +1,48 @@
+/*
+ * 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.telephonytest;
+
+import junit.framework.TestSuite;
+
+import android.test.InstrumentationTestRunner;
+import android.test.InstrumentationTestSuite;
+
+/**
+ * Instrumentation Test Runner for all Telephony unit tests.
+ *
+ * Running all tests:
+ *
+ *   runtest telephony-unit
+ * or
+ *   adb shell am instrument -w com.android.telephonytest/.TelephonyUnitTestRunner
+ */
+
+public class TelephonyUnitTestRunner extends InstrumentationTestRunner {
+
+    @Override
+    public TestSuite getAllTests() {
+        TestSuite suite = new InstrumentationTestSuite(this);
+        suite.addTestSuite(com.android.telephonytest.unit.CallerInfoUnitTest.class);
+        suite.addTestSuite(com.android.telephonytest.unit.PhoneNumberUtilsUnitTest.class);
+        return suite;
+    }
+
+    @Override
+    public ClassLoader getLoader() {
+        return TelephonyUnitTestRunner.class.getClassLoader();
+    }
+}
diff --git a/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/CallerInfoUnitTest.java b/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/CallerInfoUnitTest.java
new file mode 100644
index 0000000..0f24f15
--- /dev/null
+++ b/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/CallerInfoUnitTest.java
@@ -0,0 +1,240 @@
+/*
+ * 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.telephonytest.unit;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.Resources;
+import com.android.internal.telephony.CallerInfo;
+import com.android.internal.telephony.CallerInfoAsyncQuery;
+import android.util.Log;
+import android.os.Looper;
+import android.test.ActivityInstrumentationTestCase;
+import android.util.StringBuilderPrinter;
+
+/*
+ * Check the CallerInfo utility class works as expected.
+ *
+ */
+
+public class CallerInfoUnitTest extends AndroidTestCase {
+    private CallerInfo mInfo;
+    private Context mContext;
+
+    private static final String kEmergencyNumber = "Emergency Number";
+    private static final int kToken = 0xdeadbeef;
+    private static final String TAG = "CallerInfoUnitTest";
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mContext = new MockContext();
+        mInfo = new CallerInfo();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    /**
+     * Checks the caller info instance is flagged as an emergency if
+     * the number is an emergency one. There is no test for the
+     * contact based constructors because emergency number are not in
+     * the contact DB.
+     */
+    @SmallTest
+    public void testEmergencyIsProperlySet() throws Exception {
+        assertFalse(mInfo.isEmergencyNumber());
+
+        mInfo = CallerInfo.getCallerInfo(mContext, "911");
+        assertIsValidEmergencyCallerInfo();
+
+        mInfo = CallerInfo.getCallerInfo(mContext, "tel:911");
+        assertIsValidEmergencyCallerInfo();
+
+
+        // This one hits the content resolver.
+        mInfo = CallerInfo.getCallerInfo(mContext, "18001234567");
+        assertFalse(mInfo.isEmergencyNumber());
+    }
+
+    /**
+     * Same as testEmergencyIsProperlySet but uses the async query api.
+     */
+    @SmallTest
+    public void testEmergencyIsProperlySetUsingAsyncQuery() throws Exception {
+        QueryRunner query;
+
+        query = new QueryRunner("911");
+        query.runAndCheckCompletion();
+        assertIsValidEmergencyCallerInfo();
+
+        query = new QueryRunner("tel:911");
+        query.runAndCheckCompletion();
+        assertIsValidEmergencyCallerInfo();
+
+        query = new QueryRunner("18001234567");
+        query.runAndCheckCompletion();
+        assertFalse(mInfo.isEmergencyNumber());
+    }
+
+    /**
+     * For emergency caller info, phoneNumber should be set to the
+     * string emergency_call_dialog_number_for_display and the
+     * photoResource should be set to the picture_emergency drawable.
+     */
+    @SmallTest
+    public void testEmergencyNumberAndPhotoAreSet() throws Exception {
+        mInfo = CallerInfo.getCallerInfo(mContext, "911");
+
+        assertIsValidEmergencyCallerInfo();
+    }
+
+    // TODO: Add more tests:
+    /**
+     * Check if the voice mail number cannot be retrieved that the
+     * original phone number is preserved.
+     */
+    /**
+     * Check the markAs* methods work.
+     */
+
+
+    //
+    // Helpers
+    //
+
+    // Partial implementation of MockResources.
+    public class MockResources extends android.test.mock.MockResources
+    {
+        @Override
+        public String getString(int resId) throws Resources.NotFoundException {
+            switch (resId) {
+                case com.android.internal.R.string.emergency_call_dialog_number_for_display:
+                    return kEmergencyNumber;
+                default:
+                    throw new UnsupportedOperationException("Missing handling for resid " + resId);
+            }
+        }
+    }
+
+    // Partial implementation of MockContext.
+    public class MockContext extends android.test.mock.MockContext {
+        private ContentResolver mResolver;
+        private Resources mResources;
+
+        public MockContext() {
+            mResolver = new android.test.mock.MockContentResolver();
+            mResources = new MockResources();
+        }
+
+        @Override
+        public ContentResolver getContentResolver() {
+            return mResolver;
+        }
+
+        @Override
+        public Resources getResources() {
+            return mResources;
+        }
+    }
+
+    /**
+     * Class to run a CallerInfoAsyncQuery in a separate thread, with
+     * its own Looper. We cannot use the main Looper because on the
+     * 1st quit the thread is maked dead, ie no further test can use
+     * it. Also there is not way to inject a Looper instance in the
+     * query, so we have to use a thread with its own looper.
+     */
+    private class QueryRunner extends Thread
+            implements CallerInfoAsyncQuery.OnQueryCompleteListener {
+        private Looper mLooper;
+        private String mNumber;
+        private boolean mAsyncCompleted;
+
+        public QueryRunner(String number) {
+            super();
+            mNumber = number;
+        }
+
+        // Run the query in the thread, wait for completion.
+        public void runAndCheckCompletion() throws InterruptedException {
+            start();
+            join();
+            assertTrue(mAsyncCompleted);
+        }
+
+        @Override
+        public void run() {
+            Looper.prepare();
+            mLooper = Looper.myLooper();
+            mAsyncCompleted = false;
+            // The query will pick the thread local looper we've just prepared.
+            CallerInfoAsyncQuery.startQuery(kToken, mContext, mNumber, this, null);
+            mLooper.loop();
+        }
+
+        // Quit the Looper on the 1st callback
+        // (EVENT_EMERGENCY_NUMBER). There is another message
+        // (EVENT_END_OF_QUEUE) that will never be delivered because
+        // the test has exited. The corresponding stack trace
+        // "Handler{xxxxx} sending message to a Handler on a dead
+        // thread" can be ignored.
+        public void onQueryComplete(int token, Object cookie, CallerInfo info) {
+            mAsyncCompleted = true;
+            mInfo = info;
+            mLooper.quit();
+        }
+    }
+
+    /**
+     * Fail if mInfo does not contain a valid emergency CallerInfo instance.
+     */
+    private void assertIsValidEmergencyCallerInfo() throws Exception {
+        assertTrue(mInfo.isEmergencyNumber());
+
+        // For emergency caller info, phoneNumber should be set to the
+        // string emergency_call_dialog_number_for_display and the
+        // photoResource should be set to the picture_emergency drawable.
+        assertEquals(kEmergencyNumber, mInfo.phoneNumber);
+        assertEquals(com.android.internal.R.drawable.picture_emergency, mInfo.photoResource);
+
+        // The name should be null
+        assertNull(mInfo.name);
+        assertEquals(0, mInfo.namePresentation);
+        assertNull(mInfo.cnapName);
+        assertEquals(0, mInfo.numberPresentation);
+
+        assertFalse(mInfo.contactExists);
+        assertEquals(0, mInfo.person_id);
+        assertFalse(mInfo.needUpdate);
+        assertNull(mInfo.contactRefUri);
+
+        assertNull(mInfo.phoneLabel);
+        assertEquals(0, mInfo.numberType);
+        assertNull(mInfo.numberLabel);
+
+        assertNull(mInfo.contactRingtoneUri);
+        assertFalse(mInfo.shouldSendToVoicemail);
+
+        assertNull(mInfo.cachedPhoto);
+        assertFalse(mInfo.isCachedPhotoCurrent);
+    }
+}
diff --git a/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/PhoneNumberUtilsUnitTest.java b/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/PhoneNumberUtilsUnitTest.java
new file mode 100644
index 0000000..2d3c548
--- /dev/null
+++ b/telephony/tests/TelephonyTest/src/com/android/telephonytest/unit/PhoneNumberUtilsUnitTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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.telephonytest.unit;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+import android.telephony.PhoneNumberUtils;
+import android.telephony.TelephonyManager;
+
+/*
+ * Check the PhoneNumberUtils utility class works as expected.
+ *
+ */
+
+public class PhoneNumberUtilsUnitTest extends AndroidTestCase {
+    private String mVoiceMailNumber;
+    private static final String TAG = "PhoneNumberUtilsUnitTest";
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        // FIXME: Why are we getting a security exception here? The
+        // permission is declared in the manifest....
+        // mVoiceMailNumber = TelephonyManager.getDefault().getVoiceMailNumber();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+    }
+
+    /**
+     * Basic checks for the VoiceMail number.
+     * Assumes READ_PHONE_STATE permission and we don't have it.
+     */
+    // TODO: Figure out why we don't have the permission declared in the manifest.
+    @SmallTest
+    public void testWithNumberNotEqualToVoiceMail() throws Exception {
+        assertFalse(PhoneNumberUtils.isVoiceMailNumber("911"));
+        assertFalse(PhoneNumberUtils.isVoiceMailNumber("tel:911"));
+        assertFalse(PhoneNumberUtils.isVoiceMailNumber("+18001234567"));
+        assertFalse(PhoneNumberUtils.isVoiceMailNumber(""));
+        assertFalse(PhoneNumberUtils.isVoiceMailNumber(null));
+        // FIXME:
+        // assertTrue(PhoneNumberUtils.isVoiceMailNumber(mVoiceMailNumber));
+    }
+
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/HandlerThreadTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/HandlerThreadTest.java
index c62f94f..f2025c6 100644
--- a/tests/AndroidTests/src/com/android/unit_tests/os/HandlerThreadTest.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/HandlerThreadTest.java
@@ -36,8 +36,11 @@
     public void testHandlerThread() throws Exception {
         HandlerThread th1 =  new HandlerThread("HandlerThreadTest") {
             protected void onLooperPrepared() {
-                mDidSetup = true;
-                mLooperTid = Process.myTid();
+                synchronized (HandlerThreadTest.this) {
+                    mDidSetup = true;
+                    mLooperTid = Process.myTid();
+                    HandlerThreadTest.this.notify();
+                }
             }
         };
         
@@ -49,14 +52,23 @@
         assertTrue(th1.isAlive());
         assertNotNull(th1.getLooper());
        
-        /* 
-         * Since getLooper() will block until the HandlerThread is setup, we are guaranteed
-         * that mDidSetup and mLooperTid will have been initalized. If they have not, then 
-         * this test should fail
-         */
+        // The call to getLooper() internally blocks until the looper is
+        // available, but will call onLooperPrepared() after that.  So we
+        // need to block here to wait for our onLooperPrepared() to complete
+        // and fill in the values we expect.
+        synchronized (this) {
+            while (!mDidSetup) {
+                try {
+                    wait();
+                } catch (InterruptedException e) {
+                }
+            }
+        }
+        
+        // Make sure that the process was set.
+        assertNotSame(-1, mLooperTid);
         // Make sure that the onLooperPrepared() was called on a different thread.
         assertNotSame(Process.myTid(), mLooperTid);
-        assertTrue(mDidSetup);
         
         final Handler h1 = new Handler(th1.getLooper()) {
             public void handleMessage(Message msg) {
diff --git a/tests/BrowserTestPlugin/jni/event/EventPlugin.cpp b/tests/BrowserTestPlugin/jni/event/EventPlugin.cpp
index 1263204..706c27e 100644
--- a/tests/BrowserTestPlugin/jni/event/EventPlugin.cpp
+++ b/tests/BrowserTestPlugin/jni/event/EventPlugin.cpp
@@ -36,27 +36,18 @@
 extern ANPCanvasInterfaceV0    gCanvasI;
 extern ANPLogInterfaceV0       gLogI;
 extern ANPPaintInterfaceV0     gPaintI;
-extern ANPSurfaceInterfaceV0   gSurfaceI;
 extern ANPTypefaceInterfaceV0  gTypefaceI;
 
 ///////////////////////////////////////////////////////////////////////////////
 
-EventPlugin::EventPlugin(NPP inst) : SubPlugin(inst) {
+EventPlugin::EventPlugin(NPP inst) : SubPlugin(inst) { }
 
-    // initialize the drawing surface
-    m_surfaceReady = false;
-    m_surface = gSurfaceI.newRasterSurface(inst, kRGB_565_ANPBitmapFormat, false);
-    if(!m_surface)
-        gLogI.log(inst, kError_ANPLogType, "----%p Unable to create Raster surface", inst);
-}
+EventPlugin::~EventPlugin() { }
 
-EventPlugin::~EventPlugin() {
-    gSurfaceI.deleteSurface(m_surface);
-}
+void EventPlugin::drawPlugin(const ANPBitmap& bitmap, const ANPRectI& clip) {
 
-void EventPlugin::drawPlugin(int surfaceWidth, int surfaceHeight) {
-
-    gLogI.log(inst(), kDebug_ANPLogType, " ------ %p drawing the plugin (%d,%d)", inst(), surfaceWidth, surfaceHeight);
+    gLogI.log(inst(), kDebug_ANPLogType, " ------ %p drawing the plugin (%d,%d)",
+              inst(), bitmap.width, bitmap.height);
 
     // get the plugin's dimensions according to the DOM
     PluginObject *obj = (PluginObject*) inst()->pdata;
@@ -64,8 +55,8 @@
     const int H = obj->window->height;
 
     // compute the current zoom level
-    const float zoomFactorW = static_cast<float>(surfaceWidth) / W;
-    const float zoomFactorH = static_cast<float>(surfaceHeight) / H;
+    const float zoomFactorW = static_cast<float>(bitmap.width) / W;
+    const float zoomFactorH = static_cast<float>(bitmap.height) / H;
 
     // check to make sure the zoom level is uniform
     if (zoomFactorW + .01 < zoomFactorH && zoomFactorW - .01 > zoomFactorH)
@@ -76,15 +67,16 @@
     const int fontSize = (int)(zoomFactorW * 16);
     const int leftMargin = (int)(zoomFactorW * 10);
 
-    // lock the surface
-    ANPBitmap bitmap;
-    if (!m_surfaceReady || !gSurfaceI.lock(m_surface, &bitmap, NULL)) {
-        gLogI.log(inst(), kError_ANPLogType, " ------ %p unable to lock the plugin", inst());
-        return;
-    }
-
-    // create a canvas
+    // create and clip a canvas
     ANPCanvas* canvas = gCanvasI.newCanvas(&bitmap);
+
+    ANPRectF clipR;
+    clipR.left = clip.left;
+    clipR.top = clip.top;
+    clipR.right = clip.right;
+    clipR.bottom = clip.bottom;
+    gCanvasI.clipRect(canvas, &clipR);
+
     gCanvasI.drawColor(canvas, 0xFFFFFFFF);
 
     // configure the paint
@@ -106,10 +98,9 @@
     const char c[] = "Browser Test Plugin";
     gCanvasI.drawText(canvas, c, sizeof(c)-1, leftMargin, -fm.fTop, paint);
 
-    // clean up variables and unlock the surface
+    // clean up variables
     gPaintI.deletePaint(paint);
     gCanvasI.deleteCanvas(canvas);
-    gSurfaceI.unlock(m_surface);
 }
 
 void EventPlugin::printToDiv(const char* text, int length) {
@@ -149,23 +140,16 @@
 
 int16 EventPlugin::handleEvent(const ANPEvent* evt) {
     switch (evt->eventType) {
-        case kDraw_ANPEventType:
-            gLogI.log(inst(), kError_ANPLogType, " ------ %p the plugin did not request draw events", inst());
-            break;
-        case kSurface_ANPEventType:
-            switch (evt->data.surface.action) {
-                case kCreated_ANPSurfaceAction:
-                    m_surfaceReady = true;
+
+        case kDraw_ANPEventType: {
+            switch (evt->data.draw.model) {
+                case kBitmap_ANPDrawingModel:
+                    drawPlugin(evt->data.draw.data.bitmap, evt->data.draw.clip);
                     return 1;
-                case kDestroyed_ANPSurfaceAction:
-                    m_surfaceReady = false;
-                    return 1;
-                case kChanged_ANPSurfaceAction:
-                    drawPlugin(evt->data.surface.data.changed.width,
-                               evt->data.surface.data.changed.height);
-                    return 1;
+                default:
+                    break;   // unknown drawing model
             }
-            break;
+        }
         case kLifecycle_ANPEventType:
             switch (evt->data.lifecycle.action) {
                 case kOnLoad_ANPLifecycleAction: {
diff --git a/tests/BrowserTestPlugin/jni/event/EventPlugin.h b/tests/BrowserTestPlugin/jni/event/EventPlugin.h
index 73dd6ea..88b7c9d 100644
--- a/tests/BrowserTestPlugin/jni/event/EventPlugin.h
+++ b/tests/BrowserTestPlugin/jni/event/EventPlugin.h
@@ -35,11 +35,8 @@
     virtual int16 handleEvent(const ANPEvent* evt);
 
 private:
-    void drawPlugin(int surfaceWidth, int surfaceHeight);
+    void drawPlugin(const ANPBitmap& bitmap, const ANPRectI& clip);
     void printToDiv(const char* text, int length);
-
-    bool        m_surfaceReady;
-    ANPSurface* m_surface;
 };
 
 #endif // eventPlugin__DEFINED
diff --git a/tests/BrowserTestPlugin/jni/main.cpp b/tests/BrowserTestPlugin/jni/main.cpp
index 056ec4d..e3ad4a7 100644
--- a/tests/BrowserTestPlugin/jni/main.cpp
+++ b/tests/BrowserTestPlugin/jni/main.cpp
@@ -65,7 +65,6 @@
 ANPLogInterfaceV0           gLogI;
 ANPPaintInterfaceV0         gPaintI;
 ANPPathInterfaceV0          gPathI;
-ANPSurfaceInterfaceV0       gSurfaceI;
 ANPSystemInterfaceV0        gSystemI;
 ANPTypefaceInterfaceV0      gTypefaceI;
 ANPWindowInterfaceV0        gWindowI;
@@ -105,16 +104,10 @@
         uint32_t        size;
         ANPInterface*   i;
     } gPairs[] = {
-        { kAudioTrackInterfaceV0_ANPGetValue,   sizeof(gSoundI),    &gSoundI },
-        { kBitmapInterfaceV0_ANPGetValue,       sizeof(gBitmapI),   &gBitmapI },
         { kCanvasInterfaceV0_ANPGetValue,       sizeof(gCanvasI),   &gCanvasI },
         { kLogInterfaceV0_ANPGetValue,          sizeof(gLogI),      &gLogI },
         { kPaintInterfaceV0_ANPGetValue,        sizeof(gPaintI),    &gPaintI },
-        { kPathInterfaceV0_ANPGetValue,         sizeof(gPathI),     &gPathI },
-        { kSurfaceInterfaceV0_ANPGetValue,      sizeof(gSurfaceI),  &gSurfaceI },
-        { kSystemInterfaceV0_ANPGetValue,       sizeof(gSystemI),   &gSystemI },
         { kTypefaceInterfaceV0_ANPGetValue,     sizeof(gTypefaceI), &gTypefaceI },
-        { kWindowInterfaceV0_ANPGetValue,       sizeof(gWindowI),   &gWindowI },
     };
     for (size_t i = 0; i < ARRAY_COUNT(gPairs); i++) {
         gPairs[i].i->inSize = gPairs[i].size;
@@ -156,7 +149,7 @@
     }
 
     // select the drawing model
-    ANPDrawingModel model = kSurface_ANPDrawingModel;
+    ANPDrawingModel model = kBitmap_ANPDrawingModel;
 
     // notify the plugin API of the drawing model we wish to use. This must be
     // done prior to creating certain subPlugin objects (e.g. surfaceViews)
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
index 8fea967..395e572 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
@@ -96,7 +96,9 @@
         // Android layout tests are stored in "layout_tests". The following two
         // tests expect "LayoutTests" in their output.
         "storage/domstorage/localstorage/iframe-events.html",
-        "storage/domstorage/sessionstorage/iframe-events.html"
+        "storage/domstorage/sessionstorage/iframe-events.html",
+        // below tests (failed or crashes) are filtered out temporarily due to prioritizing
+        "editing/selection/move-left-right.html",
     };
     
     static void fillIgnoreResultSet() {
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java
index cc2f1f5..85e0422 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FsUtils.java
@@ -1,5 +1,23 @@
+/*
+ * 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.dumprendertree;
 
+import com.android.dumprendertree.forwarder.ForwardService;
+
 import android.util.Log;
 
 import java.io.BufferedOutputStream;
@@ -12,6 +30,12 @@
 public class FsUtils {
 
     private static final String LOGTAG = "FsUtils";
+    static final String HTTP_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/";
+    static final String HTTPS_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/ssl/";
+    static final String HTTP_LOCAL_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/local/";
+    static final String HTTP_MEDIA_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/media/";
+    static final String HTTP_WML_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/wml/";
+
     private FsUtils() {
         //no creation of instances
     }
@@ -77,4 +101,24 @@
         return status;
     }
 
+    public static String getTestUrl(String path) {
+        String url = null;
+        if (!path.startsWith(HTTP_TESTS_PREFIX)) {
+            url = "file://" + path;
+        } else {
+            ForwardService.getForwardService().startForwardService();
+            if (path.startsWith(HTTPS_TESTS_PREFIX)) {
+                // still cut the URL after "http/tests/"
+                url = "https://127.0.0.1:8443/" + path.substring(HTTP_TESTS_PREFIX.length());
+            } else if (!path.startsWith(HTTP_LOCAL_TESTS_PREFIX)
+                    && !path.startsWith(HTTP_MEDIA_TESTS_PREFIX)
+                    && !path.startsWith(HTTP_WML_TESTS_PREFIX)) {
+                url = "http://127.0.0.1:8000/" + path.substring(HTTP_TESTS_PREFIX.length());
+            } else {
+                url = "file://" + path;
+            }
+        }
+        return url;
+    }
+
 }
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
index e4c8716..235e10e 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
@@ -19,6 +19,7 @@
 import com.android.dumprendertree.TestShellActivity.DumpDataType;
 import com.android.dumprendertree.forwarder.AdbUtils;
 import com.android.dumprendertree.forwarder.ForwardServer;
+import com.android.dumprendertree.forwarder.ForwardService;
 
 import android.app.Instrumentation;
 import android.content.Intent;
@@ -143,17 +144,6 @@
     static final String LAYOUT_RESULTS_CRASHED_RESULT_FILE = "results/layout_tests_crashed.txt";
     static final String LAYOUT_TESTS_RUNNER = "run_layout_tests.py";
 
-    static final String HTTP_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/";
-    static final String HTTPS_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/ssl/";
-    static final String HTTP_LOCAL_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/local/";
-    static final String HTTP_MEDIA_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/media/";
-    static final String HTTP_WML_TESTS_PREFIX = "/sdcard/android/layout_tests/http/tests/wml/";
-
-
-    static final String DEFAULT_TEST_HOST = "android-browser-test.mtv.corp.google.com";
-    static final String FORWARD_HOST_CONF = "/sdcard/drt_forward_host.txt";
-    private ForwardServer fs8000, fs8080, fs8443;
-
     private MyTestRecorder mResultRecorder;
     private Vector<String> mTestList;
     private boolean mRebaselineResults;
@@ -162,45 +152,6 @@
 
     public LayoutTestsAutoTest() {
       super("com.android.dumprendertree", TestShellActivity.class);
-
-      int addr = getForwardHostAddr();
-      if(addr != -1) {
-          fs8000 = new ForwardServer(8000, addr, 8000);
-          fs8080 = new ForwardServer(8080, addr, 8080);
-          fs8443 = new ForwardServer(8443, addr, 8443);
-      }
-    }
-
-    private int getForwardHostAddr() {
-        int addr = -1;
-        String host = null;
-        File forwardHostConf = new File(FORWARD_HOST_CONF);
-        if (forwardHostConf.isFile()) {
-            BufferedReader hostReader = null;
-            try {
-                hostReader = new BufferedReader(new FileReader(forwardHostConf));
-                host = hostReader.readLine();
-                Log.v(LOGTAG, "read forward host from file: " + host);
-            } catch (IOException ioe) {
-                Log.v(LOGTAG, "cannot read forward host from file", ioe);
-            } finally {
-                if (hostReader != null) {
-                    try {
-                        hostReader.close();
-                    } catch (IOException ioe) {
-                        // burn!!!
-                    }
-                }
-            }
-        }
-        if (host == null || host.length() == 0)
-            host = DEFAULT_TEST_HOST;
-        try {
-            addr = AdbUtils.resolve(host);
-        } catch (IOException ioe) {
-            Log.e(LOGTAG, "failed to resolve server address", ioe);
-        }
-        return addr;
     }
 
     // This function writes the result of the layout test to
@@ -366,7 +317,7 @@
         Intent intent = new Intent(Intent.ACTION_VIEW);
         intent.setClass(activity, TestShellActivity.class);
         intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
-        intent.putExtra(TestShellActivity.TEST_URL, getTestUrl(test));
+        intent.putExtra(TestShellActivity.TEST_URL, FsUtils.getTestUrl(test));
         intent.putExtra(TestShellActivity.RESULT_FILE, resultFile);
         intent.putExtra(TestShellActivity.TIMEOUT_IN_MILLIS, timeout);
         activity.startActivity(intent);
@@ -450,49 +401,10 @@
         }
 
         FsUtils.updateTestStatus(TEST_STATUS_FILE, "#DONE");
-        if(fs8000 != null)
-            fs8000.stop();
-        if(fs8080 != null)
-            fs8080.stop();
-        if(fs8443 != null)
-            fs8443.stop();
-
+        ForwardService.getForwardService().stopForwardService();
         activity.finish();
     }
 
-    private void startForwardServerIfNeeded() {
-        try {
-            if(fs8000 != null)
-                fs8000.start();
-            if(fs8080 != null)
-                fs8080.start();
-            if(fs8443 != null)
-                fs8443.start();
-        } catch (IOException ioe) {
-            Log.w(LOGTAG, "failed to start forwarder. http tests will fail.", ioe);
-        }
-    }
-
-    private String getTestUrl(String path) {
-        String url = null;
-        if (!path.startsWith(HTTP_TESTS_PREFIX)) {
-            url = "file://" + path;
-        } else {
-            startForwardServerIfNeeded();
-            if (path.startsWith(HTTPS_TESTS_PREFIX)) {
-                // still cut the URL after "http/tests/"
-                url = "https://127.0.0.1:8443/" + path.substring(HTTP_TESTS_PREFIX.length());
-            } else if (!path.startsWith(HTTP_LOCAL_TESTS_PREFIX)
-                    && !path.startsWith(HTTP_MEDIA_TESTS_PREFIX)
-                    && !path.startsWith(HTTP_WML_TESTS_PREFIX)) {
-                url = "http://127.0.0.1:8000/" + path.substring(HTTP_TESTS_PREFIX.length());
-            } else {
-                url = "file://" + path;
-            }
-        }
-        return url;
-    }
-
     private String getTestPath() {
         LayoutTestsAutoRunner runner = (LayoutTestsAutoRunner) getInstrumentation();
 
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTest.java
index 71d9758..50b7c3f 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTest.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTest.java
@@ -1,3 +1,19 @@
+/*
+ * 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.dumprendertree;
 
 import android.app.Activity;
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTestActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTestActivity.java
index 995c129..fbce78a 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTestActivity.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/ReliabilityTestActivity.java
@@ -1,3 +1,19 @@
+/*
+ * 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.dumprendertree;
 
 import android.app.Activity;
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
index 663df83..3fef61c 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
@@ -16,6 +16,8 @@
 
 package com.android.dumprendertree;
 
+import com.android.dumprendertree.forwarder.ForwardService;
+
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.content.Context;
@@ -184,6 +186,7 @@
         } catch (IOException ioe) {
             Log.w(LOGTAG, "Failed to close test list file.", ioe);
         }
+        ForwardService.getForwardService().stopForwardService();
         finished();
     }
 
@@ -215,10 +218,9 @@
             builder.create().show();
             return;
         }
-        url = "file://" + url;
         Intent intent = new Intent(Intent.ACTION_VIEW);
         intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
-        intent.putExtra(TestShellActivity.TEST_URL, url);
+        intent.putExtra(TestShellActivity.TEST_URL, FsUtils.getTestUrl(url));
         intent.putExtra(TIMEOUT_IN_MILLIS, 10000);
         executeIntent(intent);
     }
@@ -289,13 +291,20 @@
     }
 
     public void finished() {
-        if (mUiAutoTestPath != null) {
-            //don't really finish here
-            moveToNextTest();
-        } else {
-            if (mCallback != null) {
-                mCallback.finished();
+        if (mTestPageLoaded) {
+            if (mUiAutoTestPath != null) {
+                //don't really finish here
+                moveToNextTest();
+            } else {
+                if (mCallback != null) {
+                    mCallback.finished();
+                }
             }
+        } else {
+            // The test is complete but the page has not completed loading. We
+            // can't continue to the next test until both the test is finished
+            // and the page has stopped loading.
+            mReadyForNextTest = true;
         }
     }
 
@@ -443,12 +452,14 @@
         @Override
         public void onPageFinished(WebView view, String url) {
             Log.v(LOGTAG, "onPageFinished, url=" + url);
+            mTestPageLoaded = true;
             super.onPageFinished(view, url);
         }
 
         @Override
         public void onPageStarted(WebView view, String url, Bitmap favicon) {
             Log.v(LOGTAG, "onPageStarted, url=" + url);
+            mTestPageLoaded = false;
             super.onPageStarted(view, url, favicon);
         }
 
@@ -478,6 +489,17 @@
         @Override
         public void onProgressChanged(WebView view, int newProgress) {
             if (newProgress == 100) {
+
+                if (mReadyForNextTest) {
+                    // In this case, the test has completed (i.e. called
+                    // layoutTestController.notifyDone) before the page finished loading. This
+                    // usually happens if the test is not invoked by an onload handler, rather
+                    // directly in a script tag. Now that the page has finished loading, it is
+                    // safe for DRT to go to the next test.
+                    finished();
+                    return;
+                }
+
                 if (!mTimedOut && !mWaitUntilDone && !mRequestedWebKitData) {
                     String url = mWebView.getUrl();
                     Log.v(LOGTAG, "Finished: "+ url);
@@ -653,6 +675,8 @@
         mDumpDatabaseCallbacks = false;
         mCanOpenWindows = false;
         mEventSender.resetMouse();
+        mTestPageLoaded = false;
+        mReadyForNextTest = false;
     }
 
     private void setupWebViewForLayoutTests(WebView webview, CallbackProxy callbackProxy) {
@@ -709,6 +733,9 @@
     private StringBuffer mConsoleMessages;
     private boolean mCanOpenWindows;
 
+    private boolean mTestPageLoaded = false;
+    private boolean mReadyForNextTest = false;
+
     static final String TIMEOUT_STR = "**Test timeout";
 
     static final int MSG_TIMEOUT = 0;
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/AdbUtils.java b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/AdbUtils.java
index 9a3e9c2..c2ecf3a 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/AdbUtils.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/AdbUtils.java
@@ -1,3 +1,19 @@
+/*
+ * 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.dumprendertree.forwarder;
 
 import android.util.Log;
@@ -44,7 +60,6 @@
         DataInputStream dis = new DataInputStream(localSocket.getInputStream());
         OutputStream os = localSocket.getOutputStream();
         int count_read = 0;
-        byte[] buf = new byte[128];
 
         if (localSocket == null || dis == null || os == null)
             return -1;
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardServer.java b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardServer.java
index 74e018e..14f8fbe 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardServer.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardServer.java
@@ -1,3 +1,19 @@
+/*
+ * 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.dumprendertree.forwarder;
 
 import android.util.Log;
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardService.java b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardService.java
new file mode 100644
index 0000000..8b7de6e
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/ForwardService.java
@@ -0,0 +1,115 @@
+/*
+ * 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.dumprendertree.forwarder;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+
+import android.util.Log;
+
+public class ForwardService {
+
+    private ForwardServer fs8000, fs8080, fs8443;
+
+    private static ForwardService inst;
+
+    private static final String LOGTAG = "ForwardService";
+
+    private static final String DEFAULT_TEST_HOST = "android-browser-test.mtv.corp.google.com";
+
+    private static final String FORWARD_HOST_CONF = "/sdcard/drt_forward_host.txt";
+
+    private ForwardService() {
+        int addr = getForwardHostAddr();
+        if (addr != -1) {
+            fs8000 = new ForwardServer(8000, addr, 8000);
+            fs8080 = new ForwardServer(8080, addr, 8080);
+            fs8443 = new ForwardServer(8443, addr, 8443);
+        }
+    }
+
+    public static ForwardService getForwardService() {
+        if (inst == null) {
+            inst = new ForwardService();
+        }
+        return inst;
+    }
+
+    public void startForwardService() {
+        try {
+            if (fs8000 != null)
+                fs8000.start();
+            if (fs8080 != null)
+                fs8080.start();
+            if (fs8443 != null)
+                fs8443.start();
+        } catch (IOException ioe) {
+            Log.w(LOGTAG, "failed to start forwarder. http tests will fail.", ioe);
+            return;
+        }
+    }
+
+    public void stopForwardService() {
+        if (fs8000 != null) {
+            fs8000.stop();
+            fs8000 = null;
+        }
+        if (fs8080 != null) {
+            fs8080.stop();
+            fs8080 = null;
+        }
+        if (fs8443 != null) {
+            fs8443.stop();
+            fs8443 = null;
+        }
+        Log.v(LOGTAG, "forwarders stopped.");
+    }
+
+    private static int getForwardHostAddr() {
+        int addr = -1;
+        String host = null;
+        File forwardHostConf = new File(FORWARD_HOST_CONF);
+        if (forwardHostConf.isFile()) {
+            BufferedReader hostReader = null;
+            try {
+                hostReader = new BufferedReader(new FileReader(forwardHostConf));
+                host = hostReader.readLine();
+                Log.v(LOGTAG, "read forward host from file: " + host);
+            } catch (IOException ioe) {
+                Log.v(LOGTAG, "cannot read forward host from file", ioe);
+            } finally {
+                if (hostReader != null) {
+                    try {
+                        hostReader.close();
+                    } catch (IOException ioe) {
+                        // burn!!!
+                    }
+                }
+            }
+        }
+        if (host == null || host.length() == 0)
+            host = DEFAULT_TEST_HOST;
+        try {
+            addr = AdbUtils.resolve(host);
+        } catch (IOException ioe) {
+            Log.e(LOGTAG, "failed to resolve server address", ioe);
+        }
+        return addr;
+    }
+}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/Forwarder.java b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/Forwarder.java
index e1e04a7..a1f3cdf 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/Forwarder.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/forwarder/Forwarder.java
@@ -1,3 +1,19 @@
+/*
+ * 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.dumprendertree.forwarder;
 
 import android.util.Log;
diff --git a/tests/FrameworkTest/tests/src/android/content/ContentProviderOperationTest.java b/tests/FrameworkTest/tests/src/android/content/ContentProviderOperationTest.java
index dc959f5..aea124b 100644
--- a/tests/FrameworkTest/tests/src/android/content/ContentProviderOperationTest.java
+++ b/tests/FrameworkTest/tests/src/android/content/ContentProviderOperationTest.java
@@ -29,7 +29,6 @@
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import java.util.HashMap;
-import java.util.Hashtable;
 import java.util.Set;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -145,7 +144,7 @@
                 public Cursor query(Uri uri, String[] projection, String selection,
                         String[] selectionArgs, String sortOrder) {
                     // Return cursor over specific set of values
-                    return getCursor(sTestValues1);
+                    return getCursor(sTestValues1, 1);
                 }
             }, null, 0);
         } catch (OperationApplicationException e) {
@@ -153,11 +152,62 @@
         }
     }
 
+    public void testAssertNoValues() {
+        // Build an operation to assert values match provider
+        ContentProviderOperation op1 = ContentProviderOperation.newAssertQuery(sTestUri1)
+                .withExpectedCount(1).build();
+
+        try {
+            // Assert that values match from cursor
+            ContentProviderResult result = op1.apply(new TestContentProvider() {
+                public Cursor query(Uri uri, String[] projection, String selection,
+                        String[] selectionArgs, String sortOrder) {
+                    // Return cursor over specific set of values
+                    return getCursor(sTestValues1, 1);
+                }
+            }, null, 0);
+        } catch (OperationApplicationException e) {
+            fail("newAssert() failed");
+        }
+
+        ContentProviderOperation op2 = ContentProviderOperation.newAssertQuery(sTestUri1)
+                .withExpectedCount(0).build();
+
+        try {
+            // Assert that values match from cursor
+            ContentProviderResult result = op2.apply(new TestContentProvider() {
+                public Cursor query(Uri uri, String[] projection, String selection,
+                        String[] selectionArgs, String sortOrder) {
+                    // Return cursor over specific set of values
+                    return getCursor(sTestValues1, 0);
+                }
+            }, null, 0);
+        } catch (OperationApplicationException e) {
+            fail("newAssert() failed");
+        }
+
+        ContentProviderOperation op3 = ContentProviderOperation.newAssertQuery(sTestUri1)
+                .withExpectedCount(2).build();
+
+        try {
+            // Assert that values match from cursor
+            ContentProviderResult result = op3.apply(new TestContentProvider() {
+                public Cursor query(Uri uri, String[] projection, String selection,
+                        String[] selectionArgs, String sortOrder) {
+                    // Return cursor over specific set of values
+                    return getCursor(sTestValues1, 5);
+                }
+            }, null, 0);
+            fail("we expect the exception to be thrown");
+        } catch (OperationApplicationException e) {
+        }
+    }
+
     /**
      * Build a {@link Cursor} with a single row that contains all values
      * provided through the given {@link ContentValues}.
      */
-    private Cursor getCursor(ContentValues contentValues) {
+    private Cursor getCursor(ContentValues contentValues, int numRows) {
         final Set<Entry<String, Object>> valueSet = contentValues.valueSet();
         final String[] keys = new String[valueSet.size()];
         final Object[] values = new Object[valueSet.size()];
@@ -170,7 +220,9 @@
         }
 
         final MatrixCursor cursor = new MatrixCursor(keys);
-        cursor.addRow(values);
+        for (i = 0; i < numRows; i++) {
+            cursor.addRow(values);
+        }
         return cursor;
     }
 
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index b00d8b0..b6b0e63 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -187,6 +187,13 @@
         return 0;
     }
 
+    // navigation hidden
+    if (getNavHiddenName(part.string(), &config)) {
+        *axis = AXIS_NAVHIDDEN;
+        *value = config.inputFlags;
+        return 0;
+    }
+
     // navigation
     if (getNavigationName(part.string(), &config)) {
         *axis = AXIS_NAVIGATION;
@@ -217,7 +224,7 @@
     Vector<String8> parts;
 
     String8 mcc, mnc, loc, layoutsize, layoutlong, orient, den;
-    String8 touch, key, keysHidden, nav, size, vers;
+    String8 touch, key, keysHidden, nav, navHidden, size, vers;
 
     const char *p = dir;
     const char *q;
@@ -393,6 +400,19 @@
         //printf("not keyboard: %s\n", part.string());
     }
 
+    // navigation hidden
+    if (getNavHiddenName(part.string())) {
+        navHidden = part;
+
+        index++;
+        if (index == N) {
+            goto success;
+        }
+        part = parts[index];
+    } else {
+        //printf("not navHidden: %s\n", part.string());
+    }
+
     if (getNavigationName(part.string())) {
         nav = part;
 
@@ -443,6 +463,7 @@
     this->touchscreen = touch;
     this->keysHidden = keysHidden;
     this->keyboard = key;
+    this->navHidden = navHidden;
     this->navigation = nav;
     this->screenSize = size;
     this->version = vers;
@@ -476,6 +497,8 @@
     s += ",";
     s += keyboard;
     s += ",";
+    s += navHidden;
+    s += ",";
     s += navigation;
     s += ",";
     s += screenSize;
@@ -528,6 +551,10 @@
         s += "-";
         s += keyboard;
     }
+    if (this->navHidden != "") {
+        s += "-";
+        s += navHidden;
+    }
     if (this->navigation != "") {
         s += "-";
         s += navigation;
@@ -852,6 +879,30 @@
     return false;
 }
 
+bool AaptGroupEntry::getNavHiddenName(const char* name,
+                                       ResTable_config* out)
+{
+    uint8_t mask = 0;
+    uint8_t value = 0;
+    if (strcmp(name, kWildcardName) == 0) {
+        mask = out->MASK_NAVHIDDEN;
+        value = out->NAVHIDDEN_ANY;
+    } else if (strcmp(name, "navexposed") == 0) {
+        mask = out->MASK_NAVHIDDEN;
+        value = out->NAVHIDDEN_NO;
+    } else if (strcmp(name, "navhidden") == 0) {
+        mask = out->MASK_NAVHIDDEN;
+        value = out->NAVHIDDEN_YES;
+    }
+
+    if (mask != 0) {
+        if (out) out->inputFlags = (out->inputFlags&~mask) | value;
+        return true;
+    }
+
+    return false;
+}
+
 bool AaptGroupEntry::getNavigationName(const char* name,
                                      ResTable_config* out)
 {
@@ -953,6 +1004,7 @@
     if (v == 0) v = touchscreen.compare(o.touchscreen);
     if (v == 0) v = keysHidden.compare(o.keysHidden);
     if (v == 0) v = keyboard.compare(o.keyboard);
+    if (v == 0) v = navHidden.compare(o.navHidden);
     if (v == 0) v = navigation.compare(o.navigation);
     if (v == 0) v = screenSize.compare(o.screenSize);
     if (v == 0) v = version.compare(o.version);
@@ -973,6 +1025,7 @@
     getTouchscreenName(touchscreen.string(), &params);
     getKeysHiddenName(keysHidden.string(), &params);
     getKeyboardName(keyboard.string(), &params);
+    getNavHiddenName(navHidden.string(), &params);
     getNavigationName(navigation.string(), &params);
     getScreenSizeName(screenSize.string(), &params);
     getVersionName(version.string(), &params);
diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h
index 865efd1..26500a3 100644
--- a/tools/aapt/AaptAssets.h
+++ b/tools/aapt/AaptAssets.h
@@ -37,6 +37,7 @@
     AXIS_TOUCHSCREEN,
     AXIS_KEYSHIDDEN,
     AXIS_KEYBOARD,
+    AXIS_NAVHIDDEN,
     AXIS_NAVIGATION,
     AXIS_SCREENSIZE,
     AXIS_VERSION
@@ -64,6 +65,7 @@
     String8 touchscreen;
     String8 keysHidden;
     String8 keyboard;
+    String8 navHidden;
     String8 navigation;
     String8 screenSize;
     String8 version;
@@ -83,6 +85,7 @@
     static bool getKeysHiddenName(const char* name, ResTable_config* out = NULL);
     static bool getKeyboardName(const char* name, ResTable_config* out = NULL);
     static bool getNavigationName(const char* name, ResTable_config* out = NULL);
+    static bool getNavHiddenName(const char* name, ResTable_config* out = NULL);
     static bool getScreenSizeName(const char* name, ResTable_config* out = NULL);
     static bool getVersionName(const char* name, ResTable_config* out = NULL);
 
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index f85aadd..954930e 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -42,24 +42,51 @@
     public static final String priorityVarName = "priority";
     /** {@hide} */
     public static final String hiddenSSIDVarName = "scan_ssid";
+
     /** {@hide} */
-    public static final String eapVarName = "eap";
+    public class EnterpriseField {
+        private String varName;
+        private String value;
+
+        private EnterpriseField(String varName) {
+            this.varName = varName;
+            this.value = null;
+        }
+
+        public void setValue(String value) {
+            this.value = value;
+        }
+
+        public String varName() {
+            return varName;
+        }
+
+        public String value() {
+            return value;
+        }
+    }
+
     /** {@hide} */
-    public static final String phase2VarName = "phase2";
+    public EnterpriseField eap = new EnterpriseField("eap");
     /** {@hide} */
-    public static final String identityVarName = "identity";
+    public EnterpriseField phase2 = new EnterpriseField("phase2");
     /** {@hide} */
-    public static final String anonymousIdentityVarName = "anonymous_identity";
+    public EnterpriseField identity = new EnterpriseField("anonymous_identity");
     /** {@hide} */
-    public static final String passwordVarName = "password";
+    public EnterpriseField anonymous_identity = new EnterpriseField("anonymous_identity");
     /** {@hide} */
-    public static final String clientCertVarName = "client_cert";
+    public EnterpriseField password = new EnterpriseField("password");
     /** {@hide} */
-    public static final String caCertVarName = "ca_cert";
+    public EnterpriseField client_cert = new EnterpriseField("client_cert");
     /** {@hide} */
-    public static final String privateKeyVarName = "private_key";
+    public EnterpriseField private_key = new EnterpriseField("private_key");
     /** {@hide} */
-    public static final String privateKeyPasswdVarName = "private_key_passwd";
+    public EnterpriseField ca_cert = new EnterpriseField("ca_cert");
+
+    /** {@hide} */
+    public EnterpriseField[] enterpriseFields = {
+            eap, phase2, identity, anonymous_identity, password, client_cert,
+            private_key, ca_cert };
 
     /**
      * Recognized key management schemes.
@@ -267,44 +294,6 @@
      */
     public BitSet allowedGroupCiphers;
 
-    /* The following fields are used for EAP/IEEE8021X authentication */
-
-    /**
-     * The eap mode should be PEAP, TLS or TTLS.
-     * {@hide}
-     */
-    public String eap;
-    /**
-     * The phase2 authenication could be PAP, MSCHAP, MSCHAP2, GTC.
-     * {@hide}
-     */
-    public String phase2;
-    /**
-     * The identity of the user in string,
-     * which is used for the authentication.
-     * {@hide}
-     */
-    public String identity;
-    /** {@hide} */
-    public String anonymousIdentity;
-    /** {@hide} */
-    public String password;
-    /** The path of the client certificate file.
-     * {@hide}
-     */
-    public String clientCert;
-    /** The path of the CA certificate file.
-     * {@hide}
-     */
-    public String caCert;
-    /** The path of the private key file.
-     * {@hide}
-     */
-    public String privateKey;
-    /** The password of the private key file if encrypted.
-     * {@hide}
-     */
-    public String privateKeyPasswd;
 
     public WifiConfiguration() {
         networkId = -1;
@@ -320,15 +309,9 @@
         wepKeys = new String[4];
         for (int i = 0; i < wepKeys.length; i++)
             wepKeys[i] = null;
-        eap = null;
-        phase2 = null;
-        identity = null;
-        anonymousIdentity = null;
-        password = null;
-        clientCert = null;
-        caCert = null;
-        privateKey = null;
-        privateKeyPasswd = null;
+        for (EnterpriseField field : enterpriseFields) {
+            field.setValue(null);
+        }
     }
 
     public String toString() {
@@ -403,41 +386,11 @@
         if (this.preSharedKey != null) {
             sbuf.append('*');
         }
-        sbuf.append('\n').append(" eap: ");
-        if (this.eap != null) {
-            sbuf.append(eap);
-        }
-        sbuf.append('\n').append(" phase2: ");
-        if (this.phase2 != null) {
-            sbuf.append(phase2);
-        }
-        sbuf.append('\n').append(" Identity: ");
-        if (this.identity != null) {
-            sbuf.append(identity);
-        }
-        sbuf.append('\n').append(" AnonymousIdentity: ");
-        if (this.anonymousIdentity != null) {
-            sbuf.append(anonymousIdentity);
-        }
-        sbuf.append('\n').append(" Password: ");
-        if (this.password != null) {
-            sbuf.append(password);
-        }
-        sbuf.append('\n').append(" ClientCert: ");
-        if (this.clientCert != null) {
-            sbuf.append(clientCert);
-        }
-        sbuf.append('\n').append(" CaCert: ");
-        if (this.caCert != null) {
-            sbuf.append(caCert);
-        }
-        sbuf.append('\n').append(" PrivateKey: ");
-        if (this.privateKey != null) {
-            sbuf.append(privateKey);
-        }
-        sbuf.append('\n').append(" PrivateKeyPasswd: ");
-        if (this.privateKeyPasswd != null) {
-            sbuf.append(privateKeyPasswd);
+
+        for (EnterpriseField field : enterpriseFields) {
+            sbuf.append('\n').append(" " + field.varName() + ": ");
+            String value = field.value();
+            if (value != null) sbuf.append(value);
         }
         sbuf.append('\n');
         return sbuf.toString();
@@ -497,15 +450,10 @@
         writeBitSet(dest, allowedAuthAlgorithms);
         writeBitSet(dest, allowedPairwiseCiphers);
         writeBitSet(dest, allowedGroupCiphers);
-        dest.writeString(eap);
-        dest.writeString(phase2);
-        dest.writeString(identity);
-        dest.writeString(anonymousIdentity);
-        dest.writeString(password);
-        dest.writeString(clientCert);
-        dest.writeString(caCert);
-        dest.writeString(privateKey);
-        dest.writeString(privateKeyPasswd);
+
+        for (EnterpriseField field : enterpriseFields) {
+            dest.writeString(field.value());
+        }
     }
 
     /** Implement the Parcelable interface {@hide} */
@@ -528,15 +476,10 @@
                 config.allowedAuthAlgorithms  = readBitSet(in);
                 config.allowedPairwiseCiphers = readBitSet(in);
                 config.allowedGroupCiphers    = readBitSet(in);
-                config.eap = in.readString();
-                config.phase2 = in.readString();
-                config.identity = in.readString();
-                config.anonymousIdentity = in.readString();
-                config.password = in.readString();
-                config.clientCert = in.readString();
-                config.caCert = in.readString();
-                config.privateKey = in.readString();
-                config.privateKeyPasswd = in.readString();
+
+                for (EnterpriseField field : config.enterpriseFields) {
+                    field.setValue(in.readString());
+                }
                 return config;
             }
 
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index 9a11404..e3d8bf4 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -1350,7 +1350,7 @@
      */
     private synchronized void requestPolledInfo(WifiInfo info, boolean polling)
     {
-        int newRssi = WifiNative.getRssiCommand();
+        int newRssi = (polling ? WifiNative.getRssiApproxCommand() : WifiNative.getRssiCommand());
         if (newRssi != -1 && -200 < newRssi && newRssi < 256) { // screen out invalid values
             /* some implementations avoid negative values by adding 256
              * so we need to adjust for that here.