Merge change 24337 into eclair

* changes:
  Fix issue 2107584: media server crash when AudioFlinger fails to allocate memory for track control block.
diff --git a/api/current.xml b/api/current.xml
index c8384e4..f8cf61f 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -1659,6 +1659,17 @@
  visibility="public"
 >
 </field>
+<field name="accountPreferences"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843423"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="accountType"
  type="int"
  transient="false"
@@ -6814,7 +6825,7 @@
  value="16843221"
  static="true"
  final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </field>
@@ -7093,6 +7104,17 @@
  visibility="public"
 >
 </field>
+<field name="smallIcon"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843422"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="smallScreens"
  type="int"
  transient="false"
@@ -14543,6 +14565,10 @@
 </parameter>
 <parameter name="iconId" type="int">
 </parameter>
+<parameter name="smallIconId" type="int">
+</parameter>
+<parameter name="prefId" type="int">
+</parameter>
 </constructor>
 <method name="describeContents"
  return="int"
@@ -14593,6 +14619,16 @@
  visibility="public"
 >
 </field>
+<field name="accountPreferencesId"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="iconId"
  type="int"
  transient="false"
@@ -14623,6 +14659,16 @@
  visibility="public"
 >
 </field>
+<field name="smallIconId"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="type"
  type="java.lang.String"
  transient="false"
@@ -17060,6 +17106,27 @@
 <parameter name="id" type="int">
 </parameter>
 </method>
+<method name="startActivity"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="intent" type="android.app.PendingIntent">
+</parameter>
+<parameter name="fillInIntent" type="android.content.Intent">
+</parameter>
+<parameter name="flagsMask" type="int">
+</parameter>
+<parameter name="flagsValues" type="int">
+</parameter>
+<exception name="PendingIntent.CanceledException" type="android.app.PendingIntent.CanceledException">
+</exception>
+</method>
 <method name="startActivityForResult"
  return="void"
  abstract="false"
@@ -17075,6 +17142,29 @@
 <parameter name="requestCode" type="int">
 </parameter>
 </method>
+<method name="startActivityForResult"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="intent" type="android.app.PendingIntent">
+</parameter>
+<parameter name="requestCode" type="int">
+</parameter>
+<parameter name="fillInIntent" type="android.content.Intent">
+</parameter>
+<parameter name="flagsMask" type="int">
+</parameter>
+<parameter name="flagsValues" type="int">
+</parameter>
+<exception name="PendingIntent.CanceledException" type="android.app.PendingIntent.CanceledException">
+</exception>
+</method>
 <method name="startActivityFromChild"
  return="void"
  abstract="false"
@@ -17092,6 +17182,31 @@
 <parameter name="requestCode" type="int">
 </parameter>
 </method>
+<method name="startActivityFromChild"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="child" type="android.app.Activity">
+</parameter>
+<parameter name="intent" type="android.app.PendingIntent">
+</parameter>
+<parameter name="requestCode" type="int">
+</parameter>
+<parameter name="fillInIntent" type="android.content.Intent">
+</parameter>
+<parameter name="flagsMask" type="int">
+</parameter>
+<parameter name="flagsValues" type="int">
+</parameter>
+<exception name="PendingIntent.CanceledException" type="android.app.PendingIntent.CanceledException">
+</exception>
+</method>
 <method name="startActivityIfNeeded"
  return="boolean"
  abstract="false"
@@ -25457,6 +25572,85 @@
  deprecated="not deprecated"
  visibility="public"
 >
+<method name="cancelDiscovery"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="checkBluetoothAddress"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="address" type="java.lang.String">
+</parameter>
+</method>
+<method name="disable"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="enable"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getAddress"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getBondedDevices"
+ return="java.util.Set&lt;android.bluetooth.BluetoothDevice&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getName"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getRemoteDevice"
  return="android.bluetooth.BluetoothDevice"
  abstract="false"
@@ -25470,6 +25664,50 @@
 <parameter name="address" type="java.lang.String">
 </parameter>
 </method>
+<method name="getScanMode"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getState"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isDiscovering"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isEnabled"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="listenUsingRfcommOn"
  return="android.bluetooth.BluetoothServerSocket"
  abstract="false"
@@ -25485,6 +25723,1134 @@
 <exception name="IOException" type="java.io.IOException">
 </exception>
 </method>
+<method name="setName"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="name" type="java.lang.String">
+</parameter>
+</method>
+<method name="setScanMode"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="mode" type="int">
+</parameter>
+</method>
+<method name="startDiscovery"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="ACTION_DISCOVERY_FINISHED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.bluetooth.adapter.action.DISCOVERY_FINISHED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_DISCOVERY_STARTED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.bluetooth.adapter.action.DISCOVERY_STARTED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_LOCAL_NAME_CHANGED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.bluetooth.adapter.action.LOCAL_NAME_CHANGED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_SCAN_MODE_CHANGED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.bluetooth.adapter.action.SCAN_MODE_CHANGED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_STATE_CHANGED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.bluetooth.adapter.action.STATE_CHANGED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-2147483648"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_LOCAL_NAME"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.bluetooth.adapter.extra.LOCAL_NAME&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_PREVIOUS_SCAN_MODE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.bluetooth.adapter.extra.PREVIOUS_SCAN_MODE&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_PREVIOUS_STATE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.bluetooth.adapter.extra.PREVIOUS_STATE&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_SCAN_MODE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.bluetooth.adapter.extra.SCAN_MODE&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_STATE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.bluetooth.adapter.extra.STATE&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SCAN_MODE_CONNECTABLE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="21"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SCAN_MODE_CONNECTABLE_DISCOVERABLE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="23"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SCAN_MODE_NONE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="20"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="STATE_OFF"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="10"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="STATE_ON"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="12"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="STATE_TURNING_OFF"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="13"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="STATE_TURNING_ON"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="11"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="BluetoothClass"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.os.Parcelable">
+</implements>
+<method name="describeContents"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getDeviceClass"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getMajorDeviceClass"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="hasService"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="service" type="int">
+</parameter>
+</method>
+<method name="writeToParcel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="out" type="android.os.Parcel">
+</parameter>
+<parameter name="flags" type="int">
+</parameter>
+</method>
+</class>
+<class name="BluetoothClass.Device"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="BluetoothClass.Device"
+ type="android.bluetooth.BluetoothClass.Device"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<field name="AUDIO_VIDEO_CAMCORDER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1076"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AUDIO_VIDEO_CAR_AUDIO"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1056"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AUDIO_VIDEO_HANDSFREE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1032"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AUDIO_VIDEO_HEADPHONES"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1048"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AUDIO_VIDEO_HIFI_AUDIO"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1064"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AUDIO_VIDEO_LOUDSPEAKER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1044"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AUDIO_VIDEO_MICROPHONE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1040"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AUDIO_VIDEO_PORTABLE_AUDIO"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1052"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AUDIO_VIDEO_SET_TOP_BOX"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1060"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AUDIO_VIDEO_UNCATEGORIZED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1024"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AUDIO_VIDEO_VCR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1068"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AUDIO_VIDEO_VIDEO_CAMERA"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1072"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AUDIO_VIDEO_VIDEO_CONFERENCING"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1088"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AUDIO_VIDEO_VIDEO_DISPLAY_AND_LOUDSPEAKER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1084"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AUDIO_VIDEO_VIDEO_GAMING_TOY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1096"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AUDIO_VIDEO_VIDEO_MONITOR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1080"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="AUDIO_VIDEO_WEARABLE_HEADSET"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1028"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="COMPUTER_DESKTOP"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="260"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="COMPUTER_HANDHELD_PC_PDA"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="272"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="COMPUTER_LAPTOP"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="268"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="COMPUTER_PALM_SIZE_PC_PDA"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="276"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="COMPUTER_SERVER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="264"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="COMPUTER_UNCATEGORIZED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="256"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="COMPUTER_WEARABLE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="280"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="HEALTH_BLOOD_PRESSURE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2308"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="HEALTH_DATA_DISPLAY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2332"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="HEALTH_GLUCOSE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2320"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="HEALTH_PULSE_OXIMETER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2324"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="HEALTH_PULSE_RATE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2328"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="HEALTH_THERMOMETER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2312"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="HEALTH_UNCATEGORIZED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2304"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="HEALTH_WEIGHING"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2316"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PHONE_CELLULAR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="516"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PHONE_CORDLESS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="520"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PHONE_ISDN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="532"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PHONE_MODEM_OR_GATEWAY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="528"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PHONE_SMART"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="524"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PHONE_UNCATEGORIZED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="512"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TOY_CONTROLLER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2064"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TOY_DOLL_ACTION_FIGURE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2060"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TOY_GAME"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2068"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TOY_ROBOT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2052"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TOY_UNCATEGORIZED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2048"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TOY_VEHICLE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2056"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="WEARABLE_GLASSES"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1812"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="WEARABLE_HELMET"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1808"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="WEARABLE_JACKET"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1804"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="WEARABLE_PAGER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1800"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="WEARABLE_UNCATEGORIZED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1792"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="WEARABLE_WRIST_WATCH"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1796"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="BluetoothClass.Device.Major"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="BluetoothClass.Device.Major"
+ type="android.bluetooth.BluetoothClass.Device.Major"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<field name="AUDIO_VIDEO"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1024"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="COMPUTER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="256"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="HEALTH"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2304"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="IMAGING"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1536"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MISC"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="NETWORKING"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="768"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PERIPHERAL"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1280"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PHONE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="512"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TOY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2048"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="UNCATEGORIZED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="7936"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="WEARABLE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1792"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="BluetoothClass.Service"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="BluetoothClass.Service"
+ type="android.bluetooth.BluetoothClass.Service"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<field name="AUDIO"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2097152"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CAPTURE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="524288"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="INFORMATION"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="8388608"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="LIMITED_DISCOVERABILITY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="8192"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="NETWORKING"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="131072"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="OBJECT_TRANSFER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1048576"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="POSITIONING"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="65536"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="RENDER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="262144"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TELEPHONY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4194304"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 </class>
 <class name="BluetoothDevice"
  extends="java.lang.Object"
@@ -25496,6 +26862,28 @@
 >
 <implements name="android.os.Parcelable">
 </implements>
+<method name="cancelBondProcess"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="createBond"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="createRfcommSocket"
  return="android.bluetooth.BluetoothSocket"
  abstract="false"
@@ -25533,6 +26921,50 @@
  visibility="public"
 >
 </method>
+<method name="getBluetoothClass"
+ return="android.bluetooth.BluetoothClass"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getBondState"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getName"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="removeBond"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="writeToParcel"
  return="void"
  abstract="false"
@@ -25548,6 +26980,193 @@
 <parameter name="flags" type="int">
 </parameter>
 </method>
+<field name="ACTION_ACL_CONNECTED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.bluetooth.device.action.ACL_CONNECTED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_ACL_DISCONNECTED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.bluetooth.device.action.ACL_DISCONNECTED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_ACL_DISCONNECT_REQUESTED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_BOND_STATE_CHANGED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.bluetooth.device.action.BOND_STATE_CHANGED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_CLASS_CHANGED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.bluetooth.device.action.CLASS_CHANGED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_FOUND"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.bluetooth.device.action.FOUND&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ACTION_NAME_CHANGED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.bluetooth.device.action.NAME_CHANGED&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="BOND_BONDED"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="12"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="BOND_BONDING"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="11"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="BOND_NONE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="10"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ERROR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="-2147483648"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_BOND_STATE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.bluetooth.device.extra.BOND_STATE&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_CLASS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.bluetooth.device.extra.CLASS&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_DEVICE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.bluetooth.device.extra.DEVICE&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_NAME"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.bluetooth.device.extra.NAME&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_PREVIOUS_BOND_STATE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.bluetooth.device.extra.PREVIOUS_BOND_STATE&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_RSSI"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.bluetooth.device.extra.RSSI&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 </class>
 <class name="BluetoothServerSocket"
  extends="java.lang.Object"
diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp
index e66b00f8..f425f6b 100644
--- a/camera/libcameraservice/CameraService.cpp
+++ b/camera/libcameraservice/CameraService.cpp
@@ -552,17 +552,6 @@
     CameraParameters params(mHardware->getParameters());
     params.getPreviewSize(&w, &h);
 
-    const char *format = params.getPreviewFormat();
-    int fmt;
-    if (!strcmp(format, "yuv422i-yuyv"))
-        fmt = OVERLAY_FORMAT_YCbYCr_422_I;
-    else if (!strcmp(format, "rgb565"))
-        fmt = OVERLAY_FORMAT_RGB_565;
-    else {
-        LOGE("Invalid preview format for overlays");
-        return -EINVAL;
-    }
-
     if ( w != mOverlayW || h != mOverlayH )
     {
         // Force the destruction of any previous overlay
@@ -574,7 +563,7 @@
     status_t ret = NO_ERROR;
     if (mSurface != 0) {
         if (mOverlayRef.get() == NULL) {
-            mOverlayRef = mSurface->createOverlay(w, h, fmt);
+            mOverlayRef = mSurface->createOverlay(w, h, OVERLAY_FORMAT_DEFAULT);
             if ( mOverlayRef.get() == NULL )
             {
                 LOGE("Overlay Creation Failed!");
@@ -1112,8 +1101,7 @@
     }
 
     CameraParameters p(params);
-    mHardware->setParameters(p);
-    return NO_ERROR;
+    return mHardware->setParameters(p);
 }
 
 // get preview/capture parameters - key/value pairs
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index c211b47..c60045c 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -216,11 +216,9 @@
     } else
         vibrate_fd = -1;
 
-#if 0
     /* switch to non-root user and group */
     setgroups(sizeof(groups)/sizeof(groups[0]), groups);
     setuid(AID_SHELL);
-#endif
 
     /* make it safe to use both printf and STDOUT_FILENO */ 
     setvbuf(stdout, 0, _IONBF, 0);
diff --git a/cmds/keystore/Android.mk b/cmds/keystore/Android.mk
index 3daf44e..8804636 100644
--- a/cmds/keystore/Android.mk
+++ b/cmds/keystore/Android.mk
@@ -4,7 +4,7 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
-    netkeystore.c keymgmt.c
+    netkeystore.c netkeystore_main.c keymgmt.c
 
 LOCAL_C_INCLUDES := \
     $(call include-path-for, system-core)/cutils \
diff --git a/cmds/keystore/keymgmt.c b/cmds/keystore/keymgmt.c
index 69e0380..b5ace86 100644
--- a/cmds/keystore/keymgmt.c
+++ b/cmds/keystore/keymgmt.c
@@ -385,7 +385,10 @@
         return -1;
     }
     while ((de = readdir(d))) {
-        if (unlink(de->d_name) != 0) ret = -1;
+        char *dirname = de->d_name;
+        if (strcmp(".", dirname) == 0) continue;
+        if (strcmp("..", dirname) == 0) continue;
+        if (unlink(dirname) != 0) ret = -1;
     }
     closedir(d);
     state = UNINITIALIZED;
diff --git a/cmds/keystore/netkeystore.c b/cmds/keystore/netkeystore.c
index 82a92c3..83c7871 100644
--- a/cmds/keystore/netkeystore.c
+++ b/cmds/keystore/netkeystore.c
@@ -14,8 +14,6 @@
 ** limitations under the License.
 */
 
-#define LOG_TAG "keystore"
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/stat.h>
@@ -247,7 +245,7 @@
     reply->retcode = reset_keystore();
 }
 
-static void execute(LPC_MARSHAL *cmd, LPC_MARSHAL *reply)
+void execute(LPC_MARSHAL *cmd, LPC_MARSHAL *reply)
 {
     uint32_t cmd_max = sizeof(cmds)/sizeof(struct cmdinfo);
 
@@ -309,7 +307,7 @@
     return 0;
 }
 
-static int parse_cmd(int argc, const char **argv, LPC_MARSHAL *cmd)
+int parse_cmd(int argc, const char **argv, LPC_MARSHAL *cmd)
 {
     uint32_t i, len = 0;
     uint32_t cmd_max = sizeof(cmds)/sizeof(cmds[0]);
@@ -335,30 +333,30 @@
     }
 }
 
-static int shell_command(const int argc, const char **argv)
+int shell_command(const int argc, const char **argv)
 {
     int fd, i;
     LPC_MARSHAL  cmd;
 
-    if (parse_cmd(argc, argv , &cmd)) {
+    if (parse_cmd(argc, argv, &cmd)) {
         fprintf(stderr, "Incorrect command or command line is too long.\n");
-        exit(1);
+        return -1;
     }
     fd = socket_local_client(SOCKET_PATH,
                              ANDROID_SOCKET_NAMESPACE_RESERVED,
                              SOCK_STREAM);
     if (fd == -1) {
         fprintf(stderr, "Keystore service is not up and running.\n");
-        exit(1);
+        return -1;
     }
 
     if (write_marshal(fd, &cmd)) {
         fprintf(stderr, "Incorrect command or command line is too long.\n");
-        exit(1);
+        return -1;
     }
     if (read_marshal(fd, &cmd)) {
         fprintf(stderr, "Failed to read the result.\n");
-        exit(1);
+        return -1;
     }
     cmd.data[cmd.len] = 0;
     fprintf(stdout, "%s\n", (cmd.retcode == 0) ? "Succeeded!" : "Failed!");
@@ -367,30 +365,26 @@
     return 0;
 }
 
-int main(const int argc, const char *argv[])
+int server_main(const int argc, const char *argv[])
 {
     struct sockaddr addr;
     socklen_t alen;
     int lsocket, s;
     LPC_MARSHAL  cmd, reply;
 
-    if (argc > 1) {
-        return shell_command(argc - 1, argv + 1);
-    }
-
     if (init_keystore(KEYSTORE_DIR)) {
         LOGE("Can not initialize the keystore, the directory exist?\n");
-        exit(1);
+        return -1;
     }
 
     lsocket = android_get_control_socket(SOCKET_PATH);
     if (lsocket < 0) {
         LOGE("Failed to get socket from environment: %s\n", strerror(errno));
-        exit(1);
+        return -1;
     }
     if (listen(lsocket, 5)) {
         LOGE("Listen on socket failed: %s\n", strerror(errno));
-        exit(1);
+        return -1;
     }
     fcntl(lsocket, F_SETFD, FD_CLOEXEC);
     memset(&reply, 0, sizeof(LPC_MARSHAL));
diff --git a/cmds/keystore/netkeystore.h b/cmds/keystore/netkeystore.h
index d80ddae..e2ffd8b 100644
--- a/cmds/keystore/netkeystore.h
+++ b/cmds/keystore/netkeystore.h
@@ -25,6 +25,10 @@
 
 #include "common.h"
 
+// for testing
+int parse_cmd(int argc, const char **argv, LPC_MARSHAL *cmd);
+void execute(LPC_MARSHAL *cmd, LPC_MARSHAL *reply);
+
 static inline int readx(int s, void *_buf, int count)
 {
     char *buf = _buf;
diff --git a/cmds/keystore/netkeystore_main.c b/cmds/keystore/netkeystore_main.c
new file mode 100644
index 0000000..606e67a
--- /dev/null
+++ b/cmds/keystore/netkeystore_main.c
@@ -0,0 +1,29 @@
+/*
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#define LOG_TAG "keystore"
+
+int shell_command(const int argc, const char **argv);
+int server_main(const int argc, const char *argv[]);
+
+int main(const int argc, const char *argv[])
+{
+    if (argc > 1) {
+        return shell_command(argc - 1, argv + 1);
+    } else {
+        return server_main(argc, argv);
+    }
+}
diff --git a/cmds/keystore/tests/Android.mk b/cmds/keystore/tests/Android.mk
index 33541cc..e0a776a 100644
--- a/cmds/keystore/tests/Android.mk
+++ b/cmds/keystore/tests/Android.mk
@@ -16,7 +16,7 @@
 ifdef KEYSTORE_TESTS
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= netkeystore_test.c ../keymgmt.c
+LOCAL_SRC_FILES:= netkeystore_test.c ../keymgmt.c ../netkeystore.c
 LOCAL_SHARED_LIBRARIES := libcutils libssl
 LOCAL_MODULE:= netkeystore_test
 LOCAL_MODULE_TAGS := optional
diff --git a/cmds/keystore/tests/netkeystore_test.c b/cmds/keystore/tests/netkeystore_test.c
index 00390e0..ce79503 100644
--- a/cmds/keystore/tests/netkeystore_test.c
+++ b/cmds/keystore/tests/netkeystore_test.c
@@ -29,9 +29,13 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
+#include <cutils/log.h>
 
 #include "common.h"
 #include "keymgmt.h"
+#include "netkeystore.h"
+
+#define LOG_TAG "keystore_test"
 
 typedef int FUNC_PTR();
 typedef struct {
@@ -61,7 +65,9 @@
 
 void teardown()
 {
-    reset_keystore();
+    if (reset_keystore() != 0) {
+        fprintf(stderr, "Can not reset the test directory %s\n", TEST_DIR);
+    }
     rmdir(TEST_DIR);
 }
 
@@ -74,7 +80,7 @@
 
 FUNC_BODY(reset_keystore)
 {
-    chdir("/procx");
+    int ret = chdir("/proc");
     if (reset_keystore() == 0) return -1;
     chdir(TEST_DIR);
     return EXIT_SUCCESS;
@@ -87,7 +93,8 @@
     if (get_state() != UNLOCKED) return -1;
     lock();
     if (get_state() != LOCKED) return -1;
-    reset_keystore();
+
+    if (reset_keystore() != 0) return -1;
     if (get_state() != UNINITIALIZED) return -1;
     return EXIT_SUCCESS;
 }
@@ -218,6 +225,37 @@
     return EXIT_SUCCESS;
 }
 
+static int execute_cmd(int argc, const char *argv[], LPC_MARSHAL *cmd,
+        LPC_MARSHAL *reply)
+{
+    memset(cmd, 0, sizeof(LPC_MARSHAL));
+    memset(reply, 0, sizeof(LPC_MARSHAL));
+    if (parse_cmd(argc, argv, cmd)) return -1;
+    execute(cmd, reply);
+    return (reply->retcode ? -1 : 0);
+}
+
+FUNC_BODY(client_passwd)
+{
+    LPC_MARSHAL cmd, reply;
+    const char *set_passwd_cmds[2] = {"passwd", TEST_PASSWD};
+    const char *change_passwd_cmds[3] = {"passwd", TEST_PASSWD, TEST_NPASSWD};
+
+    if (execute_cmd(2, set_passwd_cmds, &cmd, &reply)) return -1;
+
+    lock();
+    if (unlock("55555555") == 0) return -1;
+    if (unlock(TEST_PASSWD) != 0) return -1;
+
+    if (execute_cmd(3, change_passwd_cmds, &cmd, &reply)) return -1;
+
+    lock();
+    if (unlock(TEST_PASSWD) == 0) return -1;
+    if (unlock(TEST_NPASSWD) != 0) return -1;
+
+    return EXIT_SUCCESS;
+}
+
 TESTFUNC all_tests[] = {
     FUNC_NAME(init_keystore),
     FUNC_NAME(reset_keystore),
@@ -229,11 +267,13 @@
     FUNC_NAME(get_key),
     FUNC_NAME(remove_key),
     FUNC_NAME(list_keys),
+    FUNC_NAME(client_passwd),
 };
 
 int main(int argc, char **argv) {
     int i, ret;
     for (i = 0 ; i < (int)(sizeof(all_tests)/sizeof(TESTFUNC)) ; ++i) {
+        LOGD("run %s...\n", all_tests[i].name);
         setup();
         if ((ret = all_tests[i].func()) != EXIT_SUCCESS) {
             fprintf(stderr, "ERROR in function %s\n", all_tests[i].name);
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index 51a0649..39ed769 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -1,9 +1,10 @@
+ifeq ($(BUILD_WITH_FULL_STAGEFRIGHT),true)
+
 LOCAL_PATH:= $(call my-dir)
 
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=       \
-        JPEGSource.cpp  \
 	stagefright.cpp
 
 LOCAL_SHARED_LIBRARIES := \
@@ -39,3 +40,5 @@
 LOCAL_MODULE:= record
 
 include $(BUILD_EXECUTABLE)
+
+endif
diff --git a/cmds/stagefright/SineSource.cpp b/cmds/stagefright/SineSource.cpp
index 3c25a7f..e5a6ccb 100644
--- a/cmds/stagefright/SineSource.cpp
+++ b/cmds/stagefright/SineSource.cpp
@@ -4,6 +4,7 @@
 
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
 
 namespace android {
@@ -48,7 +49,7 @@
 
 sp<MetaData> SineSource::getFormat() {
     sp<MetaData> meta = new MetaData;
-    meta->setCString(kKeyMIMEType, "audio/raw");
+    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
     meta->setInt32(kKeyChannelCount, mNumChannels);
     meta->setInt32(kKeySampleRate, mSampleRate);
 
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index 81a1c0a..323d448 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -21,6 +21,7 @@
 #include <media/stagefright/CameraSource.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/MPEG4Extractor.h>
 #include <media/stagefright/MPEG4Writer.h>
@@ -45,7 +46,7 @@
         sp<MetaData> meta = new MetaData;
         meta->setInt32(kKeyWidth, mWidth);
         meta->setInt32(kKeyHeight, mHeight);
-        meta->setCString(kKeyMIMEType, "video/raw");
+        meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
 
         return meta;
     }
@@ -149,8 +150,8 @@
 #endif
 
     sp<MetaData> enc_meta = new MetaData;
-    // enc_meta->setCString(kKeyMIMEType, "video/3gpp");
-    enc_meta->setCString(kKeyMIMEType, "video/mp4v-es");
+    // enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
+    enc_meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
     enc_meta->setInt32(kKeyWidth, width);
     enc_meta->setInt32(kKeyHeight, height);
 
@@ -228,7 +229,8 @@
 #endif
 
     sp<MetaData> encMeta = new MetaData;
-    encMeta->setCString(kKeyMIMEType, 1 ? "audio/3gpp" : "audio/mp4a-latm");
+    encMeta->setCString(kKeyMIMEType,
+            1 ? MEDIA_MIMETYPE_AUDIO_AMR_WB : MEDIA_MIMETYPE_AUDIO_AAC);
     encMeta->setInt32(kKeySampleRate, kSampleRate);
     encMeta->setInt32(kKeyChannelCount, kNumChannels);
     encMeta->setInt32(kKeyMaxInputSize, 8192);
@@ -248,7 +250,7 @@
         buffer->release();
         buffer = NULL;
 
-        if (++n == 10000) {
+        if (++n == 100) {
             break;
         }
     }
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index a0b83fb..73215d3 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -25,7 +25,9 @@
 #include <media/IMediaPlayerService.h>
 #include <media/stagefright/CachingDataSource.h>
 #include <media/stagefright/HTTPDataSource.h>
+#include <media/stagefright/JPEGSource.h>
 #include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaPlayerImpl.h>
 #include <media/stagefright/MediaExtractor.h>
 #include <media/stagefright/MediaSource.h>
@@ -34,8 +36,6 @@
 #include <media/stagefright/OMXClient.h>
 #include <media/stagefright/OMXCodec.h>
 
-#include "JPEGSource.h"
-
 using namespace android;
 
 static long gNumRepetitions;
@@ -126,6 +126,7 @@
     fprintf(stderr, "       -l(ist) components\n");
     fprintf(stderr, "       -m max-number-of-frames-to-decode in each pass\n");
     fprintf(stderr, "       -b bug to reproduce\n");
+    fprintf(stderr, "       -p(rofiles) dump decoder profiles supported\n");
 }
 
 int main(int argc, char **argv) {
@@ -133,12 +134,13 @@
 
     bool audioOnly = false;
     bool listComponents = false;
+    bool dumpProfiles = false;
     gNumRepetitions = 1;
     gMaxNumFrames = 0;
     gReproduceBug = -1;
 
     int res;
-    while ((res = getopt(argc, argv, "han:lm:b:")) >= 0) {
+    while ((res = getopt(argc, argv, "han:lm:b:p")) >= 0) {
         switch (res) {
             case 'a':
             {
@@ -174,6 +176,12 @@
                 break;
             }
 
+            case 'p':
+            {
+                dumpProfiles = true;
+                break;
+            }
+
             case '?':
             case 'h':
             default:
@@ -188,6 +196,53 @@
     argc -= optind;
     argv += optind;
 
+    if (dumpProfiles) {
+        sp<IServiceManager> sm = defaultServiceManager();
+        sp<IBinder> binder = sm->getService(String16("media.player"));
+        sp<IMediaPlayerService> service =
+            interface_cast<IMediaPlayerService>(binder);
+
+        CHECK(service.get() != NULL);
+
+        sp<IOMX> omx = service->createOMX();
+        CHECK(omx.get() != NULL);
+
+        const char *kMimeTypes[] = {
+            MEDIA_MIMETYPE_VIDEO_AVC, MEDIA_MIMETYPE_VIDEO_MPEG4,
+            MEDIA_MIMETYPE_VIDEO_H263
+        };
+
+        for (size_t k = 0; k < sizeof(kMimeTypes) / sizeof(kMimeTypes[0]);
+             ++k) {
+            printf("type '%s':\n", kMimeTypes[k]);
+
+            Vector<CodecCapabilities> results;
+            CHECK_EQ(QueryCodecs(omx, kMimeTypes[k],
+                                 true, // queryDecoders
+                                 &results), OK);
+
+            for (size_t i = 0; i < results.size(); ++i) {
+                printf("  decoder '%s' supports ",
+                       results[i].mComponentName.string());
+
+                if (results[i].mProfileLevels.size() == 0) {
+                    printf("NOTHING.\n");
+                    continue;
+                }
+
+                for (size_t j = 0; j < results[i].mProfileLevels.size(); ++j) {
+                    const CodecProfileLevel &profileLevel =
+                        results[i].mProfileLevels[j];
+
+                    printf("%s%ld/%ld", j > 0 ? ", " : "",
+                           profileLevel.mProfile, profileLevel.mLevel);
+                }
+
+                printf("\n");
+            }
+        }
+    }
+
     if (listComponents) {
         sp<IServiceManager> sm = defaultServiceManager();
         sp<IBinder> binder = sm->getService(String16("media.player"));
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 8c422a2..03346fe 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -185,7 +185,7 @@
 
         private final HandlerCaller mCaller;
 
-        private AccessibilityService mTarget;
+        private final AccessibilityService mTarget;
 
         public IEventListenerWrapper(AccessibilityService context) {
             mTarget = context;
@@ -211,9 +211,9 @@
             switch (message.what) {
                 case DO_ON_ACCESSIBILITY_EVENT :
                     AccessibilityEvent event = (AccessibilityEvent) message.obj;
-                    if (event != null){
-                      mTarget.onAccessibilityEvent(event);
-                      event.recycle();
+                    if (event != null) {
+                        mTarget.onAccessibilityEvent(event);
+                        event.recycle();
                     }
                     return;
                 case DO_ON_INTERRUPT :
diff --git a/core/java/android/accounts/AccountAuthenticatorCache.java b/core/java/android/accounts/AccountAuthenticatorCache.java
index 82cadd5..fdc5fbf 100644
--- a/core/java/android/accounts/AccountAuthenticatorCache.java
+++ b/core/java/android/accounts/AccountAuthenticatorCache.java
@@ -49,10 +49,15 @@
                     com.android.internal.R.styleable.AccountAuthenticator_label, 0);
             final int iconId = sa.getResourceId(
                     com.android.internal.R.styleable.AccountAuthenticator_icon, 0);
+            final int smallIconId = sa.getResourceId(
+                    com.android.internal.R.styleable.AccountAuthenticator_smallIcon, 0);
+            final int prefId = sa.getResourceId(
+                    com.android.internal.R.styleable.AccountAuthenticator_accountPreferences, 0);
             if (TextUtils.isEmpty(accountType)) {
                 return null;
             }
-            return new AuthenticatorDescription(accountType, packageName, labelId, iconId);
+            return new AuthenticatorDescription(accountType, packageName, labelId, iconId, 
+                    smallIconId, prefId);
         } finally {
             sa.recycle();
         }
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index d04abe5..9afeb74 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -21,11 +21,13 @@
 import android.content.Context;
 import android.content.IntentFilter;
 import android.content.BroadcastReceiver;
+import android.database.SQLException;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.Parcelable;
+import android.util.Log;
 
 import java.io.IOException;
 import java.util.concurrent.Callable;
@@ -364,7 +366,13 @@
         handler = (handler == null) ? mMainHandler : handler;
         handler.post(new Runnable() {
             public void run() {
-                listener.onAccountsUpdated(accountsCopy);
+                try {
+                    listener.onAccountsUpdated(accountsCopy);
+                } catch (SQLException e) {
+                    // Better luck next time.  If the problem was disk-full,
+                    // the STORAGE_OK intent will re-trigger the update.
+                    Log.e(TAG, "Can't update accounts", e);
+                }
             }
         });
     }
@@ -824,6 +832,8 @@
                 // Register a broadcast receiver to monitor account changes
                 IntentFilter intentFilter = new IntentFilter();
                 intentFilter.addAction(Constants.LOGIN_ACCOUNTS_CHANGED_ACTION);
+                // To recover from disk-full.
+                intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK); 
                 mContext.registerReceiver(mAccountsChangedBroadcastReceiver, intentFilter);
             }
         }
diff --git a/core/java/android/accounts/AuthenticatorDescription.java b/core/java/android/accounts/AuthenticatorDescription.java
index 672e648..28673b4 100644
--- a/core/java/android/accounts/AuthenticatorDescription.java
+++ b/core/java/android/accounts/AuthenticatorDescription.java
@@ -6,16 +6,21 @@
 public class AuthenticatorDescription implements Parcelable {
     final public String type;
     final public int labelId;
-    final public int iconId;
+    final public int iconId; 
+    final public int smallIconId; 
+    final public int accountPreferencesId;
     final public String packageName;
 
-    public AuthenticatorDescription(String type, String packageName, int labelId, int iconId) {
+    public AuthenticatorDescription(String type, String packageName, int labelId, int iconId, 
+            int smallIconId, int prefId) {
         if (type == null) throw new IllegalArgumentException("type cannot be null");
         if (packageName == null) throw new IllegalArgumentException("packageName cannot be null");
         this.type = type;
         this.packageName = packageName;
         this.labelId = labelId;
         this.iconId = iconId;
+        this.smallIconId = smallIconId;
+        this.accountPreferencesId = prefId;
     }
 
     public static AuthenticatorDescription newKey(String type) {
@@ -28,6 +33,8 @@
         this.packageName = null;
         this.labelId = 0;
         this.iconId = 0;
+        this.smallIconId = 0;
+        this.accountPreferencesId = 0;
     }
 
     private AuthenticatorDescription(Parcel source) {
@@ -35,6 +42,8 @@
         this.packageName = source.readString();
         this.labelId = source.readInt();
         this.iconId = source.readInt();
+        this.smallIconId = source.readInt();
+        this.accountPreferencesId = source.readInt();
     }
 
     public int describeContents() {
@@ -57,6 +66,8 @@
         dest.writeString(packageName);
         dest.writeInt(labelId);
         dest.writeInt(iconId);
+        dest.writeInt(smallIconId);
+        dest.writeInt(accountPreferencesId);
     }
 
     public static final Creator<AuthenticatorDescription> CREATOR =
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 80d7285..8c10091 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2649,10 +2649,8 @@
     }
 
     @Override
-    protected void onApplyThemeResource(Resources.Theme theme,
-                                      int resid,
-                                      boolean first)
-    {
+    protected void onApplyThemeResource(Resources.Theme theme, int resid,
+            boolean first) {
         if (mParent == null) {
             super.onApplyThemeResource(theme, resid, first);
         } else {
@@ -2723,6 +2721,66 @@
     }
 
     /**
+     * Like {@link #startActivityForResult(Intent, int)}, but allowing you
+     * to use a PendingIntent to describe the activity to be started.  Note
+     * that the given PendingIntent <em>must</em> have been created with
+     * {@link PendingIntent#getActivity PendingIntent.getActivity}; all other
+     * types will result in an IllegalArgumentException being thrown.
+     * 
+     * @param intent The PendingIntent to launch.
+     * @param requestCode If >= 0, this code will be returned in
+     *                    onActivityResult() when the activity exits.
+     * @param fillInIntent If non-null, this will be provided as the
+     * intent parameter to {@link PendingIntent#send(Context, int, Intent)
+     * PendingIntent.send(Context, int, Intent)}.
+     * @param flagsMask Intent flags in the original PendingIntent that you
+     * would like to change.
+     * @param flagsValues Desired values for any bits set in
+     * <var>flagsMask</var>
+     */
+    public void startActivityForResult(PendingIntent intent, int requestCode,
+            Intent fillInIntent, int flagsMask, int flagsValues)
+            throws PendingIntent.CanceledException {
+        if (mParent == null) {
+            startActivityForResultInner(intent, requestCode, fillInIntent,
+                    flagsMask, flagsValues, this);
+        } else {
+            mParent.startActivityFromChild(this, intent, requestCode,
+                    fillInIntent, flagsMask, flagsValues);
+        }
+    }
+
+    private void startActivityForResultInner(PendingIntent intent, int requestCode,
+            Intent fillInIntent, int flagsMask, int flagsValues, Activity activity)
+            throws PendingIntent.CanceledException {
+        try {
+            String resolvedType = null;
+            if (fillInIntent != null) {
+                resolvedType = fillInIntent.resolveTypeIfNeeded(getContentResolver());
+            }
+            int result = ActivityManagerNative.getDefault()
+                .startActivityPendingIntent(mMainThread.getApplicationThread(), intent,
+                        fillInIntent, resolvedType, mToken, activity.mEmbeddedID,
+                        requestCode, flagsMask, flagsValues);
+            if (result == IActivityManager.START_CANCELED) {
+                throw new PendingIntent.CanceledException();
+            }
+            Instrumentation.checkStartActivityResult(result, null);
+        } catch (RemoteException e) {
+        }
+        if (requestCode >= 0) {
+            // If this start is requesting a result, we can avoid making
+            // the activity visible until the result is received.  Setting
+            // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
+            // activity hidden during this time, to avoid flickering.
+            // This can only be done when a result is requested because
+            // that guarantees we will get information back when the
+            // activity is finished, no matter what happens to it.
+            mStartedActivity = true;
+        }
+    }
+
+    /**
      * Launch a new activity.  You will not receive any information about when
      * the activity exits.  This implementation overrides the base version,
      * providing information about
@@ -2746,6 +2804,27 @@
     }
 
     /**
+     * Like {@link #startActivity(Intent)}, but taking a PendingIntent
+     * to start; see
+     * {@link #startActivityForResult(PendingIntent, int, Intent, int, int)}
+     * for more information.
+     * 
+     * @param intent The PendingIntent to launch.
+     * @param fillInIntent If non-null, this will be provided as the
+     * intent parameter to {@link PendingIntent#send(Context, int, Intent)
+     * PendingIntent.send(Context, int, Intent)}.
+     * @param flagsMask Intent flags in the original PendingIntent that you
+     * would like to change.
+     * @param flagsValues Desired values for any bits set in
+     * <var>flagsMask</var>
+     */
+    public void startActivity(PendingIntent intent,
+            Intent fillInIntent, int flagsMask, int flagsValues)
+            throws PendingIntent.CanceledException {
+        startActivityForResult(intent, -1, fillInIntent, flagsMask, flagsValues);
+    }
+
+    /**
      * A special variation to launch an activity only if a new activity
      * instance is needed to handle the given Intent.  In other words, this is
      * just like {@link #startActivityForResult(Intent, int)} except: if you are 
@@ -2866,6 +2945,19 @@
     }
 
     /**
+     * Like {@link #startActivityFromChild(Activity, Intent, int)}, but
+     * taking a PendingIntent; see
+     * {@link #startActivityForResult(PendingIntent, int, Intent, int, int)}
+     * for more information.
+     */
+    public void startActivityFromChild(Activity child, PendingIntent intent,
+            int requestCode, Intent fillInIntent, int flagsMask, int flagsValues)
+            throws PendingIntent.CanceledException {
+        startActivityForResultInner(intent, requestCode, fillInIntent,
+                flagsMask, flagsValues, child);
+    }
+
+    /**
      * Call this to set the result that your activity will return to its
      * caller.
      * 
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 4ed152e..4796e49 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -144,6 +144,30 @@
             reply.writeInt(result);
             return true;
         }
+
+        case START_ACTIVITY_PENDING_INTENT_TRANSACTION:
+        {
+            data.enforceInterface(IActivityManager.descriptor);
+            IBinder b = data.readStrongBinder();
+            IApplicationThread app = ApplicationThreadNative.asInterface(b);
+            PendingIntent intent = PendingIntent.CREATOR.createFromParcel(data);
+            Intent fillInIntent = null;
+            if (data.readInt() != 0) {
+                fillInIntent = Intent.CREATOR.createFromParcel(data);
+            }
+            String resolvedType = data.readString();
+            IBinder resultTo = data.readStrongBinder();
+            String resultWho = data.readString();    
+            int requestCode = data.readInt();
+            int flagsMask = data.readInt();
+            int flagsValues = data.readInt();
+            int result = startActivityPendingIntent(app, intent,
+                    fillInIntent, resolvedType, resultTo, resultWho,
+                    requestCode, flagsMask, flagsValues);
+            reply.writeNoException();
+            reply.writeInt(result);
+            return true;
+        }
         
         case START_NEXT_MATCHING_ACTIVITY_TRANSACTION:
         {
@@ -1179,6 +1203,34 @@
         data.recycle();
         return result;
     }
+    public int startActivityPendingIntent(IApplicationThread caller,
+            PendingIntent intent, Intent fillInIntent, String resolvedType,
+            IBinder resultTo, String resultWho, int requestCode,
+            int flagsMask, int flagsValues) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
+        intent.writeToParcel(data, 0);
+        if (fillInIntent != null) {
+            data.writeInt(1);
+            fillInIntent.writeToParcel(data, 0);
+        } else {
+            data.writeInt(0);
+        }
+        data.writeString(resolvedType);
+        data.writeStrongBinder(resultTo);
+        data.writeString(resultWho);
+        data.writeInt(requestCode);
+        data.writeInt(flagsMask);
+        data.writeInt(flagsValues);
+        mRemote.transact(START_ACTIVITY_PENDING_INTENT_TRANSACTION, data, reply, 0);
+        reply.readException();
+        int result = reply.readInt();
+        reply.recycle();
+        data.recycle();
+        return result;
+    }
     public boolean startNextMatchingActivity(IBinder callingActivity,
             Intent intent) throws RemoteException {
         Parcel data = Parcel.obtain();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 2877aec..8142d1a 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4246,12 +4246,9 @@
         }
 
         thread.detach();
-        String name;
-        if (thread.mInitialApplication != null) {
-            name = thread.mInitialApplication.getPackageName();
-        } else {
-            name = "<unknown>";
-        }
+        String name = (thread.mInitialApplication != null)
+            ? thread.mInitialApplication.getPackageName()
+            : "<unknown>";
         Log.i(TAG, "Main thread of " + name + " is now exiting");
     }
 }
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index a937c11..8244645 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -77,10 +77,16 @@
     public static final int START_CLASS_NOT_FOUND = -2;
     public static final int START_FORWARD_AND_REQUEST_CONFLICT = -3;
     public static final int START_PERMISSION_DENIED = -4;
+    public static final int START_NOT_ACTIVITY = -5;
+    public static final int START_CANCELED = -6;
     public int startActivity(IApplicationThread caller,
             Intent intent, String resolvedType, Uri[] grantedUriPermissions,
             int grantedMode, IBinder resultTo, String resultWho, int requestCode,
             boolean onlyIfNeeded, boolean debug) throws RemoteException;
+    public int startActivityPendingIntent(IApplicationThread caller,
+            PendingIntent intent, Intent fillInIntent, String resolvedType,
+            IBinder resultTo, String resultWho, int requestCode,
+            int flagsMask, int flagsValues) throws RemoteException;
     public boolean startNextMatchingActivity(IBinder callingActivity,
             Intent intent) throws RemoteException;
     public boolean finishActivity(IBinder token, int code, Intent data)
@@ -436,4 +442,5 @@
     int CLOSE_SYSTEM_DIALOGS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+96;
     int GET_PROCESS_MEMORY_INFO_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+97;
     int KILL_APPLICATION_PROCESS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+98;
+    int START_ACTIVITY_PENDING_INTENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+99;
 }
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index e31f4f8..b8c3aa3 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -24,6 +24,7 @@
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
 import android.os.Bundle;
+import android.os.PerformanceCollector;
 import android.os.RemoteException;
 import android.os.Debug;
 import android.os.IBinder;
@@ -83,10 +84,8 @@
     private List<ActivityWaiter> mWaitingActivities;
     private List<ActivityMonitor> mActivityMonitors;
     private IInstrumentationWatcher mWatcher;
-    private long mPreCpuTime;
-    private long mStart;
     private boolean mAutomaticPerformanceSnapshots = false;
-    private Bundle mPrePerfMetrics = new Bundle();
+    private PerformanceCollector mPerformanceCollector;
     private Bundle mPerfMetrics = new Bundle();
 
     public Instrumentation() {
@@ -191,96 +190,21 @@
     
     public void setAutomaticPerformanceSnapshots() {
         mAutomaticPerformanceSnapshots = true;
+        mPerformanceCollector = new PerformanceCollector();
     }
 
     public void startPerformanceSnapshot() {
-        mStart = 0;
         if (!isProfiling()) {
-            // Add initial binder counts
-            Bundle binderCounts = getBinderCounts();
-            for (String key: binderCounts.keySet()) {
-                addPerfMetricLong("pre_" + key, binderCounts.getLong(key));
-            }
-
-            // Force a GC and zero out the performance counters.  Do this
-            // before reading initial CPU/wall-clock times so we don't include
-            // the cost of this setup in our final metrics.
-            startAllocCounting();
-
-            // Record CPU time up to this point, and start timing.  Note:  this
-            // must happen at the end of this method, otherwise the timing will
-            // include noise.
-            mStart = SystemClock.uptimeMillis();
-            mPreCpuTime = Process.getElapsedCpuTime();
+            mPerformanceCollector.beginSnapshot(null);
         }
     }
     
     public void endPerformanceSnapshot() {
         if (!isProfiling()) {
-            // Stop the timing. This must be done first before any other counting is stopped.
-            long cpuTime = Process.getElapsedCpuTime();
-            long duration = SystemClock.uptimeMillis();
-            
-            stopAllocCounting();
-            
-            long nativeMax = Debug.getNativeHeapSize() / 1024;
-            long nativeAllocated = Debug.getNativeHeapAllocatedSize() / 1024;
-            long nativeFree = Debug.getNativeHeapFreeSize() / 1024;
-
-            Debug.MemoryInfo memInfo = new Debug.MemoryInfo();
-            Debug.getMemoryInfo(memInfo);
-
-            Runtime runtime = Runtime.getRuntime();
-
-            long dalvikMax = runtime.totalMemory() / 1024;
-            long dalvikFree = runtime.freeMemory() / 1024;
-            long dalvikAllocated = dalvikMax - dalvikFree;
-            
-            // Add final binder counts
-            Bundle binderCounts = getBinderCounts();
-            for (String key: binderCounts.keySet()) {
-                addPerfMetricLong(key, binderCounts.getLong(key));
-            }
-            
-            // Add alloc counts
-            Bundle allocCounts = getAllocCounts();
-            for (String key: allocCounts.keySet()) {
-                addPerfMetricLong(key, allocCounts.getLong(key));
-            }
-            
-            addPerfMetricLong("execution_time", duration - mStart);
-            addPerfMetricLong("pre_cpu_time", mPreCpuTime);
-            addPerfMetricLong("cpu_time", cpuTime - mPreCpuTime);
-
-            addPerfMetricLong("native_size", nativeMax);
-            addPerfMetricLong("native_allocated", nativeAllocated);
-            addPerfMetricLong("native_free", nativeFree);
-            addPerfMetricInt("native_pss", memInfo.nativePss);
-            addPerfMetricInt("native_private_dirty", memInfo.nativePrivateDirty);
-            addPerfMetricInt("native_shared_dirty", memInfo.nativeSharedDirty);
-            
-            addPerfMetricLong("java_size", dalvikMax);
-            addPerfMetricLong("java_allocated", dalvikAllocated);
-            addPerfMetricLong("java_free", dalvikFree);
-            addPerfMetricInt("java_pss", memInfo.dalvikPss);
-            addPerfMetricInt("java_private_dirty", memInfo.dalvikPrivateDirty);
-            addPerfMetricInt("java_shared_dirty", memInfo.dalvikSharedDirty);
-            
-            addPerfMetricInt("other_pss", memInfo.otherPss);
-            addPerfMetricInt("other_private_dirty", memInfo.otherPrivateDirty);
-            addPerfMetricInt("other_shared_dirty", memInfo.otherSharedDirty);
-            
+            mPerfMetrics = mPerformanceCollector.endSnapshot();
         }
     }
     
-    private void addPerfMetricLong(String key, long value) {
-        mPerfMetrics.putLong("performance." + key, value);
-    }
-    
-    private void addPerfMetricInt(String key, int value) {
-        mPerfMetrics.putInt("performance." + key, value);
-    }
-    
     /**
      * Called when the instrumented application is stopping, after all of the
      * normal application cleanup has occurred.
@@ -1468,7 +1392,7 @@
         mWatcher = watcher;
     }
 
-    /*package*/ static void checkStartActivityResult(int res, Intent intent) {
+    /*package*/ static void checkStartActivityResult(int res, Object intent) {
         if (res >= IActivityManager.START_SUCCESS) {
             return;
         }
@@ -1476,10 +1400,10 @@
         switch (res) {
             case IActivityManager.START_INTENT_NOT_RESOLVED:
             case IActivityManager.START_CLASS_NOT_FOUND:
-                if (intent.getComponent() != null)
+                if (intent instanceof Intent && ((Intent)intent).getComponent() != null)
                     throw new ActivityNotFoundException(
                             "Unable to find explicit activity class "
-                            + intent.getComponent().toShortString()
+                            + ((Intent)intent).getComponent().toShortString()
                             + "; have you declared this activity in your AndroidManifest.xml?");
                 throw new ActivityNotFoundException(
                         "No Activity found to handle " + intent);
@@ -1489,6 +1413,9 @@
             case IActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
                 throw new AndroidRuntimeException(
                         "FORWARD_RESULT_FLAG used while also requesting a result");
+            case IActivityManager.START_NOT_ACTIVITY:
+                throw new IllegalArgumentException(
+                        "PendingIntent is not an activity");
             default:
                 throw new AndroidRuntimeException("Unknown error code "
                         + res + " when starting " + intent);
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index f7479bc..18d9b92 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -519,7 +519,8 @@
         mTarget = IIntentSender.Stub.asInterface(target);
     }
 
-    /*package*/ IIntentSender getTarget() {
+    /** @hide */
+    public IIntentSender getTarget() {
         return mTarget;
     }
 }
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 7e6efec..267d86a 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -769,8 +769,11 @@
  *     </tr>
  *     
  *     <tr><th>android:icon</th>
- *         <td>If provided, this icon will be used <i>in place</i> of the label string.  This
- *         is provided in order to present logos or other non-textual banners.</td>
+ *         <td>If provided, this icon will be shown in place of the label above the search box.
+ *           This is a reference to a drawable (icon) resource. Note that the application icon
+ *           is also used as an icon to the left of the search box and you cannot modify this
+ *           behavior, so including the icon attribute is unecessary and this may be
+ *           deprecated in the future.</td>
  *         <td align="center">No</td>
  *     </tr>
  *     
@@ -779,11 +782,6 @@
  *             entered.</td>
  *         <td align="center">No</td>
  *     </tr>
- *
- *     <tr><th>android:searchButtonText</th>
- *         <td>If provided, this text will replace the default text in the "Search" button.</td>
- *         <td align="center">No</td>
- *     </tr>
  *     
  *     <tr><th>android:searchMode</th>
  *         <td>If provided and non-zero, sets additional modes for control of the search 
@@ -792,15 +790,17 @@
  *                 <tbody>
  *                 <tr><th>showSearchLabelAsBadge</th>
  *                     <td>If set, this flag enables the display of the search target (label) 
- *                         within the search bar.  If this flag and showSearchIconAsBadge
+ *                         above the search box.  If this flag and showSearchIconAsBadge
  *                         (see below) are both not set, no badge will be shown.</td>
  *                 </tr>
  *                 <tr><th>showSearchIconAsBadge</th>
- *                     <td>If set, this flag enables the display of the search target (icon) within
- *                         the search bar.  If this flag and showSearchLabelAsBadge
+ *                     <td>If set, this flag enables the display of the search target (icon)
+ *                         above the search box.  If this flag and showSearchLabelAsBadge
  *                         (see above) are both not set, no badge will be shown.  If both flags
  *                         are set, showSearchIconAsBadge has precedence and the icon will be
- *                         shown.</td>
+ *                         shown. Because the application icon is now used to the left of the
+ *                         search box by default, using this search mode is no longer necessary
+ *                         and may be deprecated in the future.</td>
  *                 </tr>
  *                 <tr><th>queryRewriteFromData</th>
  *                     <td>If set, this flag causes the suggestion column SUGGEST_COLUMN_INTENT_DATA
@@ -2060,4 +2060,4 @@
         Thread thread = Thread.currentThread();
         Log.d(TAG, msg + " (" + thread.getName() + "-" + thread.getId() + ")");
     }
-}
+}
\ No newline at end of file
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index b531a50..2e9612a 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -42,9 +42,6 @@
  *
  * Currently the BluetoothA2dp service runs in the system server and this
  * proxy object will be immediately bound to the service on construction.
- * However this may change in future releases, and error codes such as
- * BluetoothError.ERROR_IPC_NOT_READY will be returned from this API when the
- * proxy object is not yet attached.
  * 
  * Currently this class provides methods to connect to A2DP audio sinks.
  *
@@ -54,20 +51,21 @@
     private static final String TAG = "BluetoothA2dp";
     private static final boolean DBG = false;
 
-    /** int extra for SINK_STATE_CHANGED_ACTION */
-    public static final String SINK_STATE =
-        "android.bluetooth.a2dp.intent.SINK_STATE";
-    /** int extra for SINK_STATE_CHANGED_ACTION */
-    public static final String SINK_PREVIOUS_STATE =
-        "android.bluetooth.a2dp.intent.SINK_PREVIOUS_STATE";
+    /** int extra for ACTION_SINK_STATE_CHANGED */
+    public static final String EXTRA_SINK_STATE =
+        "android.bluetooth.a2dp.extra.SINK_STATE";
+    /** int extra for ACTION_SINK_STATE_CHANGED */
+    public static final String EXTRA_PREVIOUS_SINK_STATE =
+        "android.bluetooth.a2dp.extra.PREVIOUS_SINK_STATE";
 
     /** Indicates the state of an A2DP audio sink has changed.
-     *  This intent will always contain SINK_STATE, SINK_PREVIOUS_STATE and
-     *  BluetoothIntent.ADDRESS extras.
+     * This intent will always contain EXTRA_SINK_STATE,
+     * EXTRA_PREVIOUS_SINK_STATE and BluetoothDevice.EXTRA_DEVICE
+     * extras.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String SINK_STATE_CHANGED_ACTION =
-        "android.bluetooth.a2dp.intent.action.SINK_STATE_CHANGED";
+    public static final String ACTION_SINK_STATE_CHANGED =
+        "android.bluetooth.a2dp.action.SINK_STATE_CHANGED";
 
     public static final int STATE_DISCONNECTED = 0;
     public static final int STATE_CONNECTING   = 1;
@@ -105,16 +103,16 @@
      *  Listen for SINK_STATE_CHANGED_ACTION to find out when the
      *  connection is completed.
      *  @param device Remote BT device.
-     *  @return Result code, negative indicates an immediate error.
+     *  @return false on immediate error, true otherwise
      *  @hide
      */
-    public int connectSink(BluetoothDevice device) {
+    public boolean connectSink(BluetoothDevice device) {
         if (DBG) log("connectSink(" + device + ")");
         try {
             return mService.connectSink(device);
         } catch (RemoteException e) {
-            Log.w(TAG, "", e);
-            return BluetoothError.ERROR_IPC;
+            Log.e(TAG, "", e);
+            return false;
         }
     }
 
@@ -122,16 +120,16 @@
      *  Listen for SINK_STATE_CHANGED_ACTION to find out when
      *  disconnect is completed.
      *  @param device Remote BT device.
-     *  @return Result code, negative indicates an immediate error.
+     *  @return false on immediate error, true otherwise
      *  @hide
      */
-    public int disconnectSink(BluetoothDevice device) {
+    public boolean disconnectSink(BluetoothDevice device) {
         if (DBG) log("disconnectSink(" + device + ")");
         try {
             return mService.disconnectSink(device);
         } catch (RemoteException e) {
-            Log.w(TAG, "", e);
-            return BluetoothError.ERROR_IPC;
+            Log.e(TAG, "", e);
+            return false;
         }
     }
 
@@ -156,14 +154,14 @@
             return Collections.unmodifiableSet(
                     new HashSet<BluetoothDevice>(Arrays.asList(mService.getConnectedSinks())));
         } catch (RemoteException e) {
-            Log.w(TAG, "", e);
+            Log.e(TAG, "", e);
             return null;
         }
     }
 
     /** Get the state of an A2DP sink
      *  @param device Remote BT device.
-     *  @return State code, or negative on error
+     *  @return State code, one of STATE_
      *  @hide
      */
     public int getSinkState(BluetoothDevice device) {
@@ -171,8 +169,8 @@
         try {
             return mService.getSinkState(device);
         } catch (RemoteException e) {
-            Log.w(TAG, "", e);
-            return BluetoothError.ERROR_IPC;
+            Log.e(TAG, "", e);
+            return BluetoothA2dp.STATE_DISCONNECTED;
         }
     }
 
@@ -186,15 +184,15 @@
      * @param device Paired sink
      * @param priority Integer priority, for example PRIORITY_AUTO or
      *                 PRIORITY_NONE
-     * @return Result code, negative indicates an error
+     * @return true if priority is set, false on error
      */
-    public int setSinkPriority(BluetoothDevice device, int priority) {
+    public boolean setSinkPriority(BluetoothDevice device, int priority) {
         if (DBG) log("setSinkPriority(" + device + ", " + priority + ")");
         try {
             return mService.setSinkPriority(device, priority);
         } catch (RemoteException e) {
-            Log.w(TAG, "", e);
-            return BluetoothError.ERROR_IPC;
+            Log.e(TAG, "", e);
+            return false;
         }
     }
 
@@ -208,8 +206,8 @@
         try {
             return mService.getSinkPriority(device);
         } catch (RemoteException e) {
-            Log.w(TAG, "", e);
-            return BluetoothError.ERROR_IPC;
+            Log.e(TAG, "", e);
+            return PRIORITY_OFF;
         }
     }
 
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 5a182f0..96a927b 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -16,6 +16,8 @@
 
 package android.bluetooth;
 
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
 import android.os.RemoteException;
 import android.util.Log;
 
@@ -34,48 +36,168 @@
  *
  * <p>Use the {@link BluetoothDevice} class for operations on remote Bluetooth
  * devices.
- *
- * <p>TODO: unhide more of this class
  */
 public final class BluetoothAdapter {
     private static final String TAG = "BluetoothAdapter";
 
-    /** @hide */
-    public static final int BLUETOOTH_STATE_OFF = 0;
-    /** @hide */
-    public static final int BLUETOOTH_STATE_TURNING_ON = 1;
-    /** @hide */
-    public static final int BLUETOOTH_STATE_ON = 2;
-    /** @hide */
-    public static final int BLUETOOTH_STATE_TURNING_OFF = 3;
+    /**
+     * Sentinel error value for this class. Guaranteed to not equal any other
+     * integer constant in this class. Provided as a convenience for functions
+     * that require a sentinel error value, for example:
+     * <p><code>Intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
+     * BluetoothAdapter.ERROR)</code>
+     */
+    public static final int ERROR = Integer.MIN_VALUE;
 
-    /** Inquiry scan and page scan are both off.
-     *  Device is neither discoverable nor connectable
-     *  @hide */
-    public static final int SCAN_MODE_NONE = 0;
-    /** Page scan is on, inquiry scan is off.
-     *  Device is connectable, but not discoverable
-     *  @hide*/
-    public static final int SCAN_MODE_CONNECTABLE = 1;
-    /** Page scan and inquiry scan are on.
-     *  Device is connectable and discoverable
-     *  @hide*/
-    public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 3;
+    /**
+     * Broadcast Action: The state of the local Bluetooth adapter has been
+     * changed.
+     * <p>For example, Bluetooth has been turned on or off.
+     * <p>Always contains the extra fields {@link #EXTRA_STATE} and {@link
+     * #EXTRA_PREVIOUS_STATE} containing the new and old states
+     * respectively.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_STATE_CHANGED =
+            "android.bluetooth.adapter.action.STATE_CHANGED";
 
-    /** @hide */
-    public static final int RESULT_FAILURE = -1;
-    /** @hide */
-    public static final int RESULT_SUCCESS = 0;
+    /**
+     * Used as an int extra field in {@link #ACTION_STATE_CHANGED}
+     * intents to request the current power state. Possible values are:
+     * {@link #STATE_OFF},
+     * {@link #STATE_TURNING_ON},
+     * {@link #STATE_ON},
+     * {@link #STATE_TURNING_OFF},
+     */
+    public static final String EXTRA_STATE =
+            "android.bluetooth.adapter.extra.STATE";
+    /**
+     * Used as an int extra field in {@link #ACTION_STATE_CHANGED}
+     * intents to request the previous power state. Possible values are:
+     * {@link #STATE_OFF},
+     * {@link #STATE_TURNING_ON},
+     * {@link #STATE_ON},
+     * {@link #STATE_TURNING_OFF},
+     */
+    public static final String EXTRA_PREVIOUS_STATE =
+            "android.bluetooth.adapter.extra.PREVIOUS_STATE";
 
-    /** The user will be prompted to enter a pin
-     * @hide */
-    public static final int PAIRING_VARIANT_PIN = 0;
-    /** The user will be prompted to enter a passkey
-     * @hide */
-    public static final int PAIRING_VARIANT_PASSKEY = 1;
-    /** The user will be prompted to confirm the passkey displayed on the screen
-     * @hide */
-    public static final int PAIRING_VARIANT_CONFIRMATION = 2;
+    /**
+     * Indicates the local Bluetooth adapter is off.
+     */
+    public static final int STATE_OFF = 10;
+    /**
+     * Indicates the local Bluetooth adapter is turning on. However local
+     * clients should wait for {@link #STATE_ON} before attempting to
+     * use the adapter.
+     */
+    public static final int STATE_TURNING_ON = 11;
+    /**
+     * Indicates the local Bluetooth adapter is on, and ready for use.
+     */
+    public static final int STATE_ON = 12;
+    /**
+     * Indicates the local Bluetooth adapter is turning off. Local clients
+     * should immediately attempt graceful disconnection of any remote links.
+     */
+    public static final int STATE_TURNING_OFF = 13;
+
+    /**
+     * Broadcast Action: Indicates the Bluetooth scan mode of the local Adapter
+     * has changed.
+     * <p>Always contains the extra fields {@link #EXTRA_SCAN_MODE} and {@link
+     * #EXTRA_PREVIOUS_SCAN_MODE} containing the new and old scan modes
+     * respectively.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_SCAN_MODE_CHANGED =
+            "android.bluetooth.adapter.action.SCAN_MODE_CHANGED";
+
+    /**
+     * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED}
+     * intents to request the current scan mode. Possible values are:
+     * {@link #SCAN_MODE_NONE},
+     * {@link #SCAN_MODE_CONNECTABLE},
+     * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE},
+     */
+    public static final String EXTRA_SCAN_MODE = "android.bluetooth.adapter.extra.SCAN_MODE";
+    /**
+     * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED}
+     * intents to request the previous scan mode. Possible values are:
+     * {@link #SCAN_MODE_NONE},
+     * {@link #SCAN_MODE_CONNECTABLE},
+     * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE},
+     */
+    public static final String EXTRA_PREVIOUS_SCAN_MODE =
+            "android.bluetooth.adapter.extra.PREVIOUS_SCAN_MODE";
+
+    /**
+     * Indicates that both inquiry scan and page scan are disabled on the local
+     * Bluetooth adapter. Therefore this device is neither discoverable
+     * nor connectable from remote Bluetooth devices.
+     */
+    public static final int SCAN_MODE_NONE = 20;
+    /**
+     * Indicates that inquiry scan is disabled, but page scan is enabled on the
+     * local Bluetooth adapter. Therefore this device is not discoverable from
+     * remote Bluetooth devices, but is connectable from remote devices that
+     * have previously discovered this device.
+     */
+    public static final int SCAN_MODE_CONNECTABLE = 21;
+    /**
+     * Indicates that both inquiry scan and page scan are enabled on the local
+     * Bluetooth adapter. Therefore this device is both discoverable and
+     * connectable from remote Bluetooth devices.
+     */
+    public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 23;
+
+
+    /**
+     * Broadcast Action: The local Bluetooth adapter has started the remote
+     * device discovery process.
+     * <p>This usually involves an inquiry scan of about 12 seconds, followed
+     * by a page scan of each new device to retrieve its Bluetooth name.
+     * <p>Register for {@link BluetoothDevice#ACTION_FOUND} to be notified as
+     * remote Bluetooth devices are found.
+     * <p>Device discovery is a heavyweight procedure. New connections to
+     * remote Bluetooth devices should not be attempted while discovery is in
+     * progress, and existing connections will experience limited bandwidth
+     * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing
+     * discovery.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_DISCOVERY_STARTED =
+            "android.bluetooth.adapter.action.DISCOVERY_STARTED";
+    /**
+     * Broadcast Action: The local Bluetooth adapter has finished the device
+     * discovery process.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_DISCOVERY_FINISHED =
+            "android.bluetooth.adapter.action.DISCOVERY_FINISHED";
+
+    /**
+     * Broadcast Action: The local Bluetooth adapter has changed its friendly
+     * Bluetooth name.
+     * <p>This name is visible to remote Bluetooth devices.
+     * <p>Always contains the extra field {@link #EXTRA_LOCAL_NAME} containing
+     * the name.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_LOCAL_NAME_CHANGED =
+            "android.bluetooth.adapter.action.LOCAL_NAME_CHANGED";
+    /**
+     * Used as a String extra field in {@link #ACTION_LOCAL_NAME_CHANGED}
+     * intents to request the local Bluetooth name.
+     */
+    public static final String EXTRA_LOCAL_NAME = "android.bluetooth.adapter.extra.LOCAL_NAME";
+
+    private static final int ADDRESS_LENGTH = 17;
 
     private final IBluetooth mService;
 
@@ -94,9 +216,11 @@
      * Get a {@link BluetoothDevice} object for the given Bluetooth hardware
      * address.
      * <p>Valid Bluetooth hardware addresses must be upper case, in a format
-     * such as "00:11:22:33:AA:BB".
+     * such as "00:11:22:33:AA:BB". The helper {@link #checkBluetoothAddress} is
+     * available to validate a Bluetooth address.
      * <p>A {@link BluetoothDevice} will always be returned for a valid
      * hardware address, even if this adapter has never seen that device.
+     *
      * @param address valid Bluetooth MAC address
      * @throws IllegalArgumentException if address is invalid
      */
@@ -105,10 +229,12 @@
     }
 
     /**
-     * Is Bluetooth currently turned on.
+     * Return true if Bluetooth is currently enabled and ready for use.
+     * <p>Equivalent to:
+     * <code>getBluetoothState() == STATE_ON</code>
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
      *
-     * @return true if Bluetooth enabled, false otherwise.
-     * @hide
+     * @return true if the local adapter is turned on
      */
     public boolean isEnabled() {
         try {
@@ -118,28 +244,40 @@
     }
 
     /**
-     * Get the current state of Bluetooth.
+     * Get the current state of the local Bluetooth adapter.
+     * <p>Possible return values are
+     * {@link #STATE_OFF},
+     * {@link #STATE_TURNING_ON},
+     * {@link #STATE_ON},
+     * {@link #STATE_TURNING_OFF}.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
      *
-     * @return One of BLUETOOTH_STATE_ or BluetoothError.ERROR.
-     * @hide
+     * @return current state of Bluetooth adapter
      */
-    public int getBluetoothState() {
+    public int getState() {
         try {
             return mService.getBluetoothState();
         } catch (RemoteException e) {Log.e(TAG, "", e);}
-        return BluetoothError.ERROR;
+        return STATE_OFF;
     }
 
     /**
-     * Enable the Bluetooth device.
-     * Turn on the underlying hardware.
-     * This is an asynchronous call,
-     * BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION can be used to check if
-     * and when the device is sucessfully enabled.
-     * @return false if we cannot enable the Bluetooth device. True does not
-     * imply the device was enabled, it only implies that so far there were no
-     * problems.
-     * @hide
+     * Turn on the local Bluetooth adapter.
+     * <p>This powers on the underlying Bluetooth hardware, and starts all
+     * Bluetooth system services.
+     * <p>This is an asynchronous call: it will return immediatley, and
+     * clients should listen for {@link #ACTION_STATE_CHANGED}
+     * to be notified of subsequent adapter state changes. If this call returns
+     * true, then the adapter state will immediately transition from {@link
+     * #STATE_OFF} to {@link #STATE_TURNING_ON}, and some time
+     * later transition to either {@link #STATE_OFF} or {@link
+     * #STATE_ON}. If this call returns false then there was an
+     * immediate problem that will prevent the adapter from being turned on -
+     * such as Airplane mode, or the adapter is already turned on.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
+     *
+     * @return true to indicate adapter startup has begun, or false on
+     *         immediate error
      */
     public boolean enable() {
         try {
@@ -149,11 +287,22 @@
     }
 
     /**
-     * Disable the Bluetooth device.
-     * This turns off the underlying hardware.
+     * Turn off the local Bluetooth adapter.
+     * <p>This gracefully shuts down all Bluetooth connections, stops Bluetooth
+     * system services, and powers down the underlying Bluetooth hardware.
+     * <p>This is an asynchronous call: it will return immediatley, and
+     * clients should listen for {@link #ACTION_STATE_CHANGED}
+     * to be notified of subsequent adapter state changes. If this call returns
+     * true, then the adapter state will immediately transition from {@link
+     * #STATE_ON} to {@link #STATE_TURNING_OFF}, and some time
+     * later transition to either {@link #STATE_OFF} or {@link
+     * #STATE_ON}. If this call returns false then there was an
+     * immediate problem that will prevent the adapter from being turned off -
+     * such as the adapter already being turned off.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
      *
-     * @return true if successful, false otherwise.
-     * @hide
+     * @return true to indicate adapter shutdown has begun, or false on
+     *         immediate error
      */
     public boolean disable() {
         try {
@@ -162,7 +311,13 @@
         return false;
     }
 
-    /** @hide */
+    /**
+     * Returns the hardware address of the local Bluetooth adapter.
+     * <p>For example, "00:11:22:AA:BB:CC".
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
+     *
+     * @return Bluetooth hardware address as string
+     */
     public String getAddress() {
         try {
             return mService.getAddress();
@@ -171,13 +326,11 @@
     }
 
     /**
-     * Get the friendly Bluetooth name of this device.
+     * Get the friendly Bluetooth name of the local Bluetooth adapter.
+     * <p>This name is visible to remote Bluetooth devices.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
      *
-     * This name is visible to remote Bluetooth devices. Currently it is only
-     * possible to retrieve the Bluetooth name when Bluetooth is enabled.
-     *
-     * @return the Bluetooth name, or null if there was a problem.
-     * @hide
+     * @return the Bluetooth name, or null on error
      */
     public String getName() {
         try {
@@ -187,14 +340,15 @@
     }
 
     /**
-     * Set the friendly Bluetooth name of this device.
+     * Set the friendly Bluetooth name of the local Bluetoth adapter.
+     * <p>This name is visible to remote Bluetooth devices.
+     * <p>Valid Bluetooth names are a maximum of 248 UTF-8 characters, however
+     * many remote devices can only display the first 40 characters, and some
+     * may be limited to just 20.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
      *
-     * This name is visible to remote Bluetooth devices. The Bluetooth Service
-     * is responsible for persisting this name.
-     *
-     * @param name the name to set
-     * @return     true, if the name was successfully set. False otherwise.
-     * @hide
+     * @param name a valid Bluetooth name
+     * @return     true if the name was set, false otherwise
      */
     public boolean setName(String name) {
         try {
@@ -204,28 +358,46 @@
     }
 
     /**
-     * Get the current scan mode.
-     * Used to determine if the local device is connectable and/or discoverable
-     * @return Scan mode, one of SCAN_MODE_* or an error code
-     * @hide
+     * Get the current Bluetooth scan mode of the local Bluetooth adaper.
+     * <p>The Bluetooth scan mode determines if the local adapter is
+     * connectable and/or discoverable from remote Bluetooth devices.
+     * <p>Possible values are:
+     * {@link #SCAN_MODE_NONE},
+     * {@link #SCAN_MODE_CONNECTABLE},
+     * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
+     *
+     * @return scan mode
      */
     public int getScanMode() {
         try {
             return mService.getScanMode();
         } catch (RemoteException e) {Log.e(TAG, "", e);}
-        return BluetoothError.ERROR_IPC;
+        return SCAN_MODE_NONE;
     }
 
     /**
-     * Set the current scan mode.
-     * Used to make the local device connectable and/or discoverable
-     * @param scanMode One of SCAN_MODE_*
-     * @hide
+     * Set the Bluetooth scan mode of the local Bluetooth adapter.
+     * <p>The Bluetooth scan mode determines if the local adapter is
+     * connectable and/or discoverable from remote Bluetooth devices.
+     * <p>For privacy reasons, it is recommended to limit the duration of time
+     * that the local adapter remains in a discoverable scan mode. For example,
+     * 2 minutes is a generous time to allow a remote Bluetooth device to
+     * initiate and complete its discovery process.
+     * <p>Valid scan mode values are:
+     * {@link #SCAN_MODE_NONE},
+     * {@link #SCAN_MODE_CONNECTABLE},
+     * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE}.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}
+     *
+     * @param mode valid scan mode
+     * @return     true if the scan mode was set, false otherwise
      */
-    public void setScanMode(int scanMode) {
+    public boolean setScanMode(int mode) {
         try {
-            mService.setScanMode(scanMode);
+            return mService.setScanMode(mode);
         } catch (RemoteException e) {Log.e(TAG, "", e);}
+        return false;
     }
 
     /** @hide */
@@ -243,7 +415,29 @@
         } catch (RemoteException e) {Log.e(TAG, "", e);}
     }
 
-    /** @hide */
+    /**
+     * Start the remote device discovery process.
+     * <p>The discovery process usually involves an inquiry scan of about 12
+     * seconds, followed by a page scan of each new device to retrieve its
+     * Bluetooth name.
+     * <p>This is an asynchronous call, it will return immediately. Register
+     * for {@link #ACTION_DISCOVERY_STARTED} and {@link
+     * #ACTION_DISCOVERY_FINISHED} intents to determine exactly when the
+     * discovery starts and completes. Register for {@link
+     * BluetoothDevice#ACTION_FOUND} to be notified as remote Bluetooth devices
+     * are found.
+     * <p>Device discovery is a heavyweight procedure. New connections to
+     * remote Bluetooth devices should not be attempted while discovery is in
+     * progress, and existing connections will experience limited bandwidth
+     * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing
+     * discovery.
+     * <p>Device discovery will only find remote devices that are currently
+     * <i>discoverable</i> (inquiry scan enabled). Many Bluetooth devices are
+     * not discoverable by default, and need to be entered into a special mode.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
+     *
+     * @return true on success, false on error
+     */
     public boolean startDiscovery() {
         try {
             return mService.startDiscovery();
@@ -251,14 +445,33 @@
         return false;
     }
 
-    /** @hide */
-    public void cancelDiscovery() {
+    /**
+     * Cancel the current device discovery process.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
+     *
+     * @return true on success, false on error
+     */
+    public boolean cancelDiscovery() {
         try {
             mService.cancelDiscovery();
         } catch (RemoteException e) {Log.e(TAG, "", e);}
+        return false;
     }
 
-    /** @hide */
+    /**
+     * Return true if the local Bluetooth adapter is currently in the device
+     * discovery process.
+     * <p>Device discovery is a heavyweight procedure. New connections to
+     * remote Bluetooth devices should not be attempted while discovery is in
+     * progress, and existing connections will experience limited bandwidth
+     * and high latency. Use {@link #cancelDiscovery()} to cancel an ongoing
+     * discovery.
+     * <p>Applications can also register for {@link #ACTION_DISCOVERY_STARTED}
+     * or {@link #ACTION_DISCOVERY_FINISHED} to be notified when discovery
+     * starts or completes.
+     *
+     * @return true if discovering
+     */
     public boolean isDiscovering() {
         try {
             return mService.isDiscovering();
@@ -267,27 +480,10 @@
     }
 
     /**
-     * List remote devices that are bonded (paired) to the local adapter.
+     * Return the set of {@link BluetoothDevice} objects that are bonded
+     * (paired) to the local adapter.
      *
-     * Bonding (pairing) is the process by which the user enters a pin code for
-     * the device, which generates a shared link key, allowing for
-     * authentication and encryption of future connections. In Android we
-     * require bonding before RFCOMM or SCO connections can be made to a remote
-     * device.
-     *
-     * This function lists which remote devices we have a link key for. It does
-     * not cause any RF transmission, and does not check if the remote device
-     * still has it's link key with us. If the other side no longer has its
-     * link key then the RFCOMM or SCO connection attempt will result in an
-     * error.
-     *
-     * This function does not check if the remote device is in range.
-     *
-     * Remote devices that have an in-progress bonding attempt are not
-     * returned.
-     *
-     * @return unmodifiable set of bonded devices, or null on error
-     * @hide
+     * @return unmodifiable set of {@link BluetoothDevice}, or null on error
      */
     public Set<BluetoothDevice> getBondedDevices() {
         try {
@@ -374,4 +570,33 @@
         }
         return Collections.unmodifiableSet(devices);
     }
+
+    /**
+     * Validate a Bluetooth address, such as "00:43:A8:23:10:F0"
+     *
+     * @param address Bluetooth address as string
+     * @return true if the address is valid, false otherwise
+     */
+    public static boolean checkBluetoothAddress(String address) {
+        if (address == null || address.length() != ADDRESS_LENGTH) {
+            return false;
+        }
+        for (int i = 0; i < ADDRESS_LENGTH; i++) {
+            char c = address.charAt(i);
+            switch (i % 3) {
+            case 0:
+            case 1:
+                if (Character.digit(c, 16) != -1) {
+                    break;  // hex character, OK
+                }
+                return false;
+            case 2:
+                if (c == ':') {
+                    break;  // OK
+                }
+                return false;
+            }
+        }
+        return true;
+    }
 }
diff --git a/core/java/android/bluetooth/BluetoothClass.java b/core/java/android/bluetooth/BluetoothClass.java
index 0061f10..1fbbf78 100644
--- a/core/java/android/bluetooth/BluetoothClass.java
+++ b/core/java/android/bluetooth/BluetoothClass.java
@@ -16,43 +16,89 @@
 
 package android.bluetooth;
 
+import android.os.Parcel;
+import android.os.Parcelable;
+
 /**
- * The Android Bluetooth API is not finalized, and *will* change. Use at your
- * own risk.
+ * Represents a Bluetooth class.
  *
- * Static helper methods and constants to decode the device class bit vector
- * returned by the Bluetooth API.
- *
- * The Android Bluetooth API returns a 32-bit integer to represent the class.
- * The format of these bits is defined at
+ * <p>Bluetooth Class is a 32 bit field. The format of these bits is defined at
  *   http://www.bluetooth.org/Technical/AssignedNumbers/baseband.htm
- * (login required). This class provides static helper methods and constants to
- * determine what Service Class(es) and Device Class are encoded in the 32-bit
- * class.
+ * (login required). This class contains that 32 bit field, and provides
+ * constants and methods to determine which Service Class(es) and Device Class
+ * are encoded in that field.
  *
- * Devices typically have zero or more service classes, and exactly one device
- * class. The device class is encoded as a major and minor device class, the
- * minor being a subset of the major.
+ * <p>Every Bluetooth Class is composed of zero or more service classes, and
+ * exactly one device class. The device class is further broken down into major
+ * and minor device class components.
  *
- * Class is useful to describe a device (for example to show an icon),
- * but does not reliably describe what profiles a device supports. To determine
- * profile support you usually need to perform SDP queries.
+ * <p>Class is useful as a hint to roughly describe a device (for example to
+ * show an icon in the UI), but does not reliably describe which Bluetooth
+ * profiles or services are actually supported by a device. Accurate service
+ * discovery is done through SDP requests.
  *
- * Each of these helper methods takes the 32-bit integer class as an argument.
- *
- * @hide
+ * <p>Use {@link BluetoothDevice#getBluetoothClass} to retrieve the class for
+ * a remote device.
  */
-public class BluetoothClass {
-    /** Indicates the Bluetooth API could not retrieve the class */
+public final class BluetoothClass implements Parcelable {
+    /**
+     * Legacy error value. Applications should use null instead.
+     * @hide
+     */
     public static final int ERROR = 0xFF000000;
 
-    public static final int PROFILE_HEADSET = 0;
-    public static final int PROFILE_A2DP = 1;
-    public static final int PROFILE_OPP = 2;
+    private final int mClass;
 
-    /** Every Bluetooth device has zero or more service classes */
-    public static class Service {
-        public static final int BITMASK                 = 0xFFE000;
+    /** @hide */
+    public BluetoothClass(int classInt) {
+        mClass = classInt;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o instanceof BluetoothClass) {
+            return mClass == ((BluetoothClass)o).mClass;
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return mClass;
+    }
+
+    @Override
+    public String toString() {
+        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) {
+            return new BluetoothClass(in.readInt());
+        }
+        public BluetoothClass[] newArray(int size) {
+            return new BluetoothClass[size];
+        }
+    };
+
+    /** @hide */
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(mClass);
+    }
+
+    /**
+     * Bluetooth service classes.
+     * <p>Each {@link BluetoothClass} encodes zero or more service classes.
+     */
+    public static final class Service {
+        private static final int BITMASK                 = 0xFFE000;
 
         public static final int LIMITED_DISCOVERABILITY = 0x002000;
         public static final int POSITIONING             = 0x010000;
@@ -63,32 +109,35 @@
         public static final int AUDIO                   = 0x200000;
         public static final int TELEPHONY               = 0x400000;
         public static final int INFORMATION             = 0x800000;
-
-        /** Returns true if the given class supports the given Service Class.
-         * A bluetooth device can claim to support zero or more service classes.
-         * @param btClass The bluetooth class.
-         * @param serviceClass The service class constant to test for. For
-         *                     example, Service.AUDIO. Must be one of the
-         *                     Service.FOO constants.
-         * @return True if the service class is supported.
-         */
-        public static boolean hasService(int btClass, int serviceClass) {
-            if (btClass == ERROR) {
-                return false;
-            }
-            return ((btClass & Service.BITMASK & serviceClass) != 0);
-        }
     }
 
-    /** Every Bluetooth device has exactly one device class, comprimised of
-     *  major and minor components. We have not included the minor classes for
-     *  major classes: NETWORKING, PERIPHERAL and IMAGING yet because they work
-     *  a little differently. */
+    /**
+     * Return true if the specified service class is supported by this class.
+     * <p>Valid service classes are the public constants in
+     * {@link BluetoothClass.Service}. For example, {@link
+     * BluetoothClass.Service#AUDIO}.
+     *
+     * @param service valid service class
+     * @return true if the service class is supported
+     */
+    public boolean hasService(int service) {
+        return ((mClass & Service.BITMASK & service) != 0);
+    }
+
+    /**
+     * Bluetooth device classes.
+     * <p>Each {@link BluetoothClass} encodes exactly one device class, with
+     * major and minor components.
+     * <p>The constants in {@link
+     * BluetoothClass.Device} represent a combination of major and minor
+     * components (the complete device class). The constants in {@link
+     * BluetoothClass.Device.Major} represent just the major device classes.
+     */
     public static class Device {
-        public static final int BITMASK               = 0x1FFC;
+        private static final int BITMASK               = 0x1FFC;
 
         public static class Major {
-            public static final int BITMASK           = 0x1F00;
+            private static final int BITMASK           = 0x1F00;
 
             public static final int MISC              = 0x0000;
             public static final int COMPUTER          = 0x0100;
@@ -101,18 +150,6 @@
             public static final int TOY               = 0x0800;
             public static final int HEALTH            = 0x0900;
             public static final int UNCATEGORIZED     = 0x1F00;
-
-            /** Returns the Major Device Class component of a bluetooth class.
-             * Values returned from this function can be compared with the constants
-             * Device.Major.FOO. A bluetooth device can only be associated
-             * with one major class.
-             */
-            public static int getDeviceMajor(int btClass) {
-                if (btClass == ERROR) {
-                    return ERROR;
-                }
-                return (btClass & Device.Major.BITMASK);
-            }
         }
 
         // Devices in the COMPUTER major class
@@ -178,42 +215,62 @@
         public static final int HEALTH_PULSE_OXIMETER               = 0x0914;
         public static final int HEALTH_PULSE_RATE                   = 0x0918;
         public static final int HEALTH_DATA_DISPLAY                 = 0x091C;
-
-        /** Returns the Device Class component of a bluetooth class. This includes
-         * both the major and minor device components. Values returned from this
-         * function can be compared with the constants Device.FOO. A bluetooth
-         * device can only be associated with one device class.
-         */
-        public static int getDevice(int btClass) {
-            if (btClass == ERROR) {
-                return ERROR;
-            }
-            return (btClass & Device.BITMASK);
-        }
     }
 
     /**
+     * Return the major device class component of this Bluetooth class.
+     * <p>Values returned from this function can be compared with the
+     * public constants in {@link BluetoothClass.Device.Major} to determine
+     * which major class is encoded in this Bluetooth class.
+     *
+     * @return major device class component
+     */
+    public int getMajorDeviceClass() {
+        return (mClass & Device.Major.BITMASK);
+    }
+
+    /**
+     * Return the (major and minor) device class component of this
+     * {@link BluetoothClass}.
+     * <p>Values returned from this function can be compared with the
+     * public constants in {@link BluetoothClass.Device} to determine which
+     * device class is encoded in this Bluetooth class.
+     *
+     * @return device class component
+     */
+    public int getDeviceClass() {
+        return (mClass & Device.BITMASK);
+    }
+
+    /** @hide */
+    public static final int PROFILE_HEADSET = 0;
+    /** @hide */
+    public static final int PROFILE_A2DP = 1;
+    /** @hide */
+    public static final int PROFILE_OPP = 2;
+
+    /**
      * Check class bits for possible bluetooth profile support.
      * This is a simple heuristic that tries to guess if a device with the
      * given class bits might support specified profile. It is not accurate for all
      * devices. It tries to err on the side of false positives.
-     * @param btClass The class
      * @param profile The profile to be checked
      * @return True if this device might support specified profile.
+     * @hide
      */
-    public static boolean doesClassMatch(int btClass, int profile) {
+    public boolean doesClassMatch(int profile) {
         if (profile == PROFILE_A2DP) {
-            if (BluetoothClass.Service.hasService(btClass, BluetoothClass.Service.RENDER)) {
+            if (hasService(Service.RENDER)) {
                 return true;
             }
             // By the A2DP spec, sinks must indicate the RENDER service.
             // However we found some that do not (Chordette). So lets also
             // match on some other class bits.
-            switch (BluetoothClass.Device.getDevice(btClass)) {
-                case BluetoothClass.Device.AUDIO_VIDEO_HIFI_AUDIO:
-                case BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES:
-                case BluetoothClass.Device.AUDIO_VIDEO_LOUDSPEAKER:
-                case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
+            switch (getDeviceClass()) {
+                case Device.AUDIO_VIDEO_HIFI_AUDIO:
+                case Device.AUDIO_VIDEO_HEADPHONES:
+                case Device.AUDIO_VIDEO_LOUDSPEAKER:
+                case Device.AUDIO_VIDEO_CAR_AUDIO:
                     return true;
                 default:
                     return false;
@@ -221,37 +278,37 @@
         } else if (profile == PROFILE_HEADSET) {
             // The render service class is required by the spec for HFP, so is a
             // pretty good signal
-            if (BluetoothClass.Service.hasService(btClass, BluetoothClass.Service.RENDER)) {
+            if (hasService(Service.RENDER)) {
                 return true;
             }
             // Just in case they forgot the render service class
-            switch (BluetoothClass.Device.getDevice(btClass)) {
-                case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
-                case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
-                case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
+            switch (getDeviceClass()) {
+                case Device.AUDIO_VIDEO_HANDSFREE:
+                case Device.AUDIO_VIDEO_WEARABLE_HEADSET:
+                case Device.AUDIO_VIDEO_CAR_AUDIO:
                     return true;
                 default:
                     return false;
             }
         } else if (profile == PROFILE_OPP) {
-            if (BluetoothClass.Service.hasService(btClass, BluetoothClass.Service.OBJECT_TRANSFER)) {
+            if (hasService(Service.OBJECT_TRANSFER)) {
                 return true;
             }
 
-            switch (BluetoothClass.Device.getDevice(btClass)) {
-                case BluetoothClass.Device.COMPUTER_UNCATEGORIZED:
-                case BluetoothClass.Device.COMPUTER_DESKTOP:
-                case BluetoothClass.Device.COMPUTER_SERVER:
-                case BluetoothClass.Device.COMPUTER_LAPTOP:
-                case BluetoothClass.Device.COMPUTER_HANDHELD_PC_PDA:
-                case BluetoothClass.Device.COMPUTER_PALM_SIZE_PC_PDA:
-                case BluetoothClass.Device.COMPUTER_WEARABLE:
-                case BluetoothClass.Device.PHONE_UNCATEGORIZED:
-                case BluetoothClass.Device.PHONE_CELLULAR:
-                case BluetoothClass.Device.PHONE_CORDLESS:
-                case BluetoothClass.Device.PHONE_SMART:
-                case BluetoothClass.Device.PHONE_MODEM_OR_GATEWAY:
-                case BluetoothClass.Device.PHONE_ISDN:
+            switch (getDeviceClass()) {
+                case Device.COMPUTER_UNCATEGORIZED:
+                case Device.COMPUTER_DESKTOP:
+                case Device.COMPUTER_SERVER:
+                case Device.COMPUTER_LAPTOP:
+                case Device.COMPUTER_HANDHELD_PC_PDA:
+                case Device.COMPUTER_PALM_SIZE_PC_PDA:
+                case Device.COMPUTER_WEARABLE:
+                case Device.PHONE_UNCATEGORIZED:
+                case Device.PHONE_CELLULAR:
+                case Device.PHONE_CORDLESS:
+                case Device.PHONE_SMART:
+                case Device.PHONE_MODEM_OR_GATEWAY:
+                case Device.PHONE_ISDN:
                     return true;
                 default:
                     return false;
@@ -261,4 +318,3 @@
         }
     }
 }
-
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 1b7011c..b1861ac 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -16,6 +16,8 @@
 
 package android.bluetooth;
 
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
 import android.content.Context;
 import android.os.IBinder;
 import android.os.Parcel;
@@ -38,36 +40,217 @@
  * are performed on the remote Bluetooth hardware address, using the
  * {@link BluetoothAdapter} that was used to create this {@link
  * BluetoothDevice}.
- *
- * TODO: unhide more of this class
  */
 public final class BluetoothDevice implements Parcelable {
     private static final String TAG = "BluetoothDevice";
 
-    /** We do not have a link key for the remote device, and are therefore not
-     * bonded
-     * @hide*/
-    public static final int BOND_NOT_BONDED = 0;
-    /** We have a link key for the remote device, and are probably bonded.
-     *  @hide */
-    public static final int BOND_BONDED = 1;
-    /** We are currently attempting bonding
-     *  @hide */
-    public static final int BOND_BONDING = 2;
+    /**
+     * Sentinel error value for this class. Guaranteed to not equal any other
+     * integer constant in this class. Provided as a convenience for functions
+     * that require a sentinel error value, for example:
+     * <p><code>Intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
+     * BluetoothDevice.ERROR)</code>
+     */
+    public static final int ERROR = Integer.MIN_VALUE;
 
-    /** Ask device picker to show all kinds of BT devices.
-     *  @hide */
-    public static final int DEVICE_PICKER_FILTER_TYPE_ALL = 0;
-    /** Ask device picker to show BT devices that support AUDIO profiles.
-     *  @hide */
-    public static final int DEVICE_PICKER_FILTER_TYPE_AUDIO = 1;
-    /** Ask device picker to show BT devices that support Object Transfer.
-     *  @hide */
-    public static final int DEVICE_PICKER_FILTER_TYPE_TRANSFER = 2;
+    /**
+     * Broadcast Action: Remote device discovered.
+     * <p>Sent when a remote device is found during discovery.
+     * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
+     * #EXTRA_CLASS}. Can contain the extra fields {@link #EXTRA_NAME} and/or
+     * {@link #EXTRA_RSSI} if they are available.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
+     */
+     // TODO: Change API to not broadcast RSSI if not available (incoming connection)
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_FOUND =
+            "android.bluetooth.device.action.FOUND";
 
-    //TODO: Unify these result codes in BluetoothResult or BluetoothError
+    /**
+     * Broadcast Action: Remote device disappeared.
+     * <p>Sent when a remote device that was found in the last discovery is not
+     * found in the current discovery.
+     * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_DISAPPEARED =
+            "android.bluetooth.device.action.DISAPPEARED";
+
+    /**
+     * Broadcast Action: Bluetooth class of a remote device has changed.
+     * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
+     * #EXTRA_CLASS}.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
+     * @see {@link BluetoothClass}
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_CLASS_CHANGED =
+            "android.bluetooth.device.action.CLASS_CHANGED";
+
+    /**
+     * Broadcast Action: Indicates a low level (ACL) connection has been
+     * established with a remote device.
+     * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
+     * <p>ACL connections are managed automatically by the Android Bluetooth
+     * stack.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_ACL_CONNECTED =
+            "android.bluetooth.device.action.ACL_CONNECTED";
+
+    /**
+     * Broadcast Action: Indicates that a low level (ACL) disconnection has
+     * been requested for a remote device, and it will soon be disconnected.
+     * <p>This is useful for graceful disconnection. Applications should use
+     * this intent as a hint to immediately terminate higher level connections
+     * (RFCOMM, L2CAP, or profile connections) to the remote device.
+     * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_ACL_DISCONNECT_REQUESTED =
+            "android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED";
+
+    /**
+     * Broadcast Action: Indicates a low level (ACL) disconnection from a
+     * remote device.
+     * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
+     * <p>ACL connections are managed automatically by the Android Bluetooth
+     * stack.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_ACL_DISCONNECTED =
+            "android.bluetooth.device.action.ACL_DISCONNECTED";
+
+    /**
+     * Broadcast Action: Indicates the friendly name of a remote device has
+     * been retrieved for the first time, or changed since the last retrieval.
+     * <p>Always contains the extra fields {@link #EXTRA_DEVICE} and {@link
+     * #EXTRA_NAME}.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_NAME_CHANGED =
+            "android.bluetooth.device.action.NAME_CHANGED";
+
+    /**
+     * Broadcast Action: Indicates a change in the bond state of a remote
+     * device. For example, if a device is bonded (paired).
+     * <p>Always contains the extra fields {@link #EXTRA_DEVICE}, {@link
+     * #EXTRA_BOND_STATE} and {@link #EXTRA_PREVIOUS_BOND_STATE}.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
+     */
+    // Note: When EXTRA_BOND_STATE is BOND_NONE then this will also
+    // contain a hidden extra field EXTRA_REASON with the result code.
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_BOND_STATE_CHANGED =
+            "android.bluetooth.device.action.BOND_STATE_CHANGED";
+
+    /**
+     * Used as a Parcelable {@link BluetoothDevice} extra field in every intent
+     * broadcast by this class. It contains the {@link BluetoothDevice} that
+     * the intent applies to.
+     */
+    public static final String EXTRA_DEVICE = "android.bluetooth.device.extra.DEVICE";
+
+    /**
+     * Used as a String extra field in {@link #ACTION_NAME_CHANGED} and {@link
+     * #ACTION_FOUND} intents. It contains the friendly Bluetooth name.
+     */
+    public static final String EXTRA_NAME = "android.bluetooth.device.extra.NAME";
+
+    /**
+     * Used as an optional short extra field in {@link #ACTION_FOUND} intents.
+     * Contains the RSSI value of the remote device as reported by the
+     * Bluetooth hardware.
+     */
+    public static final String EXTRA_RSSI = "android.bluetooth.device.extra.RSSI";
+
+    /**
+     * Used as an Parcelable {@link BluetoothClass} extra field in {@link
+     * #ACTION_FOUND} and {@link #ACTION_CLASS_CHANGED} intents.
+     */
+    public static final String EXTRA_CLASS = "android.bluetooth.device.extra.CLASS";
+
+    /**
+     * Used as an int extra field in {@link #ACTION_BOND_STATE_CHANGED} intents.
+     * Contains the bond state of the remote device.
+     * <p>Possible values are:
+     * {@link #BOND_NONE},
+     * {@link #BOND_BONDING},
+     * {@link #BOND_BONDED}.
+      */
+    public static final String EXTRA_BOND_STATE = "android.bluetooth.device.extra.BOND_STATE";
+    /**
+     * Used as an int extra field in {@link #ACTION_BOND_STATE_CHANGED} intents.
+     * Contains the previous bond state of the remote device.
+     * <p>Possible values are:
+     * {@link #BOND_NONE},
+     * {@link #BOND_BONDING},
+     * {@link #BOND_BONDED}.
+      */
+    public static final String EXTRA_PREVIOUS_BOND_STATE =
+            "android.bluetooth.device.extra.PREVIOUS_BOND_STATE";
+    /**
+     * Indicates the remote device is not bonded (paired).
+     * <p>There is no shared link key with the remote device, so communication
+     * (if it is allowed at all) will be unauthenticated and unencrypted.
+     */
+    public static final int BOND_NONE = 10;
+    /**
+     * Indicates bonding (pairing) is in progress with the remote device.
+     */
+    public static final int BOND_BONDING = 11;
+    /**
+     * Indicates the remote device is bonded (paired).
+     * <p>A shared link keys exists locally for the remote device, so
+     * communication can be authenticated and encrypted.
+     * <p><i>Being bonded (paired) with a remote device does not necessarily
+     * mean the device is currently connected. It just means that the ponding
+     * procedure was compeleted at some earlier time, and the link key is still
+     * stored locally, ready to use on the next connection.
+     * </i>
+     */
+    public static final int BOND_BONDED = 12;
+
+    /** @hide */
+    public static final String EXTRA_REASON = "android.bluetooth.device.extra.REASON";
+    /** @hide */
+    public static final String EXTRA_PAIRING_VARIANT =
+            "android.bluetooth.device.extra.PAIRING_VARIANT";
+    /** @hide */
+    public static final String EXTRA_PASSKEY = "android.bluetooth.device.extra.PASSKEY";
+
+    /**
+     * Broadcast Action: Indicates a failure to retrieve the name of a remote
+     * device.
+     * <p>Always contains the extra field {@link #EXTRA_DEVICE}.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
+     * @hide
+     */
+    //TODO: is this actually useful?
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_NAME_FAILED =
+            "android.bluetooth.device.action.NAME_FAILED";
+
+    /** @hide */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_PAIRING_REQUEST =
+            "android.bluetooth.device.action.PAIRING_REQUEST";
+    /** @hide */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_PAIRING_CANCEL =
+            "android.bluetooth.device.action.PAIRING_CANCEL";
+
+    /** A bond attempt succeeded
+     * @hide */
+    public static final int BOND_SUCCESS = 0;
     /** A bond attempt failed because pins did not match, or remote device did
-     * not respond to pin request in time 
+     * not respond to pin request in time
      * @hide */
     public static final int UNBOND_REASON_AUTH_FAILED = 1;
     /** A bond attempt failed because the other side explicilty rejected
@@ -83,11 +266,16 @@
     /** A bond attempt failed because a discovery is in progress
      * @hide */
     public static final int UNBOND_REASON_DISCOVERY_IN_PROGRESS = 5;
+    /** A bond attempt failed because of authentication timeout
+     * @hide */
+    public static final int UNBOND_REASON_AUTH_TIMEOUT = 6;
+    /** A bond attempt failed because of repeated attempts
+     * @hide */
+    public static final int UNBOND_REASON_REPEATED_ATTEMPTS = 7;
     /** An existing bond was explicitly revoked
      * @hide */
-    public static final int UNBOND_REASON_REMOVED = 6;
+    public static final int UNBOND_REASON_REMOVED = 8;
 
-    //TODO: Remove duplicates between here and BluetoothAdapter
     /** The user will be prompted to enter a pin
      * @hide */
     public static final int PAIRING_VARIANT_PIN = 0;
@@ -96,9 +284,13 @@
     public static final int PAIRING_VARIANT_PASSKEY = 1;
     /** The user will be prompted to confirm the passkey displayed on the screen
      * @hide */
-    public static final int PAIRING_VARIANT_CONFIRMATION = 2;
-
-    private static final int ADDRESS_LENGTH = 17;
+    public static final int PAIRING_VARIANT_PASSKEY_CONFIRMATION = 2;
+    /** The user will be prompted to accept or deny the incoming pairing request
+     * @hide */
+    public static final int PAIRING_VARIANT_CONSENT = 3;
+    /** The user will be prompted to enter the passkey displayed on remote device
+     * @hide */
+    public static final int PAIRING_VARIANT_DISPLAY_PASSKEY = 4;
 
     private static IBluetooth sService;  /* Guarenteed constant after first object constructed */
 
@@ -124,7 +316,7 @@
             }
         }
 
-        if (!checkBluetoothAddress(address)) {
+        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
             throw new IllegalArgumentException(address + " is not a valid Bluetooth address");
         }
 
@@ -193,9 +385,9 @@
      * <p>The local adapter will automatically retrieve remote names when
      * performing a device scan, and will cache them. This method just returns
      * the name for this device from the cache.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
      *
      * @return the Bluetooth name, or null if there was a problem.
-     * @hide
      */
     public String getName() {
         try {
@@ -205,15 +397,15 @@
     }
 
     /**
-     * Create a bonding with a remote bluetooth device.
+     * Start the bonding (pairing) process with the remote device.
+     * <p>This is an asynchronous call, it will return immediately. Register
+     * for {@link #ACTION_BOND_STATE_CHANGED} intents to be notified when
+     * the bonding process completes, and its result.
+     * <p>Android system services will handle the necessary user interactions
+     * to confirm and complete the bonding process.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
      *
-     * This is an asynchronous call. The result of this bonding attempt can be
-     * observed through BluetoothIntent.BOND_STATE_CHANGED_ACTION intents.
-     *
-     * @param address the remote device Bluetooth address.
-     * @return false If there was an immediate problem creating the bonding,
-     *         true otherwise.
-     * @hide
+     * @return false on immediate error, true if bonding will begin
      */
     public boolean createBond() {
         try {
@@ -223,8 +415,10 @@
     }
 
     /**
-     * Cancel an in-progress bonding request started with createBond.
-     * @hide
+     * Cancel an in-progress bonding request started with {@link #createBond}.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
+     *
+     * @return true on sucess, false on error
      */
     public boolean cancelBondProcess() {
         try {
@@ -234,12 +428,13 @@
     }
 
     /**
-     * Removes the remote device and the pairing information associated
-     * with it.
+     * Remove bond (pairing) with the remote device.
+     * <p>Delete the link key associated with the remote device, and
+     * immediately terminate connections to that device that require
+     * authentication and encryption.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN}.
      *
-     * @return true if the device was disconnected, false otherwise and on
-     *         error.
-     * @hide
+     * @return true on sucess, false on error
      */
     public boolean removeBond() {
         try {
@@ -249,21 +444,35 @@
     }
 
     /**
-     * Get the bonding state of a remote device.
+     * Get the bond state of the remote device.
+     * <p>Possible values for the bond state are:
+     * {@link #BOND_NONE},
+     * {@link #BOND_BONDING},
+     * {@link #BOND_BONDED}.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
      *
-     * Result is one of:
-     * BluetoothError.*
-     * BOND_*
-     *
-     * @param address Bluetooth hardware address of the remote device to check.
-     * @return Result code
-     * @hide
+     * @return the bond state
      */
     public int getBondState() {
         try {
             return sService.getBondState(mAddress);
         } catch (RemoteException e) {Log.e(TAG, "", e);}
-        return BluetoothError.ERROR_IPC;
+        return BOND_NONE;
+    }
+
+    /**
+     * Get the Bluetooth class of the remote device.
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH}.
+     *
+     * @return Bluetooth class object, or null on error
+     */
+    public BluetoothClass getBluetoothClass() {
+        try {
+            int classInt = sService.getRemoteClass(mAddress);
+            if (classInt == BluetoothClass.ERROR) return null;
+            return new BluetoothClass(classInt);
+        } catch (RemoteException e) {Log.e(TAG, "", e);}
+        return null;
     }
 
     /**
@@ -294,14 +503,6 @@
     }
 
     /** @hide */
-    public int getBluetoothClass() {
-        try {
-            return sService.getRemoteClass(mAddress);
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
-        return BluetoothError.ERROR_IPC;
-    }
-
-    /** @hide */
      public String[] getUuids() {
         try {
             return sService.getRemoteUuids(mAddress);
@@ -314,7 +515,7 @@
          try {
              return sService.getRemoteServiceChannel(mAddress, uuid);
          } catch (RemoteException e) {Log.e(TAG, "", e);}
-         return BluetoothError.ERROR_IPC;
+         return BluetoothDevice.ERROR;
     }
 
     /** @hide */
@@ -358,6 +559,7 @@
      * connection.
      * <p>Valid RFCOMM channels are in range 1 to 30.
      * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
+     *
      * @param channel RFCOMM channel to connect to
      * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
      * @throws IOException on error, for example Bluetooth not available, or
@@ -421,28 +623,4 @@
         return pinBytes;
     }
 
-    /** Sanity check a bluetooth address, such as "00:43:A8:23:10:F0"
-     * @hide */
-    public static boolean checkBluetoothAddress(String address) {
-        if (address == null || address.length() != ADDRESS_LENGTH) {
-            return false;
-        }
-        for (int i = 0; i < ADDRESS_LENGTH; i++) {
-            char c = address.charAt(i);
-            switch (i % 3) {
-            case 0:
-            case 1:
-                if (Character.digit(c, 16) != -1) {
-                    break;  // hex character, OK
-                }
-                return false;
-            case 2:
-                if (c == ':') {
-                    break;  // OK
-                }
-                return false;
-            }
-        }
-        return true;
-    }
 }
diff --git a/core/java/android/bluetooth/BluetoothDevicePicker.java b/core/java/android/bluetooth/BluetoothDevicePicker.java
new file mode 100644
index 0000000..05eed0e
--- /dev/null
+++ b/core/java/android/bluetooth/BluetoothDevicePicker.java
@@ -0,0 +1,66 @@
+/*
+ * 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.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+
+/**
+ * A helper to show a system "Device Picker" activity to the user.
+ *
+ * @hide
+ */
+public interface BluetoothDevicePicker {
+    public static final String EXTRA_NEED_AUTH =
+            "android.bluetooth.devicepicker.extra.NEED_AUTH";
+    public static final String EXTRA_FILTER_TYPE =
+            "android.bluetooth.devicepicker.extra.FILTER_TYPE";
+    public static final String EXTRA_LAUNCH_PACKAGE =
+            "android.bluetooth.devicepicker.extra.LAUNCH_PACKAGE";
+    public static final String EXTRA_LAUNCH_CLASS =
+            "android.bluetooth.devicepicker.extra.DEVICE_PICKER_LAUNCH_CLASS";
+
+    /**
+     * Broadcast when one BT device is selected from BT device picker screen.
+     * Selected BT device address is contained in extra string {@link BluetoothIntent}
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_DEVICE_SELECTED =
+            "android.bluetooth.devicepicker.action.DEVICE_SELECTED";
+
+    /**
+     * Broadcast when someone want to select one BT device from devices list.
+     * This intent contains below extra data:
+     * - {@link #EXTRA_NEED_AUTH} (boolean): if need authentication
+     * - {@link #EXTRA_FILTER_TYPE} (int): what kinds of device should be
+     *                                     listed
+     * - {@link #EXTRA_LAUNCH_PACKAGE} (string): where(which package) this
+     *                                           intent come from
+     * - {@link #EXTRA_LAUNCH_CLASS} (string): where(which class) this intent
+     *                                         come from
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_LAUNCH =
+            "android.bluetooth.devicepicker.action.LAUNCH";
+
+    /** Ask device picker to show all kinds of BT devices */
+    public static final int FILTER_TYPE_ALL = 0;
+    /** Ask device picker to show BT devices that support AUDIO profiles */
+    public static final int FILTER_TYPE_AUDIO = 1;
+    /** Ask device picker to show BT devices that support Object Transfer */
+    public static final int FILTER_TYPE_TRANSFER = 2;
+}
diff --git a/core/java/android/bluetooth/BluetoothError.java b/core/java/android/bluetooth/BluetoothError.java
deleted file mode 100644
index 2554bea..0000000
--- a/core/java/android/bluetooth/BluetoothError.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-/**
- * Bluetooth API error codes.
- *
- * Errors are always negative.
- *
- * @hide
- */
-public class BluetoothError {
-    /** No error */
-    public static final int SUCCESS = 0;
-
-    /** Generic error */
-    public static final int ERROR = -1000;
-
-    /** Bluetooth currently disabled */
-    public static final int ERROR_DISABLED = -1001;
-
-    /** IPC is not ready, for example service is not yet bound */
-    public static final int ERROR_IPC_NOT_READY = -1011;
-
-    /** Some other IPC error, for example a RemoteException */
-    public static final int ERROR_IPC = -1012;
-
-}
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index d31b6ae..90cff6b 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -16,6 +16,8 @@
 
 package android.bluetooth;
 
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -54,6 +56,27 @@
     private static final String TAG = "BluetoothHeadset";
     private static final boolean DBG = false;
 
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_STATE_CHANGED =
+            "android.bluetooth.headset.action.STATE_CHANGED";
+    /**
+     * TODO(API release): Consider incorporating as new state in
+     * HEADSET_STATE_CHANGED
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_AUDIO_STATE_CHANGED =
+            "android.bluetooth.headset.action.AUDIO_STATE_CHANGED";
+    public static final String EXTRA_STATE =
+            "android.bluetooth.headset.extra.STATE";
+    public static final String EXTRA_PREVIOUS_STATE =
+            "android.bluetooth.headset.extra.PREVIOUS_STATE";
+    public static final String EXTRA_AUDIO_STATE =
+            "android.bluetooth.headset.extra.AUDIO_STATE";
+
+    /**
+     * TODO(API release): Consider incorporating as new state in
+     * HEADSET_STATE_CHANGED
+     */
     private IBluetoothHeadset mService;
     private final Context mContext;
     private final ServiceListener mServiceListener;
diff --git a/core/java/android/bluetooth/BluetoothIntent.java b/core/java/android/bluetooth/BluetoothIntent.java
deleted file mode 100644
index c39bc3d..0000000
--- a/core/java/android/bluetooth/BluetoothIntent.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.bluetooth;
-
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-
-/**
- * The Android Bluetooth API is not finalized, and *will* change. Use at your
- * own risk.
- *
- * Manages the local Bluetooth device. Scan for devices, create bondings,
- * power up and down the adapter.
- *
- * @hide
- */
-public interface BluetoothIntent {
-    public static final String SCAN_MODE =
-        "android.bluetooth.intent.SCAN_MODE";
-    public static final String DEVICE =
-        "android.bluetooth.intent.DEVICE";
-    public static final String NAME =
-        "android.bluetooth.intent.NAME";
-    public static final String ALIAS =
-        "android.bluetooth.intent.ALIAS";
-    public static final String RSSI =
-        "android.bluetooth.intent.RSSI";
-    public static final String CLASS =
-        "android.bluetooth.intent.CLASS";
-    public static final String BLUETOOTH_STATE =
-        "android.bluetooth.intent.BLUETOOTH_STATE";
-    public static final String BLUETOOTH_PREVIOUS_STATE =
-        "android.bluetooth.intent.BLUETOOTH_PREVIOUS_STATE";
-    public static final String HEADSET_STATE =
-        "android.bluetooth.intent.HEADSET_STATE";
-    public static final String HEADSET_PREVIOUS_STATE =
-        "android.bluetooth.intent.HEADSET_PREVIOUS_STATE";
-    public static final String HEADSET_AUDIO_STATE =
-        "android.bluetooth.intent.HEADSET_AUDIO_STATE";
-    public static final String BOND_STATE =
-        "android.bluetooth.intent.BOND_STATE";
-    public static final String BOND_PREVIOUS_STATE =
-        "android.bluetooth.intent.BOND_PREVIOUS_STATE";
-    public static final String REASON =
-        "android.bluetooth.intent.REASON";
-    public static final String PAIRING_VARIANT =
-        "android.bluetooth.intent.PAIRING_VARIANT";
-    public static final String PASSKEY =
-        "android.bluetooth.intent.PASSKEY";
-
-    public static final String DEVICE_PICKER_NEED_AUTH =
-        "android.bluetooth.intent.DEVICE_PICKER_NEED_AUTH";
-    public static final String DEVICE_PICKER_FILTER_TYPE =
-        "android.bluetooth.intent.DEVICE_PICKER_FILTER_TYPE";
-    public static final String DEVICE_PICKER_LAUNCH_PACKAGE =
-        "android.bluetooth.intent.DEVICE_PICKER_LAUNCH_PACKAGE";
-    public static final String DEVICE_PICKER_LAUNCH_CLASS =
-        "android.bluetooth.intent.DEVICE_PICKER_LAUNCH_CLASS";
-
-     /**
-     * Broadcast when one BT device is selected from BT device picker screen.
-     * Selected BT device address is contained in extra string "BluetoothIntent.ADDRESS".
-     */
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String DEVICE_PICKER_DEVICE_SELECTED =
-        "android.bluetooth.intent.action.DEVICE_SELECTED";
-
-    /**
-     * Broadcast when someone want to select one BT device from devices list.
-     * This intent contains below extra data:
-     * - BluetoothIntent.DEVICE_PICKER_NEED_AUTH (boolean): if need authentication
-     * - BluetoothIntent.DEVICE_PICKER_FILTER_TYPE (int): what kinds of device should be listed
-     * - BluetoothIntent.DEVICE_PICKER_LAUNCH_PACKAGE (string): where(which package) this intent come from
-     * - BluetoothIntent.DEVICE_PICKER_LAUNCH_CLASS (string): where(which class) this intent come from
-     */
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String DEVICE_PICKER_DEVICE_PICKER =
-        "android.bluetooth.intent.action.DEVICE_PICKER";
-
-    /** Broadcast when the local Bluetooth device state changes, for example
-     *  when Bluetooth is enabled. Will contain int extra's BLUETOOTH_STATE and
-     *  BLUETOOTH_PREVIOUS_STATE. */
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String BLUETOOTH_STATE_CHANGED_ACTION =
-        "android.bluetooth.intent.action.BLUETOOTH_STATE_CHANGED";
-
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String NAME_CHANGED_ACTION  =
-        "android.bluetooth.intent.action.NAME_CHANGED";
-
-    /**
-     * Broadcast when the scan mode changes. Always contains an int extra
-     * named SCAN_MODE that contains the new scan mode.
-     */
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String SCAN_MODE_CHANGED_ACTION         =
-        "android.bluetooth.intent.action.SCAN_MODE_CHANGED";
-
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String DISCOVERY_STARTED_ACTION          =
-        "android.bluetooth.intent.action.DISCOVERY_STARTED";
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String DISCOVERY_COMPLETED_ACTION        =
-        "android.bluetooth.intent.action.DISCOVERY_COMPLETED";
-
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String PAIRING_REQUEST_ACTION            =
-        "android.bluetooth.intent.action.PAIRING_REQUEST";
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String PAIRING_CANCEL_ACTION             =
-        "android.bluetooth.intent.action.PAIRING_CANCEL";
-
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String REMOTE_DEVICE_FOUND_ACTION        =
-        "android.bluetooth.intent.action.REMOTE_DEVICE_FOUND";
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String REMOTE_DEVICE_DISAPPEARED_ACTION  =
-        "android.bluetooth.intent.action.REMOTE_DEVICE_DISAPPEARED";
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String REMOTE_DEVICE_CLASS_UPDATED_ACTION  =
-        "android.bluetooth.intent.action.REMOTE_DEVICE_DISAPPEARED";
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String REMOTE_DEVICE_CONNECTED_ACTION    =
-        "android.bluetooth.intent.action.REMOTE_DEVICE_CONNECTED";
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String REMOTE_DEVICE_DISCONNECT_REQUESTED_ACTION =
-        "android.bluetooth.intent.action.REMOTE_DEVICE_DISCONNECT_REQUESTED";
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String REMOTE_DEVICE_DISCONNECTED_ACTION =
-        "android.bluetooth.intent.action.REMOTE_DEVICE_DISCONNECTED";
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String REMOTE_NAME_UPDATED_ACTION        =
-        "android.bluetooth.intent.action.REMOTE_NAME_UPDATED";
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String REMOTE_NAME_FAILED_ACTION         =
-        "android.bluetooth.intent.action.REMOTE_NAME_FAILED";
-
-    /**
-     * Broadcast when the bond state of a remote device changes.
-     * Has string extra ADDRESS and int extras BOND_STATE and
-     * BOND_PREVIOUS_STATE.
-     * If BOND_STATE is BluetoothDevice.BOND_NOT_BONDED then will
-     * also have an int extra REASON with a value of:
-     * BluetoothDevice.BOND_RESULT_*
-     * */
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String BOND_STATE_CHANGED_ACTION      =
-        "android.bluetooth.intent.action.BOND_STATE_CHANGED_ACTION";
-
-    /**
-     * TODO(API release): Move into BluetoothHeadset
-     */
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String HEADSET_STATE_CHANGED_ACTION      =
-        "android.bluetooth.intent.action.HEADSET_STATE_CHANGED";
-
-    /**
-     * TODO(API release): Consider incorporating as new state in
-     * HEADSET_STATE_CHANGED
-     */
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String HEADSET_AUDIO_STATE_CHANGED_ACTION =
-        "android.bluetooth.intent.action.HEADSET_ADUIO_STATE_CHANGED";
-}
diff --git a/core/java/android/bluetooth/BluetoothPbap.java b/core/java/android/bluetooth/BluetoothPbap.java
index 645e241..b48f48e 100644
--- a/core/java/android/bluetooth/BluetoothPbap.java
+++ b/core/java/android/bluetooth/BluetoothPbap.java
@@ -221,9 +221,9 @@
      * devices. It tries to err on the side of false positives.
      * @return True if this device might support PBAP.
      */
-    public static boolean doesClassMatchSink(int btClass) {
+    public static boolean doesClassMatchSink(BluetoothClass btClass) {
         // TODO optimize the rule
-        switch (BluetoothClass.Device.getDevice(btClass)) {
+        switch (btClass.getDeviceClass()) {
         case BluetoothClass.Device.COMPUTER_DESKTOP:
         case BluetoothClass.Device.COMPUTER_LAPTOP:
         case BluetoothClass.Device.COMPUTER_SERVER:
diff --git a/core/java/android/bluetooth/IBluetoothA2dp.aidl b/core/java/android/bluetooth/IBluetoothA2dp.aidl
index e6c6be2..2df7f23 100644
--- a/core/java/android/bluetooth/IBluetoothA2dp.aidl
+++ b/core/java/android/bluetooth/IBluetoothA2dp.aidl
@@ -24,10 +24,10 @@
  * {@hide}
  */
 interface IBluetoothA2dp {
-    int connectSink(in BluetoothDevice device);
-    int disconnectSink(in BluetoothDevice device);
+    boolean connectSink(in BluetoothDevice device);
+    boolean disconnectSink(in BluetoothDevice device);
     BluetoothDevice[] getConnectedSinks();  // change to Set<> once AIDL supports
     int getSinkState(in BluetoothDevice device);
-    int setSinkPriority(in BluetoothDevice device, int priority);
+    boolean setSinkPriority(in BluetoothDevice device, int priority);
     int getSinkPriority(in BluetoothDevice device);
 }
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 0bc8a9d..0d43b2a 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -24,7 +24,6 @@
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.Locale;
 
 /**
  * Provides access to an application's raw asset files; see {@link Resources}
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 7d412a7..ba5c9ed 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -66,8 +66,6 @@
             = new SparseArray<ColorStateList>();
     private static boolean mPreloaded;
 
-    private final LongSparseArray<Drawable.ConstantState> mPreloadedDrawables;
-
     /*package*/ final TypedValue mTmpValue = new TypedValue();
 
     // These are protected by the mTmpValue lock.
@@ -158,11 +156,6 @@
         }
         updateConfiguration(config, metrics);
         assets.ensureStringBlocks();
-        if (mCompatibilityInfo.isScalingRequired()) {
-            mPreloadedDrawables = emptySparseArray();
-        } else {
-            mPreloadedDrawables = sPreloadedDrawables;
-        }
     }
 
     /**
@@ -1669,7 +1662,7 @@
             return dr;
         }
 
-        Drawable.ConstantState cs = mPreloadedDrawables.get(key);
+        Drawable.ConstantState cs = sPreloadedDrawables.get(key);
         if (cs != null) {
             dr = cs.newDrawable();
         } else {
@@ -1976,7 +1969,6 @@
         mMetrics.setToDefaults();
         updateConfiguration(null, null);
         mAssets.ensureStringBlocks();
-        mPreloadedDrawables = sPreloadedDrawables;
         mCompatibilityInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
     }
 }
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 4f31ef0..0cd4036 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -194,7 +194,7 @@
     private static final int LOCK_ACQUIRED_WARNING_THREAD_TIME_IN_MS = 100;
     private static final int LOCK_ACQUIRED_WARNING_TIME_IN_MS_ALWAYS_PRINT = 2000;
 
-    private static final int SLEEP_AFTER_YIELD_QUANTUM = 500;
+    private static final int SLEEP_AFTER_YIELD_QUANTUM = 1000;
 
     private long mLastLockMessageTime = 0L;
 
diff --git a/core/java/android/gesture/GestureOverlayView.java b/core/java/android/gesture/GestureOverlayView.java
index 5bfdcc4..30ecf5a 100755
--- a/core/java/android/gesture/GestureOverlayView.java
+++ b/core/java/android/gesture/GestureOverlayView.java
@@ -29,6 +29,7 @@
 import android.view.animation.AccelerateDecelerateInterpolator;
 import android.widget.FrameLayout;
 import android.os.SystemClock;
+import android.annotation.Widget;
 import com.android.internal.R;
 
 import java.util.ArrayList;
@@ -50,6 +51,7 @@
  * @attr ref android.R.styleable#GestureOverlayView_orientation
  * @attr ref android.R.styleable#GestureOverlayView_uncertainGestureColor
  */
+@Widget
 public class GestureOverlayView extends FrameLayout {
     public static final int GESTURE_STROKE_TYPE_SINGLE = 0;
     public static final int GESTURE_STROKE_TYPE_MULTIPLE = 1;
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 38c9dbc..04daa1c 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -37,6 +37,23 @@
  * frames for encoding for video.
  * <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 
+ * 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 
+ * should include the following:</p>
+ * <pre> &lt;uses-permission android:name="android.permission.CAMERA" />
+ * &lt;uses-feature android:name="android.hardware.camera" />
+ * &lt;uses-feature android:name="android.hardware.camera.autofocus" /></pre>
+ *
+ * <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 
+ * specifications.</p>
  */
 public class Camera {
     private static final String TAG = "Camera";
@@ -179,10 +196,10 @@
         /**
          * The callback that delivers the preview frames.
          *
-         * @param data The contents of the preview frame in {@link
-         *             android.hardware.Camera.Parameters#getPreviewFormat()}
-         *             format. If {@link
-         *             android.hardware.Camera.Parameters#setPreviewFormat(int)}
+         * @param data The contents of the preview frame in the format defined
+         *  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
          *             (NV21) format.
          * @param camera The Camera service object.
@@ -323,6 +340,13 @@
 
     /**
      * 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 
+     * 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 
+     * <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">&lt;uses-feature></a>
+     * manifest element.</p>
      */
     public interface AutoFocusCallback
     {
@@ -343,7 +367,12 @@
      * the camera does not support auto-focus, it is a no-op and {@link
      * AutoFocusCallback#onAutoFocus(boolean, Camera)} callback will be called
      * immediately.
-     *
+     * <p>If your application should not be installed
+     * on devices without auto-focus, you must declare that your application 
+     * uses auto-focus with the 
+     * <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)
@@ -874,11 +903,14 @@
         }
 
         /**
-         * Sets the image format for preview pictures. If this is never called,
-         * the default will be the YCbCr_420_SP (NV21) format.
-         *
-         * @param pixel_format the desired preview picture format
-         *                     (<var>PixelFormat.YCbCr_420_SP (NV21)</var>,
+         * 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),
          *                      <var>PixelFormat.RGB_565</var>, or
          *                      <var>PixelFormat.JPEG</var>)
          * @see android.graphics.PixelFormat
@@ -896,9 +928,9 @@
         /**
          * Returns the image format for preview pictures got from
          * {@link PreviewCallback}.
-         *
-         * @return the PixelFormat int representing the preview picture format
-         * @see android.graphics.PixelFormat
+         * 
+         * @return the {@link android.graphics.PixelFormat} int representing 
+         *         the preview picture format.
          */
         public int getPreviewFormat() {
             return pixelFormatForCameraFormat(get(KEY_PREVIEW_FORMAT));
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index f88fcdc..d8db4c1 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -145,12 +145,14 @@
                     if (DBG) Log.d(TAG, mApnType + " Received " + intent.getAction() +
                             " broadcast - state = " + state + ", oldstate = " + mMobileDataState +
                             ", unavailable = " + unavailable + ", reason = " +
-                            (reason == null ? "(unspecified)" : reason));
+                            (reason == null ? "(unspecified)" : reason) +
+                            ", apnTypeList = " + apnTypeList);
 
+                    // set this regardless of the apnTypeList.  It's all the same radio/network
+                    // underneath
+                    mNetworkInfo.setIsAvailable(!unavailable);
 
                     if (isApnTypeIncluded(apnTypeList)) {
-                        // set this even if the apn isn't Enabled
-                        mNetworkInfo.setIsAvailable(!unavailable);
                         if (mEnabled == false) {
                             // if we're not enabled but the APN Type is supported by this connection
                             // we should record the interface name if one's provided.  If the user
diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java
index 9f53937..649cb8c 100644
--- a/core/java/android/net/NetworkInfo.java
+++ b/core/java/android/net/NetworkInfo.java
@@ -131,7 +131,7 @@
         mSubtypeName = subtypeName;
         setDetailedState(DetailedState.IDLE, null, null);
         mState = State.UNKNOWN;
-        mIsAvailable = true;
+        mIsAvailable = false; // until we're told otherwise, assume unavailable
         mIsRoaming = false;
     }
 
diff --git a/core/java/android/os/PerformanceCollector.java b/core/java/android/os/PerformanceCollector.java
new file mode 100644
index 0000000..4ca1f32
--- /dev/null
+++ b/core/java/android/os/PerformanceCollector.java
@@ -0,0 +1,524 @@
+/*
+ * 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.os;
+
+
+import java.util.ArrayList;
+
+/**
+ * Collects performance data between two function calls in Bundle objects and
+ * outputs the results using writer of type {@link PerformanceResultsWriter}.
+ * <p>
+ * {@link #beginSnapshot(String)} and {@link #endSnapshot()} functions collect
+ * memory usage information and measure runtime between calls to begin and end.
+ * These functions logically wrap around an entire test, and should be called
+ * with name of test as the label, e.g. EmailPerformanceTest.
+ * <p>
+ * {@link #startTiming(String)} and {@link #stopTiming(String)} functions
+ * measure runtime between calls to start and stop. These functions logically
+ * wrap around a single test case or a small block of code, and should be called
+ * with the name of test case as the label, e.g. testSimpleSendMailSequence.
+ * <p>
+ * {@link #addIteration(String)} inserts intermediate measurement point which
+ * can be labeled with a String, e.g. Launch email app, compose, send, etc.
+ * <p>
+ * Snapshot and timing functions do not interfere with each other, and thus can
+ * be called in any order. The intended structure is to wrap begin/endSnapshot
+ * around calls to start/stopTiming, for example:
+ * <p>
+ * <code>beginSnapshot("EmailPerformanceTest");
+ * startTiming("testSimpleSendSequence");
+ * addIteration("Launch email app");
+ * addIteration("Compose");
+ * stopTiming("Send");
+ * startTiming("testComplexSendSequence");
+ * stopTiming("");
+ * startTiming("testAddLabel");
+ * stopTiming("");
+ * endSnapshot();</code>
+ * <p>
+ * Structure of results output is up to implementor of
+ * {@link PerformanceResultsWriter }.
+ *
+ * {@hide} Pending approval for public API.
+ */
+public class PerformanceCollector {
+
+    /**
+     * Interface for reporting performance data.
+     */
+    public interface PerformanceResultsWriter {
+
+        /**
+         * Callback invoked as first action in
+         * PerformanceCollector#beginSnapshot(String) for reporting the start of
+         * a performance snapshot.
+         *
+         * @param label description of code block between beginSnapshot and
+         *              PerformanceCollector#endSnapshot()
+         * @see PerformanceCollector#beginSnapshot(String)
+         */
+        public void writeBeginSnapshot(String label);
+
+        /**
+         * Callback invoked as last action in PerformanceCollector#endSnapshot()
+         * for reporting performance data collected in the snapshot.
+         *
+         * @param results memory and runtime metrics stored as key/value pairs,
+         *        in the same structure as returned by
+         *        PerformanceCollector#endSnapshot()
+         * @see PerformanceCollector#endSnapshot()
+         */
+        public void writeEndSnapshot(Bundle results);
+
+        /**
+         * Callback invoked as first action in
+         * PerformanceCollector#startTiming(String) for reporting the start of
+         * a timing measurement.
+         *
+         * @param label description of code block between startTiming and
+         *              PerformanceCollector#stopTiming(String)
+         * @see PerformanceCollector#startTiming(String)
+         */
+        public void writeStartTiming(String label);
+
+        /**
+         * Callback invoked as last action in
+         * {@link PerformanceCollector#stopTiming(String)} for reporting the
+         * sequence of timings measured.
+         *
+         * @param results runtime metrics of code block between calls to
+         *                startTiming and stopTiming, in the same structure as
+         *                returned by PerformanceCollector#stopTiming(String)
+         * @see PerformanceCollector#stopTiming(String)
+         */
+        public void writeStopTiming(Bundle results);
+    }
+
+    /**
+     * In a results Bundle, this key references a List of iteration Bundles.
+     */
+    public static final String METRIC_KEY_ITERATIONS = "iterations";
+    /**
+     * In an iteration Bundle, this key describes the iteration.
+     */
+    public static final String METRIC_KEY_LABEL = "label";
+    /**
+     * In a results Bundle, this key reports the cpu time of the code block
+     * under measurement.
+     */
+    public static final String METRIC_KEY_CPU_TIME = "cpu_time";
+    /**
+     * In a results Bundle, this key reports the execution time of the code
+     * block under measurement.
+     */
+    public static final String METRIC_KEY_EXECUTION_TIME = "execution_time";
+    /**
+     * In a snapshot Bundle, this key reports the number of received
+     * transactions from the binder driver before collection started.
+     */
+    public static final String METRIC_KEY_PRE_RECEIVED_TRANSACTIONS = "pre_received_transactions";
+    /**
+     * In a snapshot Bundle, this key reports the number of transactions sent by
+     * the running program before collection started.
+     */
+    public static final String METRIC_KEY_PRE_SENT_TRANSACTIONS = "pre_sent_transactions";
+    /**
+     * In a snapshot Bundle, this key reports the number of received
+     * transactions from the binder driver.
+     */
+    public static final String METRIC_KEY_RECEIVED_TRANSACTIONS = "received_transactions";
+    /**
+     * In a snapshot Bundle, this key reports the number of transactions sent by
+     * the running program.
+     */
+    public static final String METRIC_KEY_SENT_TRANSACTIONS = "sent_transactions";
+    /**
+     * In a snapshot Bundle, this key reports the number of garbage collection
+     * invocations.
+     */
+    public static final String METRIC_KEY_GC_INVOCATION_COUNT = "gc_invocation_count";
+    /**
+     * In a snapshot Bundle, this key reports the amount of allocated memory
+     * used by the running program.
+     */
+    public static final String METRIC_KEY_JAVA_ALLOCATED = "java_allocated";
+    /**
+     * In a snapshot Bundle, this key reports the amount of free memory
+     * available to the running program.
+     */
+    public static final String METRIC_KEY_JAVA_FREE = "java_free";
+    /**
+     * In a snapshot Bundle, this key reports the number of private dirty pages
+     * used by dalvik.
+     */
+    public static final String METRIC_KEY_JAVA_PRIVATE_DIRTY = "java_private_dirty";
+    /**
+     * In a snapshot Bundle, this key reports the proportional set size for
+     * dalvik.
+     */
+    public static final String METRIC_KEY_JAVA_PSS = "java_pss";
+    /**
+     * In a snapshot Bundle, this key reports the number of shared dirty pages
+     * used by dalvik.
+     */
+    public static final String METRIC_KEY_JAVA_SHARED_DIRTY = "java_shared_dirty";
+    /**
+     * In a snapshot Bundle, this key reports the total amount of memory
+     * available to the running program.
+     */
+    public static final String METRIC_KEY_JAVA_SIZE = "java_size";
+    /**
+     * In a snapshot Bundle, this key reports the amount of allocated memory in
+     * the native heap.
+     */
+    public static final String METRIC_KEY_NATIVE_ALLOCATED = "native_allocated";
+    /**
+     * In a snapshot Bundle, this key reports the amount of free memory in the
+     * native heap.
+     */
+    public static final String METRIC_KEY_NATIVE_FREE = "native_free";
+    /**
+     * In a snapshot Bundle, this key reports the number of private dirty pages
+     * used by the native heap.
+     */
+    public static final String METRIC_KEY_NATIVE_PRIVATE_DIRTY = "native_private_dirty";
+    /**
+     * In a snapshot Bundle, this key reports the proportional set size for the
+     * native heap.
+     */
+    public static final String METRIC_KEY_NATIVE_PSS = "native_pss";
+    /**
+     * In a snapshot Bundle, this key reports the number of shared dirty pages
+     * used by the native heap.
+     */
+    public static final String METRIC_KEY_NATIVE_SHARED_DIRTY = "native_shared_dirty";
+    /**
+     * In a snapshot Bundle, this key reports the size of the native heap.
+     */
+    public static final String METRIC_KEY_NATIVE_SIZE = "native_size";
+    /**
+     * In a snapshot Bundle, this key reports the number of objects allocated
+     * globally.
+     */
+    public static final String METRIC_KEY_GLOBAL_ALLOC_COUNT = "global_alloc_count";
+    /**
+     * In a snapshot Bundle, this key reports the size of all objects allocated
+     * globally.
+     */
+    public static final String METRIC_KEY_GLOBAL_ALLOC_SIZE = "global_alloc_size";
+    /**
+     * In a snapshot Bundle, this key reports the number of objects freed
+     * globally.
+     */
+    public static final String METRIC_KEY_GLOBAL_FREED_COUNT = "global_freed_count";
+    /**
+     * In a snapshot Bundle, this key reports the size of all objects freed
+     * globally.
+     */
+    public static final String METRIC_KEY_GLOBAL_FREED_SIZE = "global_freed_size";
+    /**
+     * In a snapshot Bundle, this key reports the number of private dirty pages
+     * used by everything else.
+     */
+    public static final String METRIC_KEY_OTHER_PRIVATE_DIRTY = "other_private_dirty";
+    /**
+     * In a snapshot Bundle, this key reports the proportional set size for
+     * everything else.
+     */
+    public static final String METRIC_KEY_OTHER_PSS = "other_pss";
+    /**
+     * In a snapshot Bundle, this key reports the number of shared dirty pages
+     * used by everything else.
+     */
+    public static final String METRIC_KEY_OTHER_SHARED_DIRTY = "other_shared_dirty";
+
+    private PerformanceResultsWriter mPerfWriter;
+    private Bundle mPerfSnapshot;
+    private Bundle mPerfMeasurement;
+    private long mSnapshotCpuTime;
+    private long mSnapshotExecTime;
+    private long mCpuTime;
+    private long mExecTime;
+
+    public PerformanceCollector() {
+    }
+
+    public PerformanceCollector(PerformanceResultsWriter writer) {
+        setPerformanceResultsWriter(writer);
+    }
+
+    public void setPerformanceResultsWriter(PerformanceResultsWriter writer) {
+        mPerfWriter = writer;
+    }
+
+    /**
+     * Begin collection of memory usage information.
+     *
+     * @param label description of code block between beginSnapshot and
+     *              endSnapshot, used to label output
+     */
+    public void beginSnapshot(String label) {
+        if (mPerfWriter != null)
+            mPerfWriter.writeBeginSnapshot(label);
+        startPerformanceSnapshot();
+    }
+
+    /**
+     * End collection of memory usage information. Returns collected data in a
+     * Bundle object.
+     *
+     * @return Memory and runtime metrics stored as key/value pairs. Values are
+     *         of type long, and keys include:
+     *         <ul>
+     *         <li>{@link #METRIC_KEY_CPU_TIME cpu_time}
+     *         <li>{@link #METRIC_KEY_EXECUTION_TIME execution_time}
+     *         <li>{@link #METRIC_KEY_PRE_RECEIVED_TRANSACTIONS
+     *         pre_received_transactions}
+     *         <li>{@link #METRIC_KEY_PRE_SENT_TRANSACTIONS
+     *         pre_sent_transactions}
+     *         <li>{@link #METRIC_KEY_RECEIVED_TRANSACTIONS
+     *         received_transactions}
+     *         <li>{@link #METRIC_KEY_SENT_TRANSACTIONS sent_transactions}
+     *         <li>{@link #METRIC_KEY_GC_INVOCATION_COUNT gc_invocation_count}
+     *         <li>{@link #METRIC_KEY_JAVA_ALLOCATED java_allocated}
+     *         <li>{@link #METRIC_KEY_JAVA_FREE java_free}
+     *         <li>{@link #METRIC_KEY_JAVA_PRIVATE_DIRTY java_private_dirty}
+     *         <li>{@link #METRIC_KEY_JAVA_PSS java_pss}
+     *         <li>{@link #METRIC_KEY_JAVA_SHARED_DIRTY java_shared_dirty}
+     *         <li>{@link #METRIC_KEY_JAVA_SIZE java_size}
+     *         <li>{@link #METRIC_KEY_NATIVE_ALLOCATED native_allocated}
+     *         <li>{@link #METRIC_KEY_NATIVE_FREE native_free}
+     *         <li>{@link #METRIC_KEY_NATIVE_PRIVATE_DIRTY native_private_dirty}
+     *         <li>{@link #METRIC_KEY_NATIVE_PSS native_pss}
+     *         <li>{@link #METRIC_KEY_NATIVE_SHARED_DIRTY native_shared_dirty}
+     *         <li>{@link #METRIC_KEY_NATIVE_SIZE native_size}
+     *         <li>{@link #METRIC_KEY_GLOBAL_ALLOC_COUNT global_alloc_count}
+     *         <li>{@link #METRIC_KEY_GLOBAL_ALLOC_SIZE global_alloc_size}
+     *         <li>{@link #METRIC_KEY_GLOBAL_FREED_COUNT global_freed_count}
+     *         <li>{@link #METRIC_KEY_GLOBAL_FREED_SIZE global_freed_size}
+     *         <li>{@link #METRIC_KEY_OTHER_PRIVATE_DIRTY other_private_dirty}
+     *         <li>{@link #METRIC_KEY_OTHER_PSS other_pss}
+     *         <li>{@link #METRIC_KEY_OTHER_SHARED_DIRTY other_shared_dirty}
+     *         </ul>
+     */
+    public Bundle endSnapshot() {
+        endPerformanceSnapshot();
+        if (mPerfWriter != null)
+            mPerfWriter.writeEndSnapshot(mPerfSnapshot);
+        return mPerfSnapshot;
+    }
+
+    /**
+     * Start measurement of user and cpu time.
+     *
+     * @param label description of code block between startTiming and
+     *        stopTiming, used to label output
+     */
+    public void startTiming(String label) {
+        if (mPerfWriter != null)
+            mPerfWriter.writeStartTiming(label);
+        mPerfMeasurement = new Bundle();
+        mPerfMeasurement.putParcelableArrayList(
+                METRIC_KEY_ITERATIONS, new ArrayList<Parcelable>());
+        mExecTime = SystemClock.uptimeMillis();
+        mCpuTime = Process.getElapsedCpuTime();
+    }
+
+    /**
+     * Add a measured segment, and start measuring the next segment. Returns
+     * collected data in a Bundle object.
+     *
+     * @param label description of code block between startTiming and
+     *              addIteration, and between two calls to addIteration, used
+     *              to label output
+     * @return Runtime metrics stored as key/value pairs. Values are of type
+     *         long, and keys include:
+     *         <ul>
+     *         <li>{@link #METRIC_KEY_LABEL label}
+     *         <li>{@link #METRIC_KEY_CPU_TIME cpu_time}
+     *         <li>{@link #METRIC_KEY_EXECUTION_TIME execution_time}
+     *         </ul>
+     */
+    public Bundle addIteration(String label) {
+        mCpuTime = Process.getElapsedCpuTime() - mCpuTime;
+        mExecTime = SystemClock.uptimeMillis() - mExecTime;
+
+        Bundle iteration = new Bundle();
+        iteration.putString(METRIC_KEY_LABEL, label);
+        iteration.putLong(METRIC_KEY_EXECUTION_TIME, mExecTime);
+        iteration.putLong(METRIC_KEY_CPU_TIME, mCpuTime);
+        mPerfMeasurement.getParcelableArrayList(METRIC_KEY_ITERATIONS).add(iteration);
+
+        mExecTime = SystemClock.uptimeMillis();
+        mCpuTime = Process.getElapsedCpuTime();
+        return iteration;
+    }
+
+    /**
+     * Stop measurement of user and cpu time.
+     *
+     * @param label description of code block between addIteration or
+     *              startTiming and stopTiming, used to label output
+     * @return Runtime metrics stored in a bundle, including all iterations
+     *         between calls to startTiming and stopTiming. List of iterations
+     *         is keyed by {@link #METRIC_KEY_ITERATIONS iterations}.
+     */
+    public Bundle stopTiming(String label) {
+        addIteration(label);
+        if (mPerfWriter != null)
+            mPerfWriter.writeStopTiming(mPerfMeasurement);
+        return mPerfMeasurement;
+    }
+
+    /*
+     * Starts tracking memory usage, binder transactions, and real & cpu timing.
+     */
+    private void startPerformanceSnapshot() {
+        // Create new snapshot
+        mPerfSnapshot = new Bundle();
+
+        // Add initial binder counts
+        Bundle binderCounts = getBinderCounts();
+        for (String key : binderCounts.keySet()) {
+            mPerfSnapshot.putLong("pre_" + key, binderCounts.getLong(key));
+        }
+
+        // Force a GC and zero out the performance counters. Do this
+        // before reading initial CPU/wall-clock times so we don't include
+        // the cost of this setup in our final metrics.
+        startAllocCounting();
+
+        // Record CPU time up to this point, and start timing. Note: this
+        // must happen at the end of this method, otherwise the timing will
+        // include noise.
+        mSnapshotExecTime = SystemClock.uptimeMillis();
+        mSnapshotCpuTime = Process.getElapsedCpuTime();
+    }
+
+    /*
+     * Stops tracking memory usage, binder transactions, and real & cpu timing.
+     * Stores collected data as type long into Bundle object for reporting.
+     */
+    private void endPerformanceSnapshot() {
+        // Stop the timing. This must be done first before any other counting is
+        // stopped.
+        mSnapshotCpuTime = Process.getElapsedCpuTime() - mSnapshotCpuTime;
+        mSnapshotExecTime = SystemClock.uptimeMillis() - mSnapshotExecTime;
+
+        stopAllocCounting();
+
+        long nativeMax = Debug.getNativeHeapSize() / 1024;
+        long nativeAllocated = Debug.getNativeHeapAllocatedSize() / 1024;
+        long nativeFree = Debug.getNativeHeapFreeSize() / 1024;
+
+        Debug.MemoryInfo memInfo = new Debug.MemoryInfo();
+        Debug.getMemoryInfo(memInfo);
+
+        Runtime runtime = Runtime.getRuntime();
+
+        long dalvikMax = runtime.totalMemory() / 1024;
+        long dalvikFree = runtime.freeMemory() / 1024;
+        long dalvikAllocated = dalvikMax - dalvikFree;
+
+        // Add final binder counts
+        Bundle binderCounts = getBinderCounts();
+        for (String key : binderCounts.keySet()) {
+            mPerfSnapshot.putLong(key, binderCounts.getLong(key));
+        }
+
+        // Add alloc counts
+        Bundle allocCounts = getAllocCounts();
+        for (String key : allocCounts.keySet()) {
+            mPerfSnapshot.putLong(key, allocCounts.getLong(key));
+        }
+
+        mPerfSnapshot.putLong(METRIC_KEY_EXECUTION_TIME, mSnapshotExecTime);
+        mPerfSnapshot.putLong(METRIC_KEY_CPU_TIME, mSnapshotCpuTime);
+
+        mPerfSnapshot.putLong(METRIC_KEY_NATIVE_SIZE, nativeMax);
+        mPerfSnapshot.putLong(METRIC_KEY_NATIVE_ALLOCATED, nativeAllocated);
+        mPerfSnapshot.putLong(METRIC_KEY_NATIVE_FREE, nativeFree);
+        mPerfSnapshot.putLong(METRIC_KEY_NATIVE_PSS, memInfo.nativePss);
+        mPerfSnapshot.putLong(METRIC_KEY_NATIVE_PRIVATE_DIRTY, memInfo.nativePrivateDirty);
+        mPerfSnapshot.putLong(METRIC_KEY_NATIVE_SHARED_DIRTY, memInfo.nativeSharedDirty);
+
+        mPerfSnapshot.putLong(METRIC_KEY_JAVA_SIZE, dalvikMax);
+        mPerfSnapshot.putLong(METRIC_KEY_JAVA_ALLOCATED, dalvikAllocated);
+        mPerfSnapshot.putLong(METRIC_KEY_JAVA_FREE, dalvikFree);
+        mPerfSnapshot.putLong(METRIC_KEY_JAVA_PSS, memInfo.dalvikPss);
+        mPerfSnapshot.putLong(METRIC_KEY_JAVA_PRIVATE_DIRTY, memInfo.dalvikPrivateDirty);
+        mPerfSnapshot.putLong(METRIC_KEY_JAVA_SHARED_DIRTY, memInfo.dalvikSharedDirty);
+
+        mPerfSnapshot.putLong(METRIC_KEY_OTHER_PSS, memInfo.otherPss);
+        mPerfSnapshot.putLong(METRIC_KEY_OTHER_PRIVATE_DIRTY, memInfo.otherPrivateDirty);
+        mPerfSnapshot.putLong(METRIC_KEY_OTHER_SHARED_DIRTY, memInfo.otherSharedDirty);
+    }
+
+    /*
+     * Starts allocation counting. This triggers a gc and resets the counts.
+     */
+    private static void startAllocCounting() {
+        // Before we start trigger a GC and reset the debug counts. Run the
+        // finalizers and another GC before starting and stopping the alloc
+        // counts. This will free up any objects that were just sitting around
+        // waiting for their finalizers to be run.
+        Runtime.getRuntime().gc();
+        Runtime.getRuntime().runFinalization();
+        Runtime.getRuntime().gc();
+
+        Debug.resetAllCounts();
+
+        // start the counts
+        Debug.startAllocCounting();
+    }
+
+    /*
+     * Stops allocation counting.
+     */
+    private static void stopAllocCounting() {
+        Runtime.getRuntime().gc();
+        Runtime.getRuntime().runFinalization();
+        Runtime.getRuntime().gc();
+        Debug.stopAllocCounting();
+    }
+
+    /*
+     * Returns a bundle with the current results from the allocation counting.
+     */
+    private static Bundle getAllocCounts() {
+        Bundle results = new Bundle();
+        results.putLong(METRIC_KEY_GLOBAL_ALLOC_COUNT, Debug.getGlobalAllocCount());
+        results.putLong(METRIC_KEY_GLOBAL_ALLOC_SIZE, Debug.getGlobalAllocSize());
+        results.putLong(METRIC_KEY_GLOBAL_FREED_COUNT, Debug.getGlobalFreedCount());
+        results.putLong(METRIC_KEY_GLOBAL_FREED_SIZE, Debug.getGlobalFreedSize());
+        results.putLong(METRIC_KEY_GC_INVOCATION_COUNT, Debug.getGlobalGcInvocationCount());
+        return results;
+    }
+
+    /*
+     * Returns a bundle with the counts for various binder counts for this
+     * process. Currently the only two that are reported are the number of send
+     * and the number of received transactions.
+     */
+    private static Bundle getBinderCounts() {
+        Bundle results = new Bundle();
+        results.putLong(METRIC_KEY_SENT_TRANSACTIONS, Debug.getBinderSentTransactions());
+        results.putLong(METRIC_KEY_RECEIVED_TRANSACTIONS, Debug.getBinderReceivedTransactions());
+        return results;
+    }
+}
diff --git a/core/java/android/pim/vcard/VCardComposer.java b/core/java/android/pim/vcard/VCardComposer.java
index 6554827..3c01a9e 100644
--- a/core/java/android/pim/vcard/VCardComposer.java
+++ b/core/java/android/pim/vcard/VCardComposer.java
@@ -871,11 +871,10 @@
     }
 
     private boolean appendPostalsForDoCoMoInternal(final StringBuilder builder,
-            final List<ContentValues> contentValuesList, int preferedType) {
+            final List<ContentValues> contentValuesList, Integer preferedType) {
         for (ContentValues contentValues : contentValuesList) {
-            final int type = contentValues.getAsInteger(StructuredPostal.TYPE);
-            final String label = contentValues
-                    .getAsString(StructuredPostal.LABEL);
+            final Integer type = contentValues.getAsInteger(StructuredPostal.TYPE);
+            final String label = contentValues.getAsString(StructuredPostal.LABEL);
             if (type == preferedType) {
                 appendVCardPostalLine(builder, type, label, contentValues);
                 return true;
@@ -887,9 +886,8 @@
     private void appendPostalsForGeneric(final StringBuilder builder,
             final List<ContentValues> contentValuesList) {
         for (ContentValues contentValues : contentValuesList) {
-            final int type = contentValues.getAsInteger(StructuredPostal.TYPE);
-            final String label = contentValues
-                    .getAsString(StructuredPostal.LABEL);
+            final Integer type = contentValues.getAsInteger(StructuredPostal.TYPE);
+            final String label = contentValues.getAsString(StructuredPostal.LABEL);
             appendVCardPostalLine(builder, type, label, contentValues);
         }
     }
@@ -900,15 +898,10 @@
                 .get(Im.CONTENT_ITEM_TYPE);
         if (contentValuesList != null) {
             for (ContentValues contentValues : contentValuesList) {
-                int type = contentValues.getAsInteger(Im.PROTOCOL);
+                Integer protocol = contentValues.getAsInteger(Im.PROTOCOL);
                 String data = contentValues.getAsString(Im.DATA);
-                
-                Log.d("@@@", "Im information. protocol=\"" + type +
-                        "\", data=\"" + data + "\", protocol=\"" +
-                        contentValues.getAsString(Im.PROTOCOL) + "\", custom_protocol=\"" +
-                        contentValues.getAsString(Im.CUSTOM_PROTOCOL) + "\"");
 
-                if (type == Im.PROTOCOL_GOOGLE_TALK) {
+                if (protocol != null && protocol == Im.PROTOCOL_GOOGLE_TALK) {
                     if (VCardConfig.usesAndroidSpecificProperty(mVCardType)) {
                         appendVCardLine(builder, Constants.PROPERTY_X_GOOGLE_TALK, data);
                     }
@@ -1129,8 +1122,8 @@
         builder.append(VCARD_COL_SEPARATOR);
     }
 
-    private void appendVCardPostalLine(StringBuilder builder, int type,
-            String label, final ContentValues contentValues) {
+    private void appendVCardPostalLine(StringBuilder builder, Integer type, String label,
+            final ContentValues contentValues) {
         builder.append(VCARD_PROPERTY_ADR);
         builder.append(VCARD_ATTR_SEPARATOR);
 
@@ -1150,6 +1143,10 @@
             }
         }
 
+        if (type == null) {
+            type = StructuredPostal.TYPE_OTHER;
+        }
+
         boolean typeIsAppended = false;
         switch (type) {
         case StructuredPostal.TYPE_HOME:
@@ -1161,7 +1158,8 @@
             typeIsAppended = true;
             break;
         case StructuredPostal.TYPE_CUSTOM:
-            if (mUsesAndroidProperty && VCardUtils.containsOnlyAlphaDigitHyphen(label)){
+            if (mUsesAndroidProperty && !TextUtils.isEmpty(label)
+                        && VCardUtils.containsOnlyAlphaDigitHyphen(label)) {
                 // We're not sure whether the label is valid in the spec ("IANA-token" in the vCard 3.1
                 // is unclear...)
                 // Just for safety, we add "X-" at the beggining of each label.
@@ -1216,17 +1214,21 @@
         builder.append(VCARD_COL_SEPARATOR);
     }
 
-    private void appendVCardEmailLine(StringBuilder builder, int type,
-            String label, String data) {
+    private void appendVCardEmailLine(StringBuilder builder, Integer type, String label, String data) {
         builder.append(VCARD_PROPERTY_EMAIL);
         builder.append(VCARD_ATTR_SEPARATOR);
 
+        if (type == null) {
+            type = Email.TYPE_OTHER;
+        }
+
         switch (type) {
         case Email.TYPE_CUSTOM:
-            if (label.equals(
-                    android.provider.Contacts.ContactMethodsColumns.MOBILE_EMAIL_TYPE_NAME)) {
+            if (android.provider.Contacts.ContactMethodsColumns.MOBILE_EMAIL_TYPE_NAME
+                        .equals(label)) {
                 builder.append(Constants.ATTR_TYPE_CELL);
-            } else if (mUsesAndroidProperty && VCardUtils.containsOnlyAlphaDigitHyphen(label)){
+            } else if (mUsesAndroidProperty && !TextUtils.isEmpty(label)
+                        && VCardUtils.containsOnlyAlphaDigitHyphen(label)) {
                 builder.append("X-");
                 builder.append(label);
             } else {
@@ -1257,11 +1259,15 @@
         builder.append(VCARD_COL_SEPARATOR);
     }
 
-    private void appendVCardTelephoneLine(StringBuilder builder, int type,
-            String label, String encodedData) {
+    private void appendVCardTelephoneLine(StringBuilder builder, Integer type, String label,
+            String encodedData) {
         builder.append(VCARD_PROPERTY_TEL);
         builder.append(VCARD_ATTR_SEPARATOR);
 
+        if (type == null) {
+            type = Phone.TYPE_OTHER;
+        }
+
         switch (type) {
         case Phone.TYPE_HOME:
             appendTypeAttributes(builder, Arrays.asList(
@@ -1295,8 +1301,8 @@
             builder.append(Constants.ATTR_TYPE_VOICE);
             break;
         case Phone.TYPE_CUSTOM:
-            if (mUsesAndroidProperty) {
-                VCardUtils.containsOnlyAlphaDigitHyphen(label);
+            if (mUsesAndroidProperty && !TextUtils.isEmpty(label)
+                        && VCardUtils.containsOnlyAlphaDigitHyphen(label)) {
                 builder.append("X-" + label);
             } else {
                 // Just ignore the custom type.
@@ -1316,11 +1322,10 @@
     /**
      * Appends phone type string which may not be available in some devices.
      */
-    private void appendUncommonPhoneType(StringBuilder builder, int type) {
+    private void appendUncommonPhoneType(StringBuilder builder, Integer type) {
         if (mIsDoCoMo) {
             // The previous implementation for DoCoMo had been conservative
-            // about
-            // miscellaneous types.
+            // about miscellaneous types.
             builder.append(Constants.ATTR_TYPE_VOICE);
         } else {
             String phoneAttribute = VCardUtils.getPhoneAttributeString(type);
diff --git a/core/java/android/pim/vcard/VCardUtils.java b/core/java/android/pim/vcard/VCardUtils.java
index b7b706f..ffceade 100644
--- a/core/java/android/pim/vcard/VCardUtils.java
+++ b/core/java/android/pim/vcard/VCardUtils.java
@@ -75,7 +75,7 @@
         sPhoneTypesSetUnknownToContacts.add(Constants.ATTR_TYPE_VIDEO);
     }
     
-    public static String getPhoneAttributeString(int type) {
+    public static String getPhoneAttributeString(Integer type) {
         return sKnownPhoneTypesMap_ItoS.get(type);
     }
     
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index fc39573..08a2a9f 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -1456,8 +1456,10 @@
         if (!TextUtils.isEmpty(summary)) {
             sb.append(summary).append(' ');
         }
-        // Drop the last space
-        sb.setLength(sb.length() - 1);
+        if (sb.length() > 0) {
+            // Drop the last space
+            sb.setLength(sb.length() - 1);
+        }
         return sb;
     }
 
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index c734aed..d354ccf 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -298,6 +298,15 @@
         }
 
         /**
+         * Build a {@link #CONTENT_LOOKUP_URI} lookup {@link Uri} using the
+         * given {@link Contacts#_ID} and {@link Contacts#LOOKUP_KEY}.
+         */
+        public static Uri getLookupUri(long contactId, String lookupKey) {
+            return ContentUris.withAppendedId(Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI,
+                    lookupKey), contactId);
+        }
+
+        /**
          * Computes a content URI (see {@link #CONTENT_URI}) given a lookup URI.
          * <p>
          * Returns null if the contact cannot be found.
diff --git a/core/java/android/provider/Im.java b/core/java/android/provider/Im.java
index f126c4d..d5cc2207 100644
--- a/core/java/android/provider/Im.java
+++ b/core/java/android/provider/Im.java
@@ -27,7 +27,7 @@
 import java.util.HashMap;
 
 /**
- * The IM provider stores all information about roster contacts, chat messages, presence, etc.
+ * The GTalk provider stores all information about roster contacts, chat messages, presence, etc.
  *
  * @hide
  */
@@ -38,7 +38,7 @@
     private Im() {}
 
     /**
-     * The Columns for IM providers (i.e. AIM, Y!, GTalk)
+     * The Columns for IM providers
      */
     public interface ProviderColumns {
         /**
@@ -146,20 +146,20 @@
          * The content:// style URL for this table
          */
         public static final Uri CONTENT_URI =
-            Uri.parse("content://im/providers");
+            Uri.parse("content://com.google.android.providers.talk/providers");
 
         public static final Uri CONTENT_URI_WITH_ACCOUNT =
-            Uri.parse("content://im/providers/account");
+            Uri.parse("content://com.google.android.providers.talk/providers/account");
 
         /**
          * The MIME type of {@link #CONTENT_URI} providing a directory of
          * people.
          */
         public static final String CONTENT_TYPE =
-                "vnd.android.cursor.dir/im-providers";
+                "vnd.android.cursor.dir/gtalk-providers";
 
         public static final String CONTENT_ITEM_TYPE =
-                "vnd.android.cursor.item/im-providers";
+                "vnd.android.cursor.item/gtalk-providers";
 
         /**
          * The default sort order for this table
@@ -253,21 +253,21 @@
          * The content:// style URL for this table
          */
         public static final Uri CONTENT_URI =
-            Uri.parse("content://im/accounts");
+            Uri.parse("content://com.google.android.providers.talk/accounts");
 
         /**
          * The MIME type of {@link #CONTENT_URI} providing a directory of
          * account.
          */
         public static final String CONTENT_TYPE =
-                "vnd.android.cursor.dir/im-accounts";
+                "vnd.android.cursor.dir/gtalk-accounts";
 
         /**
          * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
          * account.
          */
         public static final String CONTENT_ITEM_TYPE =
-                "vnd.android.cursor.item/im-accounts";
+                "vnd.android.cursor.item/gtalk-accounts";
 
         /**
          * The default sort order for this table
@@ -326,19 +326,19 @@
          * The content:// style URL for this table
          */
         public static final Uri CONTENT_URI =
-            Uri.parse("content://im/accountStatus");
+            Uri.parse("content://com.google.android.providers.talk/accountStatus");
 
         /**
          * The MIME type of {@link #CONTENT_URI} providing a directory of account status.
          */
         public static final String CONTENT_TYPE =
-                "vnd.android.cursor.dir/im-account-status";
+                "vnd.android.cursor.dir/gtalk-account-status";
 
         /**
          * The MIME type of a {@link #CONTENT_URI} subdirectory of a single account status.
          */
         public static final String CONTENT_ITEM_TYPE =
-                "vnd.android.cursor.item/im-account-status";
+                "vnd.android.cursor.item/gtalk-account-status";
 
         /**
          * The default sort order for this table
@@ -522,83 +522,83 @@
          * The content:// style URL for this table
          */
         public static final Uri CONTENT_URI =
-            Uri.parse("content://im/contacts");
+            Uri.parse("content://com.google.android.providers.talk/contacts");
 
         /**
          * The content:// style URL for contacts joined with presence
          */
         public static final Uri CONTENT_URI_WITH_PRESENCE =
-            Uri.parse("content://im/contactsWithPresence");
+            Uri.parse("content://com.google.android.providers.talk/contactsWithPresence");
 
         /**
          * The content:// style URL for barebone contacts, not joined with any other table
          */
         public static final Uri CONTENT_URI_CONTACTS_BAREBONE =
-            Uri.parse("content://im/contactsBarebone");
+            Uri.parse("content://com.google.android.providers.talk/contactsBarebone");
 
         /**
          * The content:// style URL for contacts who have an open chat session
          */
         public static final Uri CONTENT_URI_CHAT_CONTACTS =
-            Uri.parse("content://im/contacts/chatting");
+            Uri.parse("content://com.google.android.providers.talk/contacts/chatting");
 
         /**
          * The content:// style URL for contacts who have been blocked
          */
         public static final Uri CONTENT_URI_BLOCKED_CONTACTS =
-            Uri.parse("content://im/contacts/blocked");
+            Uri.parse("content://com.google.android.providers.talk/contacts/blocked");
 
         /**
          * The content:// style URL for contacts by provider and account
          */
         public static final Uri CONTENT_URI_CONTACTS_BY =
-            Uri.parse("content://im/contacts");
+            Uri.parse("content://com.google.android.providers.talk/contacts");
 
         /**
          * The content:// style URL for contacts by provider and account,
          * and who have an open chat session
          */
         public static final Uri CONTENT_URI_CHAT_CONTACTS_BY =
-            Uri.parse("content://im/contacts/chatting");
+            Uri.parse("content://com.google.android.providers.talk/contacts/chatting");
 
         /**
          * The content:// style URL for contacts by provider and account,
          * and who are online
          */
         public static final Uri CONTENT_URI_ONLINE_CONTACTS_BY =
-            Uri.parse("content://im/contacts/online");
+            Uri.parse("content://com.google.android.providers.talk/contacts/online");
 
         /**
          * The content:// style URL for contacts by provider and account,
          * and who are offline
          */
         public static final Uri CONTENT_URI_OFFLINE_CONTACTS_BY =
-            Uri.parse("content://im/contacts/offline");
+            Uri.parse("content://com.google.android.providers.talk/contacts/offline");
 
         /**
          * The content:// style URL for operations on bulk contacts
          */
         public static final Uri BULK_CONTENT_URI =
-                Uri.parse("content://im/bulk_contacts");
+                Uri.parse("content://com.google.android.providers.talk/bulk_contacts");
 
         /**
          * The content:// style URL for the count of online contacts in each
          * contact list by provider and account.
          */
         public static final Uri CONTENT_URI_ONLINE_COUNT =
-            Uri.parse("content://im/contacts/onlineCount");
+            Uri.parse("content://com.google.android.providers.talk/contacts/onlineCount");
 
         /**
          * The MIME type of {@link #CONTENT_URI} providing a directory of
          * people.
          */
-        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/im-contacts";
+        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/gtalk-contacts";
 
         /**
          * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
          * person.
          */
-        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/im-contacts";
+        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/gtalk-contacts";
 
         /**
          * The default sort order for this table
@@ -634,21 +634,21 @@
          * The content:// style URL for this table
          */
         public static final Uri CONTENT_URI =
-            Uri.parse("content://im/contactLists");
+            Uri.parse("content://com.google.android.providers.talk/contactLists");
 
         /**
          * The MIME type of {@link #CONTENT_URI} providing a directory of
          * people.
          */
         public static final String CONTENT_TYPE =
-                "vnd.android.cursor.dir/im-contactLists";
+                "vnd.android.cursor.dir/gtalk-contactLists";
 
         /**
          * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
          * person.
          */
         public static final String CONTENT_ITEM_TYPE =
-                "vnd.android.cursor.item/im-contactLists";
+                "vnd.android.cursor.item/gtalk-contactLists";
 
         /**
          * The default sort order for this table
@@ -699,21 +699,21 @@
          * The content:// style URL for this table
          */
         public static final Uri CONTENT_URI =
-            Uri.parse("content://im/blockedList");
+            Uri.parse("content://com.google.android.providers.talk/blockedList");
 
         /**
          * The MIME type of {@link #CONTENT_URI} providing a directory of
          * people.
          */
         public static final String CONTENT_TYPE =
-                "vnd.android.cursor.dir/im-blockedList";
+                "vnd.android.cursor.dir/gtalk-blockedList";
 
         /**
          * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
          * person.
          */
         public static final String CONTENT_ITEM_TYPE =
-                "vnd.android.cursor.item/im-blockedList";
+                "vnd.android.cursor.item/gtalk-blockedList";
 
         /**
          * The default sort order for this table
@@ -822,21 +822,21 @@
          * The content:// style URL for this table
          */
         public static final Uri CONTENT_URI =
-            Uri.parse("content://im/contactsEtag");
+            Uri.parse("content://com.google.android.providers.talk/contactsEtag");
 
         /**
          * The MIME type of {@link #CONTENT_URI} providing a directory of
          * people.
          */
         public static final String CONTENT_TYPE =
-                "vnd.android.cursor.dir/im-contactsEtag";
+                "vnd.android.cursor.dir/gtalk-contactsEtag";
 
         /**
          * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
          * person.
          */
         public static final String CONTENT_ITEM_TYPE =
-                "vnd.android.cursor.item/im-contactsEtag";
+                "vnd.android.cursor.item/gtalk-contactsEtag";
     }
 
     /**
@@ -1057,75 +1057,75 @@
          * The content:// style URL for this table
          */
         public static final Uri CONTENT_URI =
-                Uri.parse("content://im/messages");
+                Uri.parse("content://com.google.android.providers.talk/messages");
 
         /**
          * The content:// style URL for messages by thread id
          */
         public static final Uri CONTENT_URI_MESSAGES_BY_THREAD_ID =
-                Uri.parse("content://im/messagesByThreadId");
+                Uri.parse("content://com.google.android.providers.talk/messagesByThreadId");
 
         /**
          * The content:// style URL for messages by account and contact
          */
         public static final Uri CONTENT_URI_MESSAGES_BY_ACCOUNT_AND_CONTACT =
-                Uri.parse("content://im/messagesByAcctAndContact");
+                Uri.parse("content://com.google.android.providers.talk/messagesByAcctAndContact");
 
         /**
          * The content:// style URL for messages by provider
          */
         public static final Uri CONTENT_URI_MESSAGES_BY_PROVIDER =
-                Uri.parse("content://im/messagesByProvider");
+                Uri.parse("content://com.google.android.providers.talk/messagesByProvider");
 
         /**
          * The content:// style URL for messages by account
          */
         public static final Uri CONTENT_URI_BY_ACCOUNT =
-                Uri.parse("content://im/messagesByAccount");
+                Uri.parse("content://com.google.android.providers.talk/messagesByAccount");
 
         /**
          * The content:// style url for off the record messages
          */
         public static final Uri OTR_MESSAGES_CONTENT_URI =
-                Uri.parse("content://im/otrMessages");
+                Uri.parse("content://com.google.android.providers.talk/otrMessages");
 
         /**
          * The content:// style url for off the record messages by thread id
          */
         public static final Uri OTR_MESSAGES_CONTENT_URI_BY_THREAD_ID =
-                Uri.parse("content://im/otrMessagesByThreadId");
+                Uri.parse("content://com.google.android.providers.talk/otrMessagesByThreadId");
 
         /**
          * The content:// style url for off the record messages by account and contact
          */
         public static final Uri OTR_MESSAGES_CONTENT_URI_BY_ACCOUNT_AND_CONTACT =
-                Uri.parse("content://im/otrMessagesByAcctAndContact");
+                Uri.parse("content://com.google.android.providers.talk/otrMessagesByAcctAndContact");
 
         /**
          * The content:// style URL for off the record messages by provider
          */
         public static final Uri OTR_MESSAGES_CONTENT_URI_BY_PROVIDER =
-                Uri.parse("content://im/otrMessagesByProvider");
+                Uri.parse("content://com.google.android.providers.talk/otrMessagesByProvider");
 
         /**
          * The content:// style URL for off the record messages by account
          */
         public static final Uri OTR_MESSAGES_CONTENT_URI_BY_ACCOUNT =
-                Uri.parse("content://im/otrMessagesByAccount");
+                Uri.parse("content://com.google.android.providers.talk/otrMessagesByAccount");
 
         /**
          * The MIME type of {@link #CONTENT_URI} providing a directory of
          * people.
          */
         public static final String CONTENT_TYPE =
-                "vnd.android.cursor.dir/im-messages";
+                "vnd.android.cursor.dir/gtalk-messages";
 
         /**
          * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
          * person.
          */
         public static final String CONTENT_ITEM_TYPE =
-                "vnd.android.cursor.item/im-messages";
+                "vnd.android.cursor.item/gtalk-messages";
 
         /**
          * The default sort order for this table
@@ -1166,21 +1166,21 @@
         private GroupMembers(){}
 
         public static final Uri CONTENT_URI =
-            Uri.parse("content://im/groupMembers");
+            Uri.parse("content://com.google.android.providers.talk/groupMembers");
 
         /**
          * The MIME type of {@link #CONTENT_URI} providing a directory of
          * group members.
          */
         public static final String CONTENT_TYPE =
-            "vnd.android.cursor.dir/im-groupMembers";
+            "vnd.android.cursor.dir/gtalk-groupMembers";
 
         /**
          * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
          * group member.
          */
         public static final String CONTENT_ITEM_TYPE =
-                "vnd.android.cursor.item/im-groupMembers";
+                "vnd.android.cursor.item/gtalk-groupMembers";
     }
 
     /**
@@ -1246,21 +1246,21 @@
          * The content:// style URL for this table
          */
         public static final Uri CONTENT_URI =
-            Uri.parse("content://im/invitations");
+            Uri.parse("content://com.google.android.providers.talk/invitations");
 
         /**
          * The MIME type of {@link #CONTENT_URI} providing a directory of
          * invitations.
          */
         public static final String CONTENT_TYPE =
-            "vnd.android.cursor.dir/im-invitations";
+            "vnd.android.cursor.dir/gtalk-invitations";
 
         /**
          * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
          * invitation.
          */
         public static final String CONTENT_ITEM_TYPE =
-                "vnd.android.cursor.item/im-invitations";
+                "vnd.android.cursor.item/gtalk-invitations";
     }
 
     /**
@@ -1302,24 +1302,25 @@
         /**
          * The content:// style URL for this table
          */
-        public static final Uri CONTENT_URI = Uri.parse("content://im/avatars");
+        public static final Uri CONTENT_URI =
+            Uri.parse("content://com.google.android.providers.talk/avatars");
 
         /**
          * The content:// style URL for avatars by provider, account and contact
          */
         public static final Uri CONTENT_URI_AVATARS_BY =
-                Uri.parse("content://im/avatarsBy");
+                Uri.parse("content://com.google.android.providers.talk/avatarsBy");
 
         /**
          * The MIME type of {@link #CONTENT_URI} providing the avatars
          */
-        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/im-avatars";
+        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/gtalk-avatars";
 
         /**
          * The MIME type of a {@link #CONTENT_URI}
          */
         public static final String CONTENT_ITEM_TYPE =
-                "vnd.android.cursor.item/im-avatars";
+                "vnd.android.cursor.item/gtalk-avatars";
 
         /**
          * The default sort order for this table
@@ -1397,28 +1398,31 @@
         /**
          * The content:// style URL for this table
          */
-        public static final Uri CONTENT_URI = Uri.parse("content://im/presence");
+        public static final Uri CONTENT_URI =
+            Uri.parse("content://com.google.android.providers.talk/presence");
 
         /**
-         * The content URL for IM presences for an account
+         * The content URL for Talk presences for an account
          */
-        public static final Uri CONTENT_URI_BY_ACCOUNT = Uri.parse("content://im/presence/account");
+        public static final Uri CONTENT_URI_BY_ACCOUNT =
+            Uri.parse("content://com.google.android.providers.talk/presence/account");
 
         /**
          * The content:// style URL for operations on bulk contacts
          */
-        public static final Uri BULK_CONTENT_URI = Uri.parse("content://im/bulk_presence");
+        public static final Uri BULK_CONTENT_URI =
+            Uri.parse("content://com.google.android.providers.talk/bulk_presence");
 
         /**
          * The content:// style URL for seeding presences for a given account id.
          */
         public static final Uri SEED_PRESENCE_BY_ACCOUNT_CONTENT_URI =
-                Uri.parse("content://im/seed_presence/account");
+                Uri.parse("content://com.google.android.providers.talk/seed_presence/account");
 
         /**
          * The MIME type of a {@link #CONTENT_URI} providing a directory of presence
          */
-        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/im-presence";
+        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/gtalk-presence";
 
         /**
          * The default sort order for this table
@@ -1491,22 +1495,23 @@
          * The content:// style URL for this table
          */
         public static final Uri CONTENT_URI =
-            Uri.parse("content://im/chats");
+            Uri.parse("content://com.google.android.providers.talk/chats");
 
         /**
          * The content URL for all chats that belong to the account
          */
-        public static final Uri CONTENT_URI_BY_ACCOUNT = Uri.parse("content://im/chats/account");
+        public static final Uri CONTENT_URI_BY_ACCOUNT =
+            Uri.parse("content://com.google.android.providers.talk/chats/account");
 
         /**
          * The MIME type of {@link #CONTENT_URI} providing a directory of chats.
          */
-        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/im-chats";
+        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/gtalk-chats";
 
         /**
          * The MIME type of a {@link #CONTENT_URI} subdirectory of a single chat.
          */
-        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/im-chats";
+        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/gtalk-chats";
 
         /**
          * The default sort order for this table
@@ -1534,19 +1539,20 @@
         /**
          * The content:// style URI for this table
          */
-        public static final Uri CONTENT_URI = Uri.parse("content://im/sessionCookies");
+        public static final Uri CONTENT_URI =
+            Uri.parse("content://com.google.android.providers.talk/sessionCookies");
 
         /**
          * The content:// style URL for session cookies by provider and account
          */
         public static final Uri CONTENT_URI_SESSION_COOKIES_BY =
-            Uri.parse("content://im/sessionCookiesBy");
+            Uri.parse("content://com.google.android.providers.talk/sessionCookiesBy");
 
         /**
          * The MIME type of {@link #CONTENT_URI} providing a directory of
          * people.
          */
-        public static final String CONTENT_TYPE = "vnd.android-dir/im-sessionCookies";
+        public static final String CONTENT_TYPE = "vnd.android-dir/gtalk-sessionCookies";
     }
 
     /**
@@ -1581,12 +1587,12 @@
          * The content:// style URI for this table
          */
         public static final Uri CONTENT_URI =
-                Uri.parse("content://im/providerSettings");
+                Uri.parse("content://com.google.android.providers.talk/providerSettings");
 
         /**
          * The MIME type of {@link #CONTENT_URI} providing provider settings
          */
-        public static final String CONTENT_TYPE = "vnd.android-dir/im-providerSettings";
+        public static final String CONTENT_TYPE = "vnd.android-dir/gtalk-providerSettings";
 
         /**
          * A boolean value to indicate whether this provider should show the offline contacts
@@ -1596,13 +1602,13 @@
         /** controls whether or not the GTalk service automatically connect to server. */
         public static final String SETTING_AUTOMATICALLY_CONNECT_GTALK = "gtalk_auto_connect";
 
-        /** controls whether or not the IM service will be automatically started after boot */
+        /** controls whether or not the GTalk service will be automatically started after boot */
         public static final String SETTING_AUTOMATICALLY_START_SERVICE = "auto_start_service";
 
         /** controls whether or not the offline contacts will be hided */
         public static final String SETTING_HIDE_OFFLINE_CONTACTS = "hide_offline_contacts";
 
-        /** controls whether or not enable the IM notification */
+        /** controls whether or not enable the GTalk notification */
         public static final String SETTING_ENABLE_NOTIFICATION = "enable_notification";
 
         /** specifies whether or not to vibrate */
@@ -1794,10 +1800,10 @@
         }
 
         /**
-         * A convenience method to set whether or not enable the IM notification.
+         * A convenience method to set whether or not enable the GTalk notification.
          *
          * @param contentResolver The ContentResolver to use to access the setting table.
-         * @param enable Whether enable the IM notification
+         * @param enable Whether enable the GTalk notification
          */
         public static void setEnableNotification(ContentResolver contentResolver, long providerId,
                 boolean enable) {
@@ -1935,18 +1941,18 @@
             }
 
             /**
-             * Set whether or not enable the IM notification.
+             * Set whether or not enable the GTalk notification.
              *
-             * @param enable Whether or not enable the IM notification.
+             * @param enable Whether or not enable the GTalk notification.
              */
             public void setEnableNotification(boolean enable) {
                 ProviderSettings.setEnableNotification(mContentResolver, mProviderId, enable);
             }
 
             /**
-             * Check if the IM notification is enabled.
+             * Check if the GTalk notification is enabled.
              *
-             * @return Whether or not enable the IM notification.
+             * @return Whether or not enable the GTalk notification.
              */
             public boolean getEnableNotification() {
                 return getBoolean(SETTING_ENABLE_NOTIFICATION,
@@ -1954,7 +1960,7 @@
             }
 
             /**
-             * Set whether or not to vibrate on IM notification.
+             * Set whether or not to vibrate on GTalk notification.
              *
              * @param vibrate Whether or not to vibrate.
              */
@@ -1963,7 +1969,7 @@
             }
 
             /**
-             * Gets whether or not to vibrate on IM notification.
+             * Gets whether or not to vibrate on GTalk notification.
              *
              * @return Whether or not to vibrate.
              */
@@ -2138,8 +2144,8 @@
 
 
     /**
-     * Columns for IM branding resource map cache table. This table caches the result of
-     * loading the branding resources to speed up IM landing page start.
+     * Columns for GTalk branding resource map cache table. This table caches the result of
+     * loading the branding resources to speed up GTalk landing page start.
      */
     public interface BrandingResourceMapCacheColumns {
         /**
@@ -2160,14 +2166,15 @@
     }
 
     /**
-     * The table for caching the result of loading IM branding resources.
+     * The table for caching the result of loading GTalk branding resources.
      */
     public static final class BrandingResourceMapCache
         implements BaseColumns, BrandingResourceMapCacheColumns {
         /**
          * The content:// style URL for this table.
          */
-        public static final Uri CONTENT_URI = Uri.parse("content://im/brandingResMapCache");
+        public static final Uri CONTENT_URI =
+            Uri.parse("content://com.google.android.providers.talk/brandingResMapCache");
     }
 
 
@@ -2229,13 +2236,14 @@
         /**
          * The content:// style URL for this table.
          */
-        public static final Uri CONTENT_URI = Uri.parse("content://im/outgoingRmqMessages");
+        public static final Uri CONTENT_URI =
+            Uri.parse("content://com.google.android.providers.talk/outgoingRmqMessages");
 
         /**
          * The content:// style URL for the highest rmq id for the outgoing rmq messages
          */
         public static final Uri CONTENT_URI_FOR_HIGHEST_RMQ_ID =
-                Uri.parse("content://im/outgoingHighestRmqId");
+                Uri.parse("content://com.google.android.providers.talk/outgoingHighestRmqId");
 
         /**
          * The default sort order for this table.
@@ -2309,7 +2317,8 @@
         /**
          * The content:// style URL for this table.
          */
-        public static final Uri CONTENT_URI = Uri.parse("content://im/lastRmqId");
+        public static final Uri CONTENT_URI =
+            Uri.parse("content://com.google.android.providers.talk/lastRmqId");
     }
 
     /**
@@ -2327,7 +2336,8 @@
         /**
          * The content:// style URL for this table.
          */
-        public static final Uri CONTENT_URI = Uri.parse("content://im/s2dids");
+        public static final Uri CONTENT_URI =
+            Uri.parse("content://com.google.android.providers.talk/s2dids");
     }
 
 }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 97955ae..688f377 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2401,11 +2401,6 @@
             WIFI_NUM_ALLOWED_CHANNELS,
             WIFI_NUM_OPEN_NETWORKS_KEPT,
             BACKGROUND_DATA,
-            PREFERRED_NETWORK_MODE,
-            PREFERRED_TTY_MODE,
-            CDMA_CELL_BROADCAST_SMS,
-            PREFERRED_CDMA_SUBSCRIPTION,
-            ENHANCED_VOICE_PRIVACY_ENABLED
         };
 
         /**
diff --git a/core/java/android/server/BluetoothA2dpService.java b/core/java/android/server/BluetoothA2dpService.java
index d9fcb53..9c687e2 100644
--- a/core/java/android/server/BluetoothA2dpService.java
+++ b/core/java/android/server/BluetoothA2dpService.java
@@ -25,8 +25,6 @@
 import android.bluetooth.BluetoothA2dp;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothError;
-import android.bluetooth.BluetoothIntent;
 import android.bluetooth.BluetoothUuid;
 import android.bluetooth.IBluetoothA2dp;
 import android.content.BroadcastReceiver;
@@ -80,31 +78,31 @@
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
             BluetoothDevice device =
-                    intent.getParcelableExtra(BluetoothIntent.DEVICE);
-            if (action.equals(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION)) {
-                int state = intent.getIntExtra(BluetoothIntent.BLUETOOTH_STATE,
-                                               BluetoothError.ERROR);
+                    intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+            if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
+                int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
+                                               BluetoothAdapter.ERROR);
                 switch (state) {
-                case BluetoothAdapter.BLUETOOTH_STATE_ON:
+                case BluetoothAdapter.STATE_ON:
                     onBluetoothEnable();
                     break;
-                case BluetoothAdapter.BLUETOOTH_STATE_TURNING_OFF:
+                case BluetoothAdapter.STATE_TURNING_OFF:
                     onBluetoothDisable();
                     break;
                 }
-            } else if (action.equals(BluetoothIntent.BOND_STATE_CHANGED_ACTION)) {
-                int bondState = intent.getIntExtra(BluetoothIntent.BOND_STATE,
-                                                   BluetoothError.ERROR);
+            } else if (action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED)) {
+                int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
+                                                   BluetoothDevice.ERROR);
                 switch(bondState) {
                 case BluetoothDevice.BOND_BONDED:
                     setSinkPriority(device, BluetoothA2dp.PRIORITY_AUTO);
                     break;
                 case BluetoothDevice.BOND_BONDING:
-                case BluetoothDevice.BOND_NOT_BONDED:
+                case BluetoothDevice.BOND_NONE:
                     setSinkPriority(device, BluetoothA2dp.PRIORITY_OFF);
                     break;
                 }
-            } else if (action.equals(BluetoothIntent.REMOTE_DEVICE_CONNECTED_ACTION)) {
+            } else if (action.equals(BluetoothDevice.ACTION_ACL_CONNECTED)) {
                 if (getSinkPriority(device) > BluetoothA2dp.PRIORITY_OFF &&
                         isSinkDevice(device)) {
                     // This device is a preferred sink. Make an A2DP connection
@@ -134,9 +132,9 @@
 
         mAdapter = (BluetoothAdapter) context.getSystemService(Context.BLUETOOTH_SERVICE);
 
-        mIntentFilter = new IntentFilter(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION);
-        mIntentFilter.addAction(BluetoothIntent.BOND_STATE_CHANGED_ACTION);
-        mIntentFilter.addAction(BluetoothIntent.REMOTE_DEVICE_CONNECTED_ACTION);
+        mIntentFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
+        mIntentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
+        mIntentFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
         mContext.registerReceiver(mReceiver, mIntentFilter);
 
         mAudioDevices = new HashMap<BluetoothDevice, Integer>();
@@ -273,7 +271,7 @@
         mAudioManager.setParameters(BLUETOOTH_ENABLED + "=false");
     }
 
-    public synchronized int connectSink(BluetoothDevice device) {
+    public synchronized boolean connectSink(BluetoothDevice device) {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
                                                 "Need BLUETOOTH_ADMIN permission");
         if (DBG) log("connectSink(" + device + ")");
@@ -284,11 +282,11 @@
                 BluetoothA2dp.STATE_CONNECTED,
                 BluetoothA2dp.STATE_PLAYING,
                 BluetoothA2dp.STATE_DISCONNECTING}).size() != 0) {
-            return BluetoothError.ERROR;
+            return false;
         }
 
         if (mAudioDevices.get(device) == null && !addAudioSink(device))
-            return BluetoothError.ERROR;
+            return false;
 
         int state = mAudioDevices.get(device);
 
@@ -296,44 +294,44 @@
         case BluetoothA2dp.STATE_CONNECTED:
         case BluetoothA2dp.STATE_PLAYING:
         case BluetoothA2dp.STATE_DISCONNECTING:
-            return BluetoothError.ERROR;
+            return false;
         case BluetoothA2dp.STATE_CONNECTING:
-            return BluetoothError.SUCCESS;
+            return true;
         }
 
         String path = mBluetoothService.getObjectPathFromAddress(device.getAddress());
         if (path == null)
-            return BluetoothError.ERROR;
+            return false;
 
         // State is DISCONNECTED
         if (!connectSinkNative(path)) {
-            return BluetoothError.ERROR;
+            return false;
         }
-        return BluetoothError.SUCCESS;
+        return true;
     }
 
-    public synchronized int disconnectSink(BluetoothDevice device) {
+    public synchronized boolean disconnectSink(BluetoothDevice device) {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
                                                 "Need BLUETOOTH_ADMIN permission");
         if (DBG) log("disconnectSink(" + device + ")");
 
         String path = mBluetoothService.getObjectPathFromAddress(device.getAddress());
         if (path == null) {
-            return BluetoothError.ERROR;
+            return false;
         }
 
         switch (getSinkState(device)) {
         case BluetoothA2dp.STATE_DISCONNECTED:
-            return BluetoothError.ERROR;
+            return false;
         case BluetoothA2dp.STATE_DISCONNECTING:
-            return BluetoothError.SUCCESS;
+            return true;
         }
 
         // State is CONNECTING or CONNECTED or PLAYING
         if (!disconnectSinkNative(path)) {
-            return BluetoothError.ERROR;
+            return false;
         } else {
-            return BluetoothError.SUCCESS;
+            return true;
         }
     }
 
@@ -359,15 +357,14 @@
                 BluetoothA2dp.PRIORITY_OFF);
     }
 
-    public synchronized int setSinkPriority(BluetoothDevice device, int priority) {
+    public synchronized boolean setSinkPriority(BluetoothDevice device, int priority) {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
                                                 "Need BLUETOOTH_ADMIN permission");
-        if (!BluetoothDevice.checkBluetoothAddress(device.getAddress())) {
-            return BluetoothError.ERROR;
+        if (!BluetoothAdapter.checkBluetoothAddress(device.getAddress())) {
+            return false;
         }
         return Settings.Secure.putInt(mContext.getContentResolver(),
-                Settings.Secure.getBluetoothA2dpSinkPriorityKey(device.getAddress()), priority) ?
-                BluetoothError.SUCCESS : BluetoothError.ERROR;
+                Settings.Secure.getBluetoothA2dpSinkPriorityKey(device.getAddress()), priority);
     }
 
     private synchronized void onSinkPropertyChanged(String path, String []propValues) {
@@ -413,10 +410,10 @@
             }
             mAudioDevices.put(device, state);
 
-            Intent intent = new Intent(BluetoothA2dp.SINK_STATE_CHANGED_ACTION);
-            intent.putExtra(BluetoothIntent.DEVICE, device);
-            intent.putExtra(BluetoothA2dp.SINK_PREVIOUS_STATE, prevState);
-            intent.putExtra(BluetoothA2dp.SINK_STATE, state);
+            Intent intent = new Intent(BluetoothA2dp.ACTION_SINK_STATE_CHANGED);
+            intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
+            intent.putExtra(BluetoothA2dp.EXTRA_PREVIOUS_SINK_STATE, prevState);
+            intent.putExtra(BluetoothA2dp.EXTRA_SINK_STATE, state);
             mContext.sendBroadcast(intent, BLUETOOTH_PERM);
 
             if (DBG) log("A2DP state : device: " + device + " State:" + prevState + "->" + state);
diff --git a/core/java/android/server/BluetoothEventLoop.java b/core/java/android/server/BluetoothEventLoop.java
index 8cef3a2..1ed5c49 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -17,11 +17,9 @@
 package android.server;
 
 import android.bluetooth.BluetoothA2dp;
-import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothError;
-import android.bluetooth.BluetoothIntent;
 import android.bluetooth.BluetoothUuid;
 import android.content.Context;
 import android.content.Intent;
@@ -55,6 +53,7 @@
 
     private static final int EVENT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY = 1;
     private static final int EVENT_RESTART_BLUETOOTH = 2;
+    private static final int EVENT_PAIRING_CONSENT_DELAYED_ACCEPT = 3;
 
     // The time (in millisecs) to delay the pairing attempt after the first
     // auto pairing attempt fails. We use an exponential delay with
@@ -69,9 +68,10 @@
     private final Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
+            String address = null;
             switch (msg.what) {
             case EVENT_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY:
-                String address = (String)msg.obj;
+                address = (String)msg.obj;
                 if (address != null) {
                     mBluetoothService.createBond(address);
                     return;
@@ -80,6 +80,12 @@
             case EVENT_RESTART_BLUETOOTH:
                 mBluetoothService.restart();
                 break;
+            case EVENT_PAIRING_CONSENT_DELAYED_ACCEPT:
+                address = (String)msg.obj;
+                if (address != null) {
+                    mBluetoothService.setPairingConfirmation(address, true);
+                }
+                break;
             }
         }
     };
@@ -141,11 +147,12 @@
             rssiValue = Short.MIN_VALUE;
         }
         if (classValue != null) {
-            Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_FOUND_ACTION);
-            intent.putExtra(BluetoothIntent.DEVICE, mAdapter.getRemoteDevice(address));
-            intent.putExtra(BluetoothIntent.CLASS, Integer.valueOf(classValue));
-            intent.putExtra(BluetoothIntent.RSSI, rssiValue);
-            intent.putExtra(BluetoothIntent.NAME, name);
+            Intent intent = new Intent(BluetoothDevice.ACTION_FOUND);
+            intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
+            intent.putExtra(BluetoothDevice.EXTRA_CLASS,
+                    new BluetoothClass(Integer.valueOf(classValue)));
+            intent.putExtra(BluetoothDevice.EXTRA_RSSI, rssiValue);
+            intent.putExtra(BluetoothDevice.EXTRA_NAME, name);
 
             mContext.sendBroadcast(intent, BLUETOOTH_PERM);
         } else {
@@ -162,14 +169,25 @@
     }
 
     private void onDeviceDisappeared(String address) {
-        Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_DISAPPEARED_ACTION);
-        intent.putExtra(BluetoothIntent.DEVICE, mAdapter.getRemoteDevice(address));
+        Intent intent = new Intent(BluetoothDevice.ACTION_DISAPPEARED);
+        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
+        mContext.sendBroadcast(intent, BLUETOOTH_PERM);
+    }
+
+    private void onDeviceDisconnectRequested(String deviceObjectPath) {
+        String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
+        if (address == null) {
+            Log.e(TAG, "onDeviceDisconnectRequested: Address of the remote device in null");
+            return;
+        }
+        Intent intent = new Intent(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED);
+        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
         mContext.sendBroadcast(intent, BLUETOOTH_PERM);
     }
 
     private void onCreatePairedDeviceResult(String address, int result) {
         address = address.toUpperCase();
-        if (result == BluetoothError.SUCCESS) {
+        if (result == BluetoothDevice.BOND_SUCCESS) {
             mBluetoothService.getBondState().setBondState(address, BluetoothDevice.BOND_BONDED);
             if (mBluetoothService.getBondState().isAutoPairingAttemptsInProgress(address)) {
                 mBluetoothService.getBondState().clearPinAttempts(address);
@@ -183,7 +201,7 @@
             pairingAttempt(address, result);
         } else {
             mBluetoothService.getBondState().setBondState(address,
-                                                          BluetoothDevice.BOND_NOT_BONDED, result);
+                                                          BluetoothDevice.BOND_NONE, result);
             if (mBluetoothService.getBondState().isAutoPairingAttemptsInProgress(address)) {
                 mBluetoothService.getBondState().clearPinAttempts(address);
             }
@@ -203,7 +221,7 @@
                     MAX_AUTO_PAIRING_FAILURE_ATTEMPT_DELAY) {
             mBluetoothService.getBondState().clearPinAttempts(address);
             mBluetoothService.getBondState().setBondState(address,
-                    BluetoothDevice.BOND_NOT_BONDED, result);
+                    BluetoothDevice.BOND_NONE, result);
             return;
         }
 
@@ -214,7 +232,7 @@
         if (!postResult) {
             mBluetoothService.getBondState().clearPinAttempts(address);
             mBluetoothService.getBondState().setBondState(address,
-                    BluetoothDevice.BOND_NOT_BONDED, result);
+                    BluetoothDevice.BOND_NONE, result);
             return;
         }
         mBluetoothService.getBondState().attempt(address);
@@ -229,6 +247,7 @@
                 addDevice(address, properties);
             }
         }
+        mBluetoothService.getBondState().setBondState(address, BluetoothDevice.BOND_BONDING);
         return;
     }
 
@@ -236,14 +255,19 @@
         String address = mBluetoothService.getAddressFromObjectPath(deviceObjectPath);
         if (address != null)
             mBluetoothService.getBondState().setBondState(address.toUpperCase(),
-                    BluetoothDevice.BOND_NOT_BONDED, BluetoothDevice.UNBOND_REASON_REMOVED);
+                    BluetoothDevice.BOND_NONE, BluetoothDevice.UNBOND_REASON_REMOVED);
     }
 
     /*package*/ void onPropertyChanged(String[] propValues) {
+        if (mBluetoothService.isAdapterPropertiesEmpty()) {
+            // We have got a property change before
+            // we filled up our cache.
+            mBluetoothService.getAllProperties();
+        }
         String name = propValues[0];
         if (name.equals("Name")) {
-            Intent intent = new Intent(BluetoothIntent.NAME_CHANGED_ACTION);
-            intent.putExtra(BluetoothIntent.NAME, propValues[1]);
+            Intent intent = new Intent(BluetoothDevice.ACTION_NAME_CHANGED);
+            intent.putExtra(BluetoothDevice.EXTRA_NAME, propValues[1]);
             mContext.sendBroadcast(intent, BLUETOOTH_PERM);
             mBluetoothService.setProperty(name, propValues[1]);
         } else if (name.equals("Pairable") || name.equals("Discoverable")) {
@@ -260,8 +284,8 @@
                     pairable.equals("true"),
                     discoverable.equals("true"));
             if (mode >= 0) {
-                Intent intent = new Intent(BluetoothIntent.SCAN_MODE_CHANGED_ACTION);
-                intent.putExtra(BluetoothIntent.SCAN_MODE, mode);
+                Intent intent = new Intent(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
+                intent.putExtra(BluetoothAdapter.EXTRA_SCAN_MODE, mode);
                 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
                 mContext.sendBroadcast(intent, BLUETOOTH_PERM);
             }
@@ -270,12 +294,12 @@
             Intent intent;
             if (propValues[1].equals("true")) {
                 mBluetoothService.setIsDiscovering(true);
-                intent = new Intent(BluetoothIntent.DISCOVERY_STARTED_ACTION);
+                intent = new Intent(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
             } else {
                 // Stop the discovery.
                 mBluetoothService.cancelDiscovery();
                 mBluetoothService.setIsDiscovering(false);
-                intent = new Intent(BluetoothIntent.DISCOVERY_COMPLETED_ACTION);
+                intent = new Intent(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
             }
             mContext.sendBroadcast(intent, BLUETOOTH_PERM);
             mBluetoothService.setProperty(name, propValues[1]);
@@ -308,25 +332,26 @@
         }
         BluetoothDevice device = mAdapter.getRemoteDevice(address);
         if (name.equals("Name")) {
-            Intent intent = new Intent(BluetoothIntent.REMOTE_NAME_UPDATED_ACTION);
-            intent.putExtra(BluetoothIntent.DEVICE, device);
-            intent.putExtra(BluetoothIntent.NAME, propValues[1]);
+            Intent intent = new Intent(BluetoothDevice.ACTION_NAME_CHANGED);
+            intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
+            intent.putExtra(BluetoothDevice.EXTRA_NAME, propValues[1]);
             mContext.sendBroadcast(intent, BLUETOOTH_PERM);
             mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
         } else if (name.equals("Class")) {
-            Intent intent = new Intent(BluetoothIntent.REMOTE_DEVICE_CLASS_UPDATED_ACTION);
-            intent.putExtra(BluetoothIntent.DEVICE, device);
-            intent.putExtra(BluetoothIntent.CLASS, propValues[1]);
+            Intent intent = new Intent(BluetoothDevice.ACTION_CLASS_CHANGED);
+            intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
+            intent.putExtra(BluetoothDevice.EXTRA_CLASS,
+                    new BluetoothClass(Integer.valueOf(propValues[1])));
             mContext.sendBroadcast(intent, BLUETOOTH_PERM);
             mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
         } else if (name.equals("Connected")) {
             Intent intent = null;
             if (propValues[1].equals("true")) {
-                intent = new Intent(BluetoothIntent.REMOTE_DEVICE_CONNECTED_ACTION);
+                intent = new Intent(BluetoothDevice.ACTION_ACL_CONNECTED);
             } else {
-                intent = new Intent(BluetoothIntent.REMOTE_DEVICE_DISCONNECTED_ACTION);
+                intent = new Intent(BluetoothDevice.ACTION_ACL_DISCONNECTED);
             }
-            intent.putExtra(BluetoothIntent.DEVICE, device);
+            intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
             mContext.sendBroadcast(intent, BLUETOOTH_PERM);
             mBluetoothService.setRemoteDeviceProperty(address, name, propValues[1]);
         } else if (name.equals("UUIDs")) {
@@ -346,7 +371,7 @@
                 mBluetoothService.getBondState().setBondState(address, BluetoothDevice.BOND_BONDED);
             } else {
                 mBluetoothService.getBondState().setBondState(address,
-                        BluetoothDevice.BOND_NOT_BONDED);
+                        BluetoothDevice.BOND_NONE);
                 mBluetoothService.setRemoteDeviceProperty(address, "Trusted", "false");
             }
         } else if (name.equals("Trusted")) {
@@ -366,7 +391,7 @@
         address = address.toUpperCase();
         mPasskeyAgentRequestData.put(address, new Integer(nativeData));
 
-        if (mBluetoothService.getBluetoothState() == BluetoothAdapter.BLUETOOTH_STATE_TURNING_OFF) {
+        if (mBluetoothService.getBluetoothState() == BluetoothAdapter.STATE_TURNING_OFF) {
             // shutdown path
             mBluetoothService.cancelPairingUserInput(address);
             return null;
@@ -374,15 +399,40 @@
         return address;
     }
 
-    private void onRequestConfirmation(String objectPath, int passkey, int nativeData) {
+    private void onRequestPairingConsent(String objectPath, int nativeData) {
         String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
         if (address == null) return;
 
-        Intent intent = new Intent(BluetoothIntent.PAIRING_REQUEST_ACTION);
-        intent.putExtra(BluetoothIntent.DEVICE, mAdapter.getRemoteDevice(address));
-        intent.putExtra(BluetoothIntent.PASSKEY, passkey);
-        intent.putExtra(BluetoothIntent.PAIRING_VARIANT,
-                BluetoothDevice.PAIRING_VARIANT_CONFIRMATION);
+        /* The link key will not be stored if the incoming request has MITM
+         * protection switched on. Unfortunately, some devices have MITM
+         * switched on even though their capabilities are NoInputNoOutput,
+         * so we may get this request many times. Also if we respond immediately,
+         * the other end is unable to handle it. Delay sending the message.
+         */
+        if (mBluetoothService.getBondState().getBondState(address) == BluetoothDevice.BOND_BONDED) {
+            Message message = mHandler.obtainMessage(EVENT_PAIRING_CONSENT_DELAYED_ACCEPT);
+            message.obj = address;
+            mHandler.sendMessageDelayed(message, 1500);
+            return;
+        }
+
+        Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
+        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
+        intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
+                        BluetoothDevice.PAIRING_VARIANT_CONSENT);
+        mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
+        return;
+    }
+
+    private void onRequestPasskeyConfirmation(String objectPath, int passkey, int nativeData) {
+        String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
+        if (address == null) return;
+
+        Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
+        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
+        intent.putExtra(BluetoothDevice.EXTRA_PASSKEY, passkey);
+        intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
+                BluetoothDevice.PAIRING_VARIANT_PASSKEY_CONFIRMATION);
         mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
         return;
     }
@@ -391,9 +441,10 @@
         String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
         if (address == null) return;
 
-        Intent intent = new Intent(BluetoothIntent.PAIRING_REQUEST_ACTION);
-        intent.putExtra(BluetoothIntent.DEVICE, mAdapter.getRemoteDevice(address));
-        intent.putExtra(BluetoothIntent.PAIRING_VARIANT, BluetoothDevice.PAIRING_VARIANT_PASSKEY);
+        Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
+        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
+        intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
+                BluetoothDevice.PAIRING_VARIANT_PASSKEY);
         mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
         return;
     }
@@ -405,10 +456,10 @@
         if (mBluetoothService.getBondState().getBondState(address) ==
                 BluetoothDevice.BOND_BONDING) {
             // we initiated the bonding
-            int btClass = mBluetoothService.getRemoteClass(address);
+            BluetoothClass btClass = new BluetoothClass(mBluetoothService.getRemoteClass(address));
 
             // try 0000 once if the device looks dumb
-            switch (BluetoothClass.Device.getDevice(btClass)) {
+            switch (btClass.getDeviceClass()) {
             case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
             case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
             case BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES:
@@ -423,13 +474,25 @@
                 }
            }
         }
-        Intent intent = new Intent(BluetoothIntent.PAIRING_REQUEST_ACTION);
-        intent.putExtra(BluetoothIntent.DEVICE, mAdapter.getRemoteDevice(address));
-        intent.putExtra(BluetoothIntent.PAIRING_VARIANT, BluetoothDevice.PAIRING_VARIANT_PIN);
+        Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
+        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
+        intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, BluetoothDevice.PAIRING_VARIANT_PIN);
         mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
         return;
     }
 
+    private void onDisplayPasskey(String objectPath, int passkey, int nativeData) {
+        String address = checkPairingRequestAndGetAddress(objectPath, nativeData);
+        if (address == null) return;
+
+        Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_REQUEST);
+        intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
+        intent.putExtra(BluetoothDevice.EXTRA_PASSKEY, passkey);
+        intent.putExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
+                        BluetoothDevice.PAIRING_VARIANT_DISPLAY_PASSKEY);
+        mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
+    }
+
     private boolean onAgentAuthorize(String objectPath, String deviceUuid) {
         String address = mBluetoothService.getAddressFromObjectPath(objectPath);
         if (address == null) {
@@ -460,7 +523,7 @@
     }
 
     private void onAgentCancel() {
-        Intent intent = new Intent(BluetoothIntent.PAIRING_CANCEL_ACTION);
+        Intent intent = new Intent(BluetoothDevice.ACTION_PAIRING_CANCEL);
         mContext.sendBroadcast(intent, BLUETOOTH_ADMIN_PERM);
         return;
     }
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index b168850..6ce0f5f 100644
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -27,9 +27,7 @@
 import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothError;
 import android.bluetooth.BluetoothHeadset;
-import android.bluetooth.BluetoothIntent;
 import android.bluetooth.IBluetooth;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
@@ -102,7 +100,7 @@
             disableNative();
         }
 
-        mBluetoothState = BluetoothAdapter.BLUETOOTH_STATE_OFF;
+        mBluetoothState = BluetoothAdapter.STATE_OFF;
         mIsDiscovering = false;
         mAdapterProperties = new HashMap<String, String>();
         mDeviceProperties = new HashMap<String, Map<String,String>>();
@@ -128,7 +126,7 @@
 
     public boolean isEnabled() {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
-        return mBluetoothState == BluetoothAdapter.BLUETOOTH_STATE_ON;
+        return mBluetoothState == BluetoothAdapter.STATE_ON;
     }
 
     public int getBluetoothState() {
@@ -153,9 +151,9 @@
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
 
         switch (mBluetoothState) {
-        case BluetoothAdapter.BLUETOOTH_STATE_OFF:
+        case BluetoothAdapter.STATE_OFF:
             return true;
-        case BluetoothAdapter.BLUETOOTH_STATE_ON:
+        case BluetoothAdapter.STATE_ON:
             break;
         default:
             return false;
@@ -163,7 +161,7 @@
         if (mEnableThread != null && mEnableThread.isAlive()) {
             return false;
         }
-        setBluetoothState(BluetoothAdapter.BLUETOOTH_STATE_TURNING_OFF);
+        setBluetoothState(BluetoothAdapter.STATE_TURNING_OFF);
 
         // Allow 3 seconds for profiles to gracefully disconnect
         // TODO: Introduce a callback mechanism so that each profile can notify
@@ -175,7 +173,7 @@
 
 
     private synchronized void finishDisable(boolean saveSetting) {
-        if (mBluetoothState != BluetoothAdapter.BLUETOOTH_STATE_TURNING_OFF) {
+        if (mBluetoothState != BluetoothAdapter.STATE_TURNING_OFF) {
             return;
         }
         mEventLoop.stop();
@@ -184,13 +182,13 @@
 
         // mark in progress bondings as cancelled
         for (String address : mBondState.listInState(BluetoothDevice.BOND_BONDING)) {
-            mBondState.setBondState(address, BluetoothDevice.BOND_NOT_BONDED,
+            mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
                                     BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
         }
 
         // update mode
-        Intent intent = new Intent(BluetoothIntent.SCAN_MODE_CHANGED_ACTION);
-        intent.putExtra(BluetoothIntent.SCAN_MODE, BluetoothAdapter.SCAN_MODE_NONE);
+        Intent intent = new Intent(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
+        intent.putExtra(BluetoothAdapter.EXTRA_SCAN_MODE, BluetoothAdapter.SCAN_MODE_NONE);
         mContext.sendBroadcast(intent, BLUETOOTH_PERM);
 
         mIsDiscovering = false;
@@ -200,7 +198,7 @@
             persistBluetoothOnSetting(false);
         }
 
-        setBluetoothState(BluetoothAdapter.BLUETOOTH_STATE_OFF);
+        setBluetoothState(BluetoothAdapter.STATE_OFF);
 
         // Log bluetooth off to battery stats.
         long ident = Binder.clearCallingIdentity();
@@ -237,13 +235,13 @@
         if (mIsAirplaneSensitive && isAirplaneModeOn()) {
             return false;
         }
-        if (mBluetoothState != BluetoothAdapter.BLUETOOTH_STATE_OFF) {
+        if (mBluetoothState != BluetoothAdapter.STATE_OFF) {
             return false;
         }
         if (mEnableThread != null && mEnableThread.isAlive()) {
             return false;
         }
-        setBluetoothState(BluetoothAdapter.BLUETOOTH_STATE_TURNING_ON);
+        setBluetoothState(BluetoothAdapter.STATE_TURNING_ON);
         mEnableThread = new EnableThread(saveSetting);
         mEnableThread.start();
         return true;
@@ -251,7 +249,7 @@
 
     /** Forcibly restart Bluetooth if it is on */
     /* package */ synchronized void restart() {
-        if (mBluetoothState != BluetoothAdapter.BLUETOOTH_STATE_ON) {
+        if (mBluetoothState != BluetoothAdapter.STATE_ON) {
             return;
         }
         mRestart = true;
@@ -267,9 +265,9 @@
 
         if (DBG) log("Bluetooth state " + mBluetoothState + " -> " + state);
 
-        Intent intent = new Intent(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION);
-        intent.putExtra(BluetoothIntent.BLUETOOTH_PREVIOUS_STATE, mBluetoothState);
-        intent.putExtra(BluetoothIntent.BLUETOOTH_STATE, state);
+        Intent intent = new Intent(BluetoothAdapter.ACTION_STATE_CHANGED);
+        intent.putExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, mBluetoothState);
+        intent.putExtra(BluetoothAdapter.EXTRA_STATE, state);
         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
 
         mBluetoothState = state;
@@ -357,8 +355,8 @@
             mEnableThread = null;
 
             setBluetoothState(res ?
-                              BluetoothAdapter.BLUETOOTH_STATE_ON :
-                              BluetoothAdapter.BLUETOOTH_STATE_OFF);
+                              BluetoothAdapter.STATE_ON :
+                              BluetoothAdapter.STATE_OFF);
 
             if (res) {
                 // Update mode
@@ -411,7 +409,7 @@
                         ));
 
         public synchronized void loadBondState() {
-            if (mBluetoothState != BluetoothAdapter.BLUETOOTH_STATE_TURNING_ON) {
+            if (mBluetoothState != BluetoothAdapter.STATE_TURNING_ON) {
                 return;
             }
             String []bonds = null;
@@ -442,17 +440,17 @@
             }
             if (DBG) log(address + " bond state " + oldState + " -> " + state + " (" +
                          reason + ")");
-            Intent intent = new Intent(BluetoothIntent.BOND_STATE_CHANGED_ACTION);
-            intent.putExtra(BluetoothIntent.DEVICE, mAdapter.getRemoteDevice(address));
-            intent.putExtra(BluetoothIntent.BOND_STATE, state);
-            intent.putExtra(BluetoothIntent.BOND_PREVIOUS_STATE, oldState);
-            if (state == BluetoothDevice.BOND_NOT_BONDED) {
+            Intent intent = new Intent(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
+            intent.putExtra(BluetoothDevice.EXTRA_DEVICE, mAdapter.getRemoteDevice(address));
+            intent.putExtra(BluetoothDevice.EXTRA_BOND_STATE, state);
+            intent.putExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, oldState);
+            if (state == BluetoothDevice.BOND_NONE) {
                 if (reason <= 0) {
                     Log.w(TAG, "setBondState() called to unbond device, but reason code is " +
                           "invalid. Overriding reason code with BOND_RESULT_REMOVED");
                     reason = BluetoothDevice.UNBOND_REASON_REMOVED;
                 }
-                intent.putExtra(BluetoothIntent.REASON, reason);
+                intent.putExtra(BluetoothDevice.EXTRA_REASON, reason);
                 mState.remove(address);
             } else {
                 mState.put(address, state);
@@ -471,7 +469,7 @@
         public synchronized int getBondState(String address) {
             Integer state = mState.get(address);
             if (state == null) {
-                return BluetoothDevice.BOND_NOT_BONDED;
+                return BluetoothDevice.BOND_NONE;
             }
             return state.intValue();
         }
@@ -527,7 +525,7 @@
 
     private static String toBondStateString(int bondState) {
         switch (bondState) {
-        case BluetoothDevice.BOND_NOT_BONDED:
+        case BluetoothDevice.BOND_NONE:
             return "not bonded";
         case BluetoothDevice.BOND_BONDING:
             return "bonding";
@@ -538,6 +536,10 @@
         }
     }
 
+    /*package*/ synchronized boolean isAdapterPropertiesEmpty() {
+        return mAdapterProperties.isEmpty();
+    }
+
     /*package*/synchronized void getAllProperties() {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         mAdapterProperties.clear();
@@ -629,17 +631,24 @@
     public synchronized boolean setScanMode(int mode) {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
                                                 "Need BLUETOOTH_ADMIN permission");
-        boolean pairable = false, discoverable = false;
-        String modeString = scanModeToBluezString(mode);
-        if (modeString.equals("off")) {
+        boolean pairable = false;
+        boolean discoverable = false;
+        switch (mode) {
+        case BluetoothAdapter.SCAN_MODE_NONE:
             pairable = false;
             discoverable = false;
-        } else if (modeString.equals("pariable")) {
+            break;
+        case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
             pairable = true;
             discoverable = false;
-        } else if (modeString.equals("discoverable")) {
+            break;
+        case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
             pairable = true;
             discoverable = true;
+            break;
+        default:
+            Log.w(TAG, "Requested invalid scan mode " + mode);
+            return false;
         }
         setPropertyBoolean("Pairable", pairable);
         setPropertyBoolean("Discoverable", discoverable);
@@ -677,7 +686,7 @@
      */
     public synchronized String getRemoteName(String address) {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
-        if (!BluetoothDevice.checkBluetoothAddress(address)) {
+        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
             return null;
         }
         Map <String, String> properties = mDeviceProperties.get(address);
@@ -705,7 +714,7 @@
     public synchronized int getScanMode() {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
         if (!isEnabled())
-            return BluetoothError.ERROR;
+            return BluetoothAdapter.SCAN_MODE_NONE;
 
         boolean pairable = getProperty("Pairable").equals("true");
         boolean discoverable = getProperty("Discoverable").equals("true");
@@ -739,7 +748,7 @@
     public synchronized boolean createBond(String address) {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
                                                 "Need BLUETOOTH_ADMIN permission");
-        if (!BluetoothDevice.checkBluetoothAddress(address)) {
+        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
             return false;
         }
         address = address.toUpperCase();
@@ -754,7 +763,7 @@
         // Check for bond state only if we are not performing auto
         // pairing exponential back-off attempts.
         if (!mBondState.isAutoPairingAttemptsInProgress(address) &&
-                mBondState.getBondState(address) != BluetoothDevice.BOND_NOT_BONDED) {
+                mBondState.getBondState(address) != BluetoothDevice.BOND_NONE) {
             log("Ignoring createBond(): this device is already bonding or bonded");
             return false;
         }
@@ -770,7 +779,7 @@
     public synchronized boolean cancelBondProcess(String address) {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
                                                 "Need BLUETOOTH_ADMIN permission");
-        if (!BluetoothDevice.checkBluetoothAddress(address)) {
+        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
             return false;
         }
         address = address.toUpperCase();
@@ -778,7 +787,7 @@
             return false;
         }
 
-        mBondState.setBondState(address, BluetoothDevice.BOND_NOT_BONDED,
+        mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
                                 BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
         cancelDeviceCreationNative(address);
         return true;
@@ -787,7 +796,7 @@
     public synchronized boolean removeBond(String address) {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
                                                 "Need BLUETOOTH_ADMIN permission");
-        if (!BluetoothDevice.checkBluetoothAddress(address)) {
+        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
             return false;
         }
         return removeDeviceNative(getObjectPathFromAddress(address));
@@ -800,8 +809,8 @@
 
     public synchronized int getBondState(String address) {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
-        if (!BluetoothDevice.checkBluetoothAddress(address)) {
-            return BluetoothError.ERROR;
+        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
+            return BluetoothDevice.ERROR;
         }
         return mBondState.getBondState(address.toUpperCase());
     }
@@ -890,7 +899,7 @@
      * @return boolean to indicate operation success or fail
      */
     public synchronized boolean setTrust(String address, boolean value) {
-        if (!BluetoothDevice.checkBluetoothAddress(address)) {
+        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
             mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
             return false;
         }
@@ -907,7 +916,7 @@
      * @return boolean to indicate trust or untrust state
      */
     public synchronized boolean getTrustState(String address) {
-        if (!BluetoothDevice.checkBluetoothAddress(address)) {
+        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
             mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
             return false;
         }
@@ -931,7 +940,7 @@
      *         classes.
      */
     public synchronized int getRemoteClass(String address) {
-        if (!BluetoothDevice.checkBluetoothAddress(address)) {
+        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
             mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
             return BluetoothClass.ERROR;
         }
@@ -953,7 +962,7 @@
      */
     public synchronized String[] getRemoteUuids(String address) {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
-        if (!BluetoothDevice.checkBluetoothAddress(address)) {
+        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
             return null;
         }
         String value = getRemoteDeviceProperty(address, "UUIDs");
@@ -974,8 +983,8 @@
      */
     public int getRemoteServiceChannel(String address, String uuid) {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
-        if (!BluetoothDevice.checkBluetoothAddress(address)) {
-            return BluetoothError.ERROR_IPC;
+        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
+            return BluetoothDevice.ERROR;
         }
         return getDeviceServiceChannelNative(getObjectPathFromAddress(address), uuid, 0x0004);
     }
@@ -984,7 +993,7 @@
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
                                                 "Need BLUETOOTH_ADMIN permission");
         if (pin == null || pin.length <= 0 || pin.length > 16 ||
-            !BluetoothDevice.checkBluetoothAddress(address)) {
+            !BluetoothAdapter.checkBluetoothAddress(address)) {
             return false;
         }
         address = address.toUpperCase();
@@ -1009,7 +1018,7 @@
     public synchronized boolean setPasskey(String address, int passkey) {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
                                                 "Need BLUETOOTH_ADMIN permission");
-        if (passkey < 0 || passkey > 999999 || !BluetoothDevice.checkBluetoothAddress(address)) {
+        if (passkey < 0 || passkey > 999999 || !BluetoothAdapter.checkBluetoothAddress(address)) {
             return false;
         }
         address = address.toUpperCase();
@@ -1040,10 +1049,10 @@
     public synchronized boolean cancelPairingUserInput(String address) {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
                                                 "Need BLUETOOTH_ADMIN permission");
-        if (!BluetoothDevice.checkBluetoothAddress(address)) {
+        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
             return false;
         }
-        mBondState.setBondState(address, BluetoothDevice.BOND_NOT_BONDED,
+        mBondState.setBondState(address, BluetoothDevice.BOND_NONE,
                 BluetoothDevice.UNBOND_REASON_AUTH_CANCELED);
         address = address.toUpperCase();
         Integer data = mEventLoop.getPasskeyAgentRequestData().remove(address);
@@ -1099,16 +1108,16 @@
         pw.println("\nmIsAirplaneSensitive = " + mIsAirplaneSensitive + "\n");
 
         switch(mBluetoothState) {
-        case BluetoothAdapter.BLUETOOTH_STATE_OFF:
+        case BluetoothAdapter.STATE_OFF:
             pw.println("\nBluetooth OFF\n");
             return;
-        case BluetoothAdapter.BLUETOOTH_STATE_TURNING_ON:
+        case BluetoothAdapter.STATE_TURNING_ON:
             pw.println("\nBluetooth TURNING ON\n");
             return;
-        case BluetoothAdapter.BLUETOOTH_STATE_TURNING_OFF:
+        case BluetoothAdapter.STATE_TURNING_OFF:
             pw.println("\nBluetooth TURNING OFF\n");
             return;
-        case BluetoothAdapter.BLUETOOTH_STATE_ON:
+        case BluetoothAdapter.STATE_ON:
             pw.println("\nBluetooth ON\n");
         }
 
@@ -1257,5 +1266,4 @@
     private native boolean setPairingConfirmationNative(String address, boolean confirm,
             int nativeData);
     private native boolean setDevicePropertyBooleanNative(String objectPath, String key, int value);
-
 }
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 95b5730..e5659d5 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -22,7 +22,10 @@
 
 import android.app.Service;
 import android.app.WallpaperManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.graphics.Rect;
 import android.os.IBinder;
 import android.os.Message;
@@ -88,6 +91,8 @@
         
         boolean mInitializing = true;
         boolean mVisible;
+        boolean mScreenOn = true;
+        boolean mReportedVisible;
         boolean mDestroyed;
         
         // Current window state.
@@ -117,6 +122,19 @@
         float mPendingYOffset;
         MotionEvent mPendingMove;
         
+        final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                if (Intent.ACTION_SCREEN_ON.equals(intent.getAction())) {
+                    mScreenOn = true;
+                    reportVisibility();
+                } else if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) {
+                    mScreenOn = false;
+                    reportVisibility();
+                }
+            }
+        };
+        
         final BaseSurfaceHolder mSurfaceHolder = new BaseSurfaceHolder() {
 
             @Override
@@ -239,7 +257,7 @@
          * {@link #onVisibilityChanged(boolean)}.
          */
         public boolean isVisible() {
-            return mVisible;
+            return mReportedVisible;
         }
         
         /**
@@ -489,6 +507,11 @@
             mSession = ViewRoot.getWindowSession(getMainLooper());
             mWindow.setSession(mSession);
             
+            IntentFilter filter = new IntentFilter();
+            filter.addAction(Intent.ACTION_SCREEN_ON);
+            filter.addAction(Intent.ACTION_SCREEN_OFF);
+            registerReceiver(mReceiver, filter);
+            
             if (DEBUG) Log.v(TAG, "onCreate(): " + this);
             onCreate(mSurfaceHolder);
             
@@ -505,11 +528,19 @@
         }
         
         void doVisibilityChanged(boolean visible) {
+            mVisible = visible;
+            reportVisibility();
+        }
+        
+        void reportVisibility() {
             if (!mDestroyed) {
-                mVisible = visible;
-                if (DEBUG) Log.v(TAG, "onVisibilityChanged(" + visible
-                        + "): " + this);
-                onVisibilityChanged(visible);
+                boolean visible = mVisible && mScreenOn;
+                if (mReportedVisible != visible) {
+                    mReportedVisible = visible;
+                    if (DEBUG) Log.v(TAG, "onVisibilityChanged(" + visible
+                            + "): " + this);
+                    onVisibilityChanged(visible);
+                }
             }
         }
         
@@ -562,6 +593,8 @@
             if (DEBUG) Log.v(TAG, "onDestroy(): " + this);
             onDestroy();
             
+            unregisterReceiver(mReceiver);
+            
             if (mCreated) {
                 try {
                     mSession.remove(mWindow);
diff --git a/core/java/android/syncml/pim/PropertyNode.java b/core/java/android/syncml/pim/PropertyNode.java
index 983ecb8..3a5c994 100644
--- a/core/java/android/syncml/pim/PropertyNode.java
+++ b/core/java/android/syncml/pim/PropertyNode.java
@@ -28,6 +28,7 @@
 import java.util.Map.Entry;
 import java.util.regex.Pattern;
 
+@Deprecated
 public class PropertyNode {
 
     public String propName;
diff --git a/core/java/android/syncml/pim/VBuilder.java b/core/java/android/syncml/pim/VBuilder.java
index 4528645..b6cb674 100644
--- a/core/java/android/syncml/pim/VBuilder.java
+++ b/core/java/android/syncml/pim/VBuilder.java
@@ -18,6 +18,7 @@
 
 import java.util.List;
 
+@Deprecated
 public interface VBuilder {
     void start();
 
diff --git a/core/java/android/syncml/pim/VBuilderCollection.java b/core/java/android/syncml/pim/VBuilderCollection.java
index f09c1c4..06e3100 100644
--- a/core/java/android/syncml/pim/VBuilderCollection.java
+++ b/core/java/android/syncml/pim/VBuilderCollection.java
@@ -19,6 +19,7 @@
 import java.util.Collection;
 import java.util.List;
 
+@Deprecated
 public class VBuilderCollection implements VBuilder {
 
     private final Collection<VBuilder> mVBuilderCollection;
diff --git a/core/java/android/syncml/pim/VDataBuilder.java b/core/java/android/syncml/pim/VDataBuilder.java
index f6e5b65..db8a299 100644
--- a/core/java/android/syncml/pim/VDataBuilder.java
+++ b/core/java/android/syncml/pim/VDataBuilder.java
@@ -36,6 +36,7 @@
  * VNode: standy by a vcard instance.
  * PropertyNode: standy by a property line of a card.
  */
+@Deprecated
 public class VDataBuilder implements VBuilder {
     static private String LOG_TAG = "VDATABuilder"; 
     
diff --git a/core/java/android/syncml/pim/VNode.java b/core/java/android/syncml/pim/VNode.java
index 9015415..378a9d1 100644
--- a/core/java/android/syncml/pim/VNode.java
+++ b/core/java/android/syncml/pim/VNode.java
@@ -18,6 +18,7 @@
 
 import java.util.ArrayList;
 
+@Deprecated
 public class VNode {
 
     public String VName;
diff --git a/core/java/android/syncml/pim/VParser.java b/core/java/android/syncml/pim/VParser.java
index 57c5f7a..14d2875 100644
--- a/core/java/android/syncml/pim/VParser.java
+++ b/core/java/android/syncml/pim/VParser.java
@@ -25,6 +25,7 @@
  * This interface is used to parse the V format files, such as VCard & VCal
  *
  */
+@Deprecated
 abstract public class VParser {
     // Assume that "iso-8859-1" is able to map "all" 8bit characters to some unicode and
     // decode the unicode to the original charset. If not, this setting will cause some bug. 
diff --git a/core/java/android/syncml/pim/vcalendar/CalendarStruct.java b/core/java/android/syncml/pim/vcalendar/CalendarStruct.java
deleted file mode 100644
index 3388ada..0000000
--- a/core/java/android/syncml/pim/vcalendar/CalendarStruct.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.syncml.pim.vcalendar;
-
-import java.util.List;
-import java.util.ArrayList;
-
-/**
- * Same comment as ContactStruct.
- */
-public class CalendarStruct{
-
-    public static class EventStruct{
-        public String description;
-        public String dtend;
-        public String dtstart;
-        public String duration;
-        public String has_alarm;
-        public String last_date;
-        public String rrule;
-        public String status;
-        public String title;
-        public String event_location;
-        public String uid;
-        public List<String> reminderList;
-
-        public void addReminderList(String method){
-            if(reminderList == null)
-                reminderList = new ArrayList<String>();
-            reminderList.add(method);
-        }
-    }
-
-    public String timezone;
-    public List<EventStruct> eventList;
-
-    public void addEventList(EventStruct stru){
-        if(eventList == null)
-            eventList = new ArrayList<EventStruct>();
-        eventList.add(stru);
-    }
-}
diff --git a/core/java/android/syncml/pim/vcalendar/VCalComposer.java b/core/java/android/syncml/pim/vcalendar/VCalComposer.java
deleted file mode 100644
index 18b6719..0000000
--- a/core/java/android/syncml/pim/vcalendar/VCalComposer.java
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.syncml.pim.vcalendar;
-
-/**
- * vCalendar string composer class
- */
-public class VCalComposer {
-
-    public final static String VERSION_VCALENDAR10 = "vcalendar1.0";
-    public final static String VERSION_VCALENDAR20 = "vcalendar2.0";
-
-    public final static int VERSION_VCAL10_INT = 1;
-    public final static int VERSION_VCAL20_INT = 2;
-
-    private static String mNewLine = "\r\n";
-    private String mVersion = null;
-
-    public VCalComposer() {
-    }
-
-    /**
-     * Create a vCalendar String.
-     * @param struct see more from CalendarStruct class
-     * @param vcalversion MUST be VERSION_VCAL10 /VERSION_VCAL20
-     * @return vCalendar string
-     * @throws VcalException if version is invalid or create failed
-     */
-    public String createVCal(CalendarStruct struct, int vcalversion)
-                                                throws VCalException{
-
-        StringBuilder returnStr = new StringBuilder();
-
-        //Version check
-        if(vcalversion != 1 && vcalversion != 2)
-            throw new VCalException("version not match 1.0 or 2.0.");
-        if (vcalversion == 1)
-            mVersion = VERSION_VCALENDAR10;
-        else
-            mVersion = VERSION_VCALENDAR20;
-
-        //Build vCalendar:
-        returnStr.append("BEGIN:VCALENDAR").append(mNewLine);
-
-        if(vcalversion == VERSION_VCAL10_INT)
-            returnStr.append("VERSION:1.0").append(mNewLine);
-        else
-            returnStr.append("VERSION:2.0").append(mNewLine);
-
-        returnStr.append("PRODID:vCal ID default").append(mNewLine);
-
-        if(!isNull(struct.timezone)){
-            if(vcalversion == VERSION_VCAL10_INT)
-                returnStr.append("TZ:").append(struct.timezone).append(mNewLine);
-            else//down here MUST have
-                returnStr.append("BEGIN:VTIMEZONE").append(mNewLine).
-                    append("TZID:vCal default").append(mNewLine).
-                    append("BEGIN:STANDARD").append(mNewLine).
-                    append("DTSTART:16010101T000000").append(mNewLine).
-                    append("TZOFFSETFROM:").append(struct.timezone).append(mNewLine).
-                    append("TZOFFSETTO:").append(struct.timezone).append(mNewLine).
-                    append("END:STANDARD").append(mNewLine).
-                    append("END:VTIMEZONE").append(mNewLine);
-        }
-        //Build VEVNET
-        for(int i = 0; i < struct.eventList.size(); i++){
-            String str = buildEventStr( struct.eventList.get(i) );
-            returnStr.append(str);
-        }
-
-        //Build VTODO
-        //TODO
-
-        returnStr.append("END:VCALENDAR").append(mNewLine).append(mNewLine);
-
-        return returnStr.toString();
-    }
-
-    private String buildEventStr(CalendarStruct.EventStruct stru){
-
-        StringBuilder strbuf = new StringBuilder();
-
-        strbuf.append("BEGIN:VEVENT").append(mNewLine);
-
-        if(!isNull(stru.uid))
-            strbuf.append("UID:").append(stru.uid).append(mNewLine);
-
-        if(!isNull(stru.description))
-            strbuf.append("DESCRIPTION:").
-            append(foldingString(stru.description)).append(mNewLine);
-
-        if(!isNull(stru.dtend))
-            strbuf.append("DTEND:").append(stru.dtend).append(mNewLine);
-
-        if(!isNull(stru.dtstart))
-            strbuf.append("DTSTART:").append(stru.dtstart).append(mNewLine);
-
-        if(!isNull(stru.duration))
-            strbuf.append("DUE:").append(stru.duration).append(mNewLine);
-
-        if(!isNull(stru.event_location))
-            strbuf.append("LOCATION:").append(stru.event_location).append(mNewLine);
-
-        if(!isNull(stru.last_date))
-            strbuf.append("COMPLETED:").append(stru.last_date).append(mNewLine);
-
-        if(!isNull(stru.rrule))
-            strbuf.append("RRULE:").append(stru.rrule).append(mNewLine);
-
-        if(!isNull(stru.title))
-            strbuf.append("SUMMARY:").append(stru.title).append(mNewLine);
-
-        if(!isNull(stru.status)){
-            String stat = "TENTATIVE";
-            switch (Integer.parseInt(stru.status)){
-            case 0://Calendar.Calendars.STATUS_TENTATIVE
-                stat = "TENTATIVE";
-                break;
-            case 1://Calendar.Calendars.STATUS_CONFIRMED
-                stat = "CONFIRMED";
-                break;
-            case 2://Calendar.Calendars.STATUS_CANCELED
-                stat = "CANCELLED";
-                break;
-            }
-            strbuf.append("STATUS:").append(stat).append(mNewLine);
-        }
-        //Alarm
-        if(!isNull(stru.has_alarm)
-            && stru.reminderList != null
-            && stru.reminderList.size() > 0){
-
-            if (mVersion.equals(VERSION_VCALENDAR10)){
-                String prefix = "";
-                for(String method : stru.reminderList){
-                    switch (Integer.parseInt(method)){
-                    case 0:
-                        prefix = "DALARM";
-                        break;
-                    case 1:
-                        prefix = "AALARM";
-                        break;
-                    case 2:
-                        prefix = "MALARM";
-                        break;
-                    case 3:
-                    default:
-                        prefix = "DALARM";
-                        break;
-                    }
-                    strbuf.append(prefix).append(":default").append(mNewLine);
-                }
-            }else {//version 2.0 only support audio-method now.
-                strbuf.append("BEGIN:VALARM").append(mNewLine).
-                       append("ACTION:AUDIO").append(mNewLine).
-                       append("TRIGGER:-PT10M").append(mNewLine).
-                       append("END:VALARM").append(mNewLine);
-            }
-        }
-        strbuf.append("END:VEVENT").append(mNewLine);
-        return strbuf.toString();
-    }
-
-    /** Alter str to folding supported format. */
-    private String foldingString(String str){
-        return str.replaceAll("\r\n", "\n").replaceAll("\n", "\r\n ");
-    }
-
-    /** is null */
-    private boolean isNull(String str){
-        if(str == null || str.trim().equals(""))
-            return true;
-        return false;
-    }
-}
diff --git a/core/java/android/syncml/pim/vcalendar/VCalException.java b/core/java/android/syncml/pim/vcalendar/VCalException.java
deleted file mode 100644
index 48ea134..0000000
--- a/core/java/android/syncml/pim/vcalendar/VCalException.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.syncml.pim.vcalendar;
-
-public class VCalException extends java.lang.Exception{
-    // constructors
-
-    /**
-     * Constructs a VCalException object
-     */
-
-    public VCalException()
-    {
-    }
-
-    /**
-     * Constructs a VCalException object
-     *
-     * @param message the error message
-     */
-
-    public VCalException( String message )
-    {
-        super( message );
-    }
-
-}
diff --git a/core/java/android/syncml/pim/vcalendar/VCalParser.java b/core/java/android/syncml/pim/vcalendar/VCalParser.java
deleted file mode 100644
index bc2d598..0000000
--- a/core/java/android/syncml/pim/vcalendar/VCalParser.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.syncml.pim.vcalendar;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import android.util.Config;
-import android.util.Log;
-
-import android.syncml.pim.VDataBuilder;
-import android.syncml.pim.VParser;
-
-public class VCalParser{
-
-    private final static String TAG = "VCalParser";
-
-    public final static String VERSION_VCALENDAR10 = "vcalendar1.0";
-    public final static String VERSION_VCALENDAR20 = "vcalendar2.0";
-
-    private VParser mParser = null;
-    private String mVersion = null;
-
-    public VCalParser() {
-    }
-
-    public boolean parse(String vcalendarStr, VDataBuilder builder)
-            throws VCalException {
-
-        vcalendarStr = verifyVCal(vcalendarStr);
-        try{
-            boolean isSuccess = mParser.parse(
-                    new ByteArrayInputStream(vcalendarStr.getBytes()),
-                    "US-ASCII", builder);
-
-            if (!isSuccess) {
-                if (mVersion.equals(VERSION_VCALENDAR10)) {
-                    if(Config.LOGD)
-                        Log.d(TAG, "Parse failed for vCal 1.0 parser."
-                            + " Try to use 2.0 parser.");
-                    mVersion = VERSION_VCALENDAR20;
-                    return parse(vcalendarStr, builder);
-                }else
-                    throw new VCalException("parse failed.(even use 2.0 parser)");
-            }
-        }catch (IOException e){
-            throw new VCalException(e.getMessage());
-        }
-        return true;
-    }
-
-    /**
-     * Verify vCalendar string, and initialize mVersion according to it.
-     * */
-    private String verifyVCal(String vcalStr) {
-
-        //Version check
-        judgeVersion(vcalStr);
-
-        vcalStr = vcalStr.replaceAll("\r\n", "\n");
-        String[] strlist = vcalStr.split("\n");
-
-        StringBuilder replacedStr = new StringBuilder();
-
-        for (int i = 0; i < strlist.length; i++) {
-            if (strlist[i].indexOf(":") < 0) {
-                if (strlist[i].length() == 0 && strlist[i + 1].indexOf(":") > 0)
-                    replacedStr.append(strlist[i]).append("\r\n");
-                else
-                    replacedStr.append(" ").append(strlist[i]).append("\r\n");
-            } else
-                replacedStr.append(strlist[i]).append("\r\n");
-        }
-        if(Config.LOGD)Log.d(TAG, "After verify:\r\n" + replacedStr.toString());
-
-        return replacedStr.toString();
-    }
-
-    /**
-     * If version not given. Search from vcal string of the VERSION property.
-     * Then instance mParser to appropriate parser.
-     */
-    private void judgeVersion(String vcalStr) {
-
-        if (mVersion == null) {
-            int versionIdx = vcalStr.indexOf("\nVERSION:");
-
-            mVersion = VERSION_VCALENDAR10;
-
-            if (versionIdx != -1){
-                String versionStr = vcalStr.substring(
-                        versionIdx, vcalStr.indexOf("\n", versionIdx + 1));
-                if (versionStr.indexOf("2.0") > 0)
-                    mVersion = VERSION_VCALENDAR20;
-            }
-        }
-        if (mVersion.equals(VERSION_VCALENDAR10))
-            mParser = new VCalParser_V10();
-        if (mVersion.equals(VERSION_VCALENDAR20))
-            mParser = new VCalParser_V20();
-    }
-}
-
diff --git a/core/java/android/syncml/pim/vcalendar/VCalParser_V10.java b/core/java/android/syncml/pim/vcalendar/VCalParser_V10.java
deleted file mode 100644
index 1b251f3..0000000
--- a/core/java/android/syncml/pim/vcalendar/VCalParser_V10.java
+++ /dev/null
@@ -1,1628 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.syncml.pim.vcalendar;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import android.syncml.pim.VParser;
-
-public class VCalParser_V10 extends VParser {
-
-    /*
-     * The names of the properties whose value are not separated by ";"
-     */
-    private static final HashSet<String> mEvtPropNameGroup1 = new HashSet<String>(
-            Arrays.asList("ATTACH", "ATTENDEE", "DCREATED", "COMPLETED",
-                    "DESCRIPTION", "DUE", "DTEND", "EXRULE", "LAST-MODIFIED",
-                    "LOCATION", "RNUM", "PRIORITY", "RELATED-TO", "RRULE",
-                    "SEQUENCE", "DTSTART", "SUMMARY", "TRANSP", "URL", "UID",
-                    // above belong to simprop
-                    "CLASS", "STATUS"));
-
-    /*
-     * The names of properties whose value are separated by ";"
-     */
-    private static final HashSet<String> mEvtPropNameGroup2 = new HashSet<String>(
-            Arrays.asList("AALARM", "CATEGORIES", "DALARM", "EXDATE", "MALARM",
-                    "PALARM", "RDATE", "RESOURCES"));
-
-    private static final HashSet<String> mValueCAT = new HashSet<String>(Arrays
-            .asList("APPOINTMENT", "BUSINESS", "EDUCATION", "HOLIDAY",
-                    "MEETING", "MISCELLANEOUS", "PERSONAL", "PHONE CALL",
-                    "SICK DAY", "SPECIAL OCCASION", "TRAVEL", "VACATION"));
-
-    private static final HashSet<String> mValueCLASS = new HashSet<String>(Arrays
-            .asList("PUBLIC", "PRIVATE", "CONFIDENTIAL"));
-
-    private static final HashSet<String> mValueRES = new HashSet<String>(Arrays
-            .asList("CATERING", "CHAIRS", "EASEL", "PROJECTOR", "VCR",
-                    "VEHICLE"));
-
-    private static final HashSet<String> mValueSTAT = new HashSet<String>(Arrays
-            .asList("ACCEPTED", "NEEDS ACTION", "SENT", "TENTATIVE",
-                    "CONFIRMED", "DECLINED", "COMPLETED", "DELEGATED"));
-
-    /*
-     * The names of properties whose value can contain escape characters
-     */
-    private static final HashSet<String> mEscAllowedProps = new HashSet<String>(
-            Arrays.asList("DESCRIPTION", "SUMMARY", "AALARM", "DALARM",
-                    "MALARM", "PALARM"));
-
-    private static final HashMap<String, HashSet<String>> mSpecialValueSetMap =
-        new HashMap<String, HashSet<String>>();
-
-    static {
-        mSpecialValueSetMap.put("CATEGORIES", mValueCAT);
-        mSpecialValueSetMap.put("CLASS", mValueCLASS);
-        mSpecialValueSetMap.put("RESOURCES", mValueRES);
-        mSpecialValueSetMap.put("STATUS", mValueSTAT);
-    }
-
-    public VCalParser_V10() {
-    }
-
-    protected int parseVFile(int offset) {
-        return parseVCalFile(offset);
-    }
-
-    private int parseVCalFile(int offset) {
-        int ret = 0, sum = 0;
-
-        /* remove wsls */
-        while (PARSE_ERROR != (ret = parseWsls(offset))) {
-            offset += ret;
-            sum += ret;
-        }
-
-        ret = parseVCal(offset); // BEGIN:VCAL ... END:VCAL
-        if (PARSE_ERROR != ret) {
-            offset += ret;
-            sum += ret;
-        } else {
-            return PARSE_ERROR;
-        }
-
-        /* remove wsls */
-        while (PARSE_ERROR != (ret = parseWsls(offset))) {
-            offset += ret;
-            sum += ret;
-        }
-        return sum;
-    }
-
-    /**
-     * "BEGIN" [ws] ":" [ws] "VCALENDAR" [ws] 1*crlf calprop calentities [ws]
-     * *crlf "END" [ws] ":" [ws] "VCALENDAR" [ws] 1*CRLF
-     */
-    private int parseVCal(int offset) {
-        int ret = 0, sum = 0;
-
-        /* BEGIN */
-        ret = parseString(offset, "BEGIN", false);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-
-        // [ws]
-        ret = removeWs(offset);
-        offset += ret;
-        sum += ret;
-
-        // ":"
-        ret = parseString(offset, ":", false);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-
-        // [ws]
-        ret = removeWs(offset);
-        offset += ret;
-        sum += ret;
-
-        // "VCALENDAR
-        ret = parseString(offset, "VCALENDAR", false);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-        if (mBuilder != null) {
-            mBuilder.startRecord("VCALENDAR");
-        }
-
-        /* [ws] */
-        ret = removeWs(offset);
-        offset += ret;
-        sum += ret;
-
-        // 1*CRLF
-        ret = parseCrlf(offset);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-        while (PARSE_ERROR != (ret = parseCrlf(offset))) {
-            offset += ret;
-            sum += ret;
-        }
-
-        // calprop
-        ret = parseCalprops(offset);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-
-        // calentities
-        ret = parseCalentities(offset);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-
-        // [ws]
-        ret = removeWs(offset);
-        offset += ret;
-        sum += ret;
-
-        // *CRLF
-        while (PARSE_ERROR != (ret = parseCrlf(offset))) {
-            offset += ret;
-            sum += ret;
-        }
-
-        // "END"
-        ret = parseString(offset, "END", false);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-
-        // [ws]
-        ret = removeWs(offset);
-        offset += ret;
-        sum += ret;
-
-        // ":"
-        // ":"
-        ret = parseString(offset, ":", false);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-
-        // [ws]
-        ret = removeWs(offset);
-        offset += ret;
-        sum += ret;
-
-        // "VCALENDAR"
-        ret = parseString(offset, "VCALENDAR", false);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-        if (mBuilder != null) {
-            mBuilder.endRecord();
-        }
-
-        // [ws]
-        ret = removeWs(offset);
-        offset += ret;
-        sum += ret;
-
-        // 1 * CRLF
-        ret = parseCrlf(offset);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-        while (PARSE_ERROR != (ret = parseCrlf(offset))) {
-            offset += ret;
-            sum += ret;
-        }
-
-        return sum;
-    }
-
-    /**
-     * calprops * CRLF calprop / calprop
-     */
-    private int parseCalprops(int offset) {
-        int ret = 0, sum = 0;
-
-        if (mBuilder != null) {
-            mBuilder.startProperty();
-        }
-        ret = parseCalprop(offset);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-        if (mBuilder != null) {
-            mBuilder.endProperty();
-        }
-
-        for (;;) {
-            /* *CRLF */
-            while (PARSE_ERROR != (ret = parseCrlf(offset))) {
-                offset += ret;
-                sum += ret;
-            }
-            // follow VEVENT ,it wont reach endProperty
-            if (mBuilder != null) {
-                mBuilder.startProperty();
-            }
-            ret = parseCalprop(offset);
-            if (PARSE_ERROR == ret) {
-                break;
-            }
-            offset += ret;
-            sum += ret;
-            if (mBuilder != null) {
-                mBuilder.endProperty();
-            }
-        }
-
-        return sum;
-    }
-
-    /**
-     * calentities *CRLF calentity / calentity
-     */
-    private int parseCalentities(int offset) {
-        int ret = 0, sum = 0;
-
-        ret = parseCalentity(offset);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-
-        for (;;) {
-            /* *CRLF */
-            while (PARSE_ERROR != (ret = parseCrlf(offset))) {
-                offset += ret;
-                sum += ret;
-            }
-
-            ret = parseCalentity(offset);
-            if (PARSE_ERROR == ret) {
-                break;
-            }
-            offset += ret;
-            sum += ret;
-        }
-
-        return sum;
-    }
-
-    /**
-     * calprop = DAYLIGHT/ GEO/ PRODID/ TZ/ VERSION
-     */
-    private int parseCalprop(int offset) {
-        int ret = 0;
-
-        ret = parseCalprop0(offset, "DAYLIGHT");
-        if (PARSE_ERROR != ret) {
-            return ret;
-        }
-
-        ret = parseCalprop0(offset, "GEO");
-        if (PARSE_ERROR != ret) {
-            return ret;
-        }
-
-        ret = parseCalprop0(offset, "PRODID");
-        if (PARSE_ERROR != ret) {
-            return ret;
-        }
-
-        ret = parseCalprop0(offset, "TZ");
-        if (PARSE_ERROR != ret) {
-            return ret;
-        }
-
-        ret = parseCalprop1(offset);
-        if (PARSE_ERROR != ret) {
-            return ret;
-        }
-        return PARSE_ERROR;
-    }
-
-    /**
-     * evententity / todoentity
-     */
-    private int parseCalentity(int offset) {
-        int ret = 0;
-
-        ret = parseEvententity(offset);
-        if (PARSE_ERROR != ret) {
-            return ret;
-        }
-
-        ret = parseTodoentity(offset);
-        if (PARSE_ERROR != ret) {
-            return ret;
-        }
-        return PARSE_ERROR;
-
-    }
-
-    /**
-     * propName [params] ":" value CRLF
-     */
-    private int parseCalprop0(int offset, String propName) {
-        int ret = 0, sum = 0, start = 0;
-
-        ret = parseString(offset, propName, true);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-        if (mBuilder != null) {
-            mBuilder.propertyName(propName);
-        }
-
-        ret = parseParams(offset);
-        if (PARSE_ERROR != ret) {
-            offset += ret;
-            sum += ret;
-        }
-
-        ret = parseString(offset, ":", true);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-
-        start = offset;
-        ret = parseValue(offset);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-        if (mBuilder != null) {
-            ArrayList<String> v = new ArrayList<String>();
-            v.add(mBuffer.substring(start, offset));
-            mBuilder.propertyValues(v);
-        }
-
-        ret = parseCrlf(offset);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        sum += ret;
-
-        return sum;
-    }
-
-    /**
-     * "VERSION" [params] ":" "1.0" CRLF
-     */
-    private int parseCalprop1(int offset) {
-        int ret = 0, sum = 0;
-
-        ret = parseString(offset, "VERSION", true);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-        if (mBuilder != null) {
-            mBuilder.propertyName("VERSION");
-        }
-
-        ret = parseParams(offset);
-        if (PARSE_ERROR != ret) {
-            offset += ret;
-            sum += ret;
-        }
-
-        ret = parseString(offset, ":", true);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-
-        ret = parseString(offset, "1.0", true);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-        if (mBuilder != null) {
-            ArrayList<String> v = new ArrayList<String>();
-            v.add("1.0");
-            mBuilder.propertyValues(v);
-        }
-        ret = parseCrlf(offset);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        sum += ret;
-
-        return sum;
-    }
-
-    /**
-     * "BEGIN" [ws] ":" [ws] "VEVENT" [ws] 1*CRLF entprops [ws] *CRLF "END" [ws]
-     * ":" [ws] "VEVENT" [ws] 1*CRLF
-     */
-    private int parseEvententity(int offset) {
-        int ret = 0, sum = 0;
-
-        ret = parseString(offset, "BEGIN", false);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-
-        // [ws]
-        ret = removeWs(offset);
-        offset += ret;
-        sum += ret;
-
-        // ":"
-        ret = parseString(offset, ":", false);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-
-        // [ws]
-        ret = removeWs(offset);
-        offset += ret;
-        sum += ret;
-
-        // "VEVNET"
-        ret = parseString(offset, "VEVENT", false);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-        if (mBuilder != null) {
-            mBuilder.startRecord("VEVENT");
-        }
-
-        /* [ws] */
-        ret = removeWs(offset);
-        offset += ret;
-        sum += ret;
-
-        // 1*CRLF
-        ret = parseCrlf(offset);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-        while (PARSE_ERROR != (ret = parseCrlf(offset))) {
-            offset += ret;
-            sum += ret;
-        }
-
-        ret = parseEntprops(offset);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-
-        // [ws]
-        ret = removeWs(offset);
-        offset += ret;
-        sum += ret;
-
-        // *CRLF
-        while (PARSE_ERROR != (ret = parseCrlf(offset))) {
-            offset += ret;
-            sum += ret;
-        }
-
-        // "END"
-        ret = parseString(offset, "END", false);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-
-        // [ws]
-        ret = removeWs(offset);
-        offset += ret;
-        sum += ret;
-
-        // ":"
-        ret = parseString(offset, ":", false);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-
-        // [ws]
-        ret = removeWs(offset);
-        offset += ret;
-        sum += ret;
-
-        // "VEVENT"
-        ret = parseString(offset, "VEVENT", false);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-        if (mBuilder != null) {
-            mBuilder.endRecord();
-        }
-
-        // [ws]
-        ret = removeWs(offset);
-        offset += ret;
-        sum += ret;
-
-        // 1 * CRLF
-        ret = parseCrlf(offset);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-        while (PARSE_ERROR != (ret = parseCrlf(offset))) {
-            offset += ret;
-            sum += ret;
-        }
-
-        return sum;
-    }
-
-    /**
-     * "BEGIN" [ws] ":" [ws] "VTODO" [ws] 1*CRLF entprops [ws] *CRLF "END" [ws]
-     * ":" [ws] "VTODO" [ws] 1*CRLF
-     */
-    private int parseTodoentity(int offset) {
-        int ret = 0, sum = 0;
-
-        ret = parseString(offset, "BEGIN", false);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-
-        // [ws]
-        ret = removeWs(offset);
-        offset += ret;
-        sum += ret;
-
-        // ":"
-        ret = parseString(offset, ":", false);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-
-        // [ws]
-        ret = removeWs(offset);
-        offset += ret;
-        sum += ret;
-
-        // "VTODO"
-        ret = parseString(offset, "VTODO", false);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-        if (mBuilder != null) {
-            mBuilder.startRecord("VTODO");
-        }
-
-        // 1*CRLF
-        ret = parseCrlf(offset);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-        while (PARSE_ERROR != (ret = parseCrlf(offset))) {
-            offset += ret;
-            sum += ret;
-        }
-
-        ret = parseEntprops(offset);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-
-        // [ws]
-        ret = removeWs(offset);
-        offset += ret;
-        sum += ret;
-
-        // *CRLF
-        while (PARSE_ERROR != (ret = parseCrlf(offset))) {
-            offset += ret;
-            sum += ret;
-        }
-
-        // "END"
-        ret = parseString(offset, "END", false);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-
-        // [ws]
-        ret = removeWs(offset);
-        offset += ret;
-        sum += ret;
-
-        // ":"
-        ret = parseString(offset, ":", false);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-
-        // [ws]
-        ret = removeWs(offset);
-        offset += ret;
-        sum += ret;
-
-        // "VTODO"
-        ret = parseString(offset, "VTODO", false);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-        if (mBuilder != null) {
-            mBuilder.endRecord();
-        }
-
-        // [ws]
-        ret = removeWs(offset);
-        offset += ret;
-        sum += ret;
-
-        // 1 * CRLF
-        ret = parseCrlf(offset);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-        while (PARSE_ERROR != (ret = parseCrlf(offset))) {
-            offset += ret;
-            sum += ret;
-        }
-
-        return sum;
-    }
-
-    /**
-     * entprops *CRLF entprop / entprop
-     */
-    private int parseEntprops(int offset) {
-        int ret = 0, sum = 0;
-        if (mBuilder != null) {
-            mBuilder.startProperty();
-        }
-
-        ret = parseEntprop(offset);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-        if (mBuilder != null) {
-            mBuilder.endProperty();
-        }
-
-        for (;;) {
-            while (PARSE_ERROR != (ret = parseCrlf(offset))) {
-                offset += ret;
-                sum += ret;
-            }
-            if (mBuilder != null) {
-                mBuilder.startProperty();
-            }
-
-            ret = parseEntprop(offset);
-            if (PARSE_ERROR == ret) {
-                break;
-            }
-            offset += ret;
-            sum += ret;
-            if (mBuilder != null) {
-                mBuilder.endProperty();
-            }
-        }
-        return sum;
-    }
-
-    /**
-     * for VEVENT,VTODO prop. entprop0 / entprop1
-     */
-    private int parseEntprop(int offset) {
-        int ret = 0;
-        ret = parseEntprop0(offset);
-        if (PARSE_ERROR != ret) {
-            return ret;
-        }
-
-        ret = parseEntprop1(offset);
-        if (PARSE_ERROR != ret) {
-            return ret;
-        }
-        return PARSE_ERROR;
-    }
-
-    /**
-     * Same with card. ";" [ws] paramlist
-     */
-    private int parseParams(int offset) {
-        int ret = 0, sum = 0;
-
-        ret = parseString(offset, ";", true);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-
-        ret = removeWs(offset);
-        offset += ret;
-        sum += ret;
-
-        ret = parseParamlist(offset);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        sum += ret;
-
-        return sum;
-    }
-
-    /**
-     * Same with card. paramlist [ws] ";" [ws] param / param
-     */
-    private int parseParamlist(int offset) {
-        int ret = 0, sum = 0;
-
-        ret = parseParam(offset);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-
-        int offsetTemp = offset;
-        int sumTemp = sum;
-        for (;;) {
-            ret = removeWs(offsetTemp);
-            offsetTemp += ret;
-            sumTemp += ret;
-
-            ret = parseString(offsetTemp, ";", false);
-            if (PARSE_ERROR == ret) {
-                return sum;
-            }
-            offsetTemp += ret;
-            sumTemp += ret;
-
-            ret = removeWs(offsetTemp);
-            offsetTemp += ret;
-            sumTemp += ret;
-
-            ret = parseParam(offsetTemp);
-            if (PARSE_ERROR == ret) {
-                break;
-            }
-            offsetTemp += ret;
-            sumTemp += ret;
-
-            // offset = offsetTemp;
-            sum = sumTemp;
-        }
-        return sum;
-    }
-
-    /**
-     * param0 - param7 / knowntype
-     */
-    private int parseParam(int offset) {
-        int ret = 0;
-
-        ret = parseParam0(offset);
-        if (PARSE_ERROR != ret) {
-            return ret;
-        }
-
-        ret = parseParam1(offset);
-        if (PARSE_ERROR != ret) {
-            return ret;
-        }
-
-        ret = parseParam2(offset);
-        if (PARSE_ERROR != ret) {
-            return ret;
-        }
-
-        ret = parseParam3(offset);
-        if (PARSE_ERROR != ret) {
-            return ret;
-        }
-
-        ret = parseParam4(offset);
-        if (PARSE_ERROR != ret) {
-            return ret;
-        }
-
-        ret = parseParam5(offset);
-        if (PARSE_ERROR != ret) {
-            return ret;
-        }
-
-        ret = parseParam6(offset);
-        if (PARSE_ERROR != ret) {
-            return ret;
-        }
-
-        ret = parseParam7(offset);
-        if (PARSE_ERROR != ret) {
-            return ret;
-        }
-
-        int start = offset;
-        ret = parseKnownType(offset);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        if (mBuilder != null) {
-            mBuilder.propertyParamType(null);
-            mBuilder.propertyParamValue(mBuffer.substring(start, offset));
-        }
-
-        return ret;
-    }
-
-    /**
-     * simprop AND "CLASS" AND "STATUS" The value of these properties are not
-     * seperated by ";"
-     *
-     * [ws] simprop [params] ":" value CRLF
-     */
-    private int parseEntprop0(int offset) {
-        int ret = 0, sum = 0, start = 0;
-
-        ret = removeWs(offset);
-        offset += ret;
-        sum += ret;
-
-        String propName = getWord(offset).toUpperCase();
-        if (!mEvtPropNameGroup1.contains(propName)) {
-            if (PARSE_ERROR == parseXWord(offset))
-                return PARSE_ERROR;
-        }
-        ret = propName.length();
-        offset += ret;
-        sum += ret;
-        if (mBuilder != null) {
-            mBuilder.propertyName(propName);
-        }
-
-        ret = parseParams(offset);
-        if (PARSE_ERROR != ret) {
-            offset += ret;
-            sum += ret;
-        }
-
-        ret = parseString(offset, ":", false);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-
-        start = offset;
-        ret = parseValue(offset);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-        if (mBuilder != null) {
-            ArrayList<String> v = new ArrayList<String>();
-            v.add(exportEntpropValue(propName, mBuffer.substring(start,
-                            offset)));
-            mBuilder.propertyValues(v);
-            // Filter value,match string, REFER:RFC
-            if (PARSE_ERROR == valueFilter(propName, v))
-                return PARSE_ERROR;
-        }
-
-        ret = parseCrlf(offset);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        sum += ret;
-        return sum;
-    }
-
-    /**
-     * other event prop names except simprop AND "CLASS" AND "STATUS" The value
-     * of these properties are seperated by ";" [ws] proper name [params] ":"
-     * value CRLF
-     */
-    private int parseEntprop1(int offset) {
-        int ret = 0, sum = 0;
-
-        ret = removeWs(offset);
-        offset += ret;
-        sum += ret;
-
-        String propName = getWord(offset).toUpperCase();
-        if (!mEvtPropNameGroup2.contains(propName)) {
-            return PARSE_ERROR;
-        }
-        ret = propName.length();
-        offset += ret;
-        sum += ret;
-        if (mBuilder != null) {
-            mBuilder.propertyName(propName);
-        }
-
-        ret = parseParams(offset);
-        if (PARSE_ERROR != ret) {
-            offset += ret;
-            sum += ret;
-        }
-
-        ret = parseString(offset, ":", false);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-
-        int start = offset;
-        ret = parseValue(offset);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-        // mutil-values
-        if (mBuilder != null) {
-            int end = 0;
-            ArrayList<String> v = new ArrayList<String>();
-            Pattern p = Pattern
-                    .compile("([^;\\\\]*(\\\\[\\\\;:,])*[^;\\\\]*)(;?)");
-            Matcher m = p.matcher(mBuffer.substring(start, offset));
-            while (m.find()) {
-                String s = exportEntpropValue(propName, m.group(1));
-                v.add(s);
-                end = m.end();
-                if (offset == start + end) {
-                    String endValue = m.group(3);
-                    if (";".equals(endValue)) {
-                        v.add("");
-                    }
-                    break;
-                }
-            }
-            mBuilder.propertyValues(v);
-            // Filter value,match string, REFER:RFC
-            if (PARSE_ERROR == valueFilter(propName, v))
-                return PARSE_ERROR;
-        }
-
-        ret = parseCrlf(offset);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        sum += ret;
-        return sum;
-    }
-
-    /**
-     * "TYPE" [ws] = [ws] ptypeval
-     */
-    private int parseParam0(int offset) {
-        int ret = 0, sum = 0, start = offset;
-
-        ret = parseString(offset, "TYPE", true);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-        if (mBuilder != null) {
-            mBuilder.propertyParamType(mBuffer.substring(start, offset));
-        }
-
-        ret = removeWs(offset);
-        offset += ret;
-        sum += ret;
-
-        ret = parseString(offset, "=", false);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-
-        ret = removeWs(offset);
-        offset += ret;
-        sum += ret;
-
-        start = offset;
-        ret = parsePtypeval(offset);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-        if (mBuilder != null) {
-            mBuilder.propertyParamValue(mBuffer.substring(start, offset));
-        }
-        return sum;
-    }
-
-    /**
-     * ["VALUE" [ws] "=" [ws]] pvalueval
-     */
-    private int parseParam1(int offset) {
-        int ret = 0, sum = 0, start = offset;
-        boolean flag = false;
-
-        ret = parseString(offset, "VALUE", true);
-        if (PARSE_ERROR != ret) {
-            offset += ret;
-            sum += ret;
-            flag = true;
-        }
-        if (flag == true && mBuilder != null) {
-            mBuilder.propertyParamType(mBuffer.substring(start, offset));
-        }
-
-        ret = removeWs(offset);
-        offset += ret;
-        sum += ret;
-
-        ret = parseString(offset, "=", true);
-        if (PARSE_ERROR != ret) {
-            if (flag == false) { // "VALUE" does not exist
-                return PARSE_ERROR;
-            }
-            offset += ret;
-            sum += ret;
-        } else {
-            if (flag == true) { // "VALUE" exists
-                return PARSE_ERROR;
-            }
-        }
-
-        ret = removeWs(offset);
-        offset += ret;
-        sum += ret;
-
-        start = offset;
-        ret = parsePValueVal(offset);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-        if (mBuilder != null) {
-            mBuilder.propertyParamValue(mBuffer.substring(start, offset));
-        }
-
-        return sum;
-    }
-
-    /** ["ENCODING" [ws] "=" [ws]] pencodingval */
-    private int parseParam2(int offset) {
-        int ret = 0, sum = 0, start = offset;
-        boolean flag = false;
-
-        ret = parseString(offset, "ENCODING", true);
-        if (PARSE_ERROR != ret) {
-            offset += ret;
-            sum += ret;
-            flag = true;
-        }
-        if (flag == true && mBuilder != null) {
-            mBuilder.propertyParamType(mBuffer.substring(start, offset));
-        }
-
-        ret = removeWs(offset);
-        offset += ret;
-        sum += ret;
-
-        ret = parseString(offset, "=", true);
-        if (PARSE_ERROR != ret) {
-            if (flag == false) { // "VALUE" does not exist
-                return PARSE_ERROR;
-            }
-            offset += ret;
-            sum += ret;
-        } else {
-            if (flag == true) { // "VALUE" exists
-                return PARSE_ERROR;
-            }
-        }
-
-        ret = removeWs(offset);
-        offset += ret;
-        sum += ret;
-
-        start = offset;
-        ret = parsePEncodingVal(offset);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-        if (mBuilder != null) {
-            mBuilder.propertyParamValue(mBuffer.substring(start, offset));
-        }
-
-        return sum;
-    }
-
-    /**
-     * "CHARSET" [WS] "=" [WS] charsetval
-     */
-    private int parseParam3(int offset) {
-        int ret = 0, sum = 0, start = offset;
-
-        ret = parseString(offset, "CHARSET", true);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-        if (mBuilder != null) {
-            mBuilder.propertyParamType(mBuffer.substring(start, offset));
-        }
-
-        ret = removeWs(offset);
-        offset += ret;
-        sum += ret;
-
-        ret = parseString(offset, "=", true);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-
-        ret = removeWs(offset);
-        offset += ret;
-        sum += ret;
-
-        start = offset;
-        ret = parseCharsetVal(offset);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-        if (mBuilder != null) {
-            mBuilder.propertyParamValue(mBuffer.substring(start, offset));
-        }
-
-        return sum;
-    }
-
-    /**
-     * "LANGUAGE" [ws] "=" [ws] langval
-     */
-    private int parseParam4(int offset) {
-        int ret = 0, sum = 0, start = offset;
-
-        ret = parseString(offset, "LANGUAGE", true);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-        if (mBuilder != null) {
-            mBuilder.propertyParamType(mBuffer.substring(start, offset));
-        }
-
-        ret = removeWs(offset);
-        offset += ret;
-        sum += ret;
-
-        ret = parseString(offset, "=", true);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-
-        ret = removeWs(offset);
-        offset += ret;
-        sum += ret;
-
-        start = offset;
-        ret = parseLangVal(offset);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-        if (mBuilder != null) {
-            mBuilder.propertyParamValue(mBuffer.substring(start, offset));
-        }
-
-        return sum;
-    }
-
-    /**
-     * "ROLE" [ws] "=" [ws] roleval
-     */
-    private int parseParam5(int offset) {
-        int ret = 0, sum = 0, start = offset;
-
-        ret = parseString(offset, "ROLE", true);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-        if (mBuilder != null) {
-            mBuilder.propertyParamType(mBuffer.substring(start, offset));
-        }
-
-        ret = removeWs(offset);
-        offset += ret;
-        sum += ret;
-
-        ret = parseString(offset, "=", true);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-
-        ret = removeWs(offset);
-        offset += ret;
-        sum += ret;
-
-        start = offset;
-        ret = parseRoleVal(offset);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-        if (mBuilder != null) {
-            mBuilder.propertyParamValue(mBuffer.substring(start, offset));
-        }
-
-        return sum;
-    }
-
-    /**
-     * "STATUS" [ws] = [ws] statuval
-     */
-    private int parseParam6(int offset) {
-        int ret = 0, sum = 0, start = offset;
-
-        ret = parseString(offset, "STATUS", true);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-        if (mBuilder != null) {
-            mBuilder.propertyParamType(mBuffer.substring(start, offset));
-        }
-
-        ret = removeWs(offset);
-        offset += ret;
-        sum += ret;
-
-        ret = parseString(offset, "=", true);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-
-        ret = removeWs(offset);
-        offset += ret;
-        sum += ret;
-
-        start = offset;
-        ret = parseStatuVal(offset);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-        if (mBuilder != null) {
-            mBuilder.propertyParamValue(mBuffer.substring(start, offset));
-        }
-
-        return sum;
-
-    }
-
-    /**
-     * XWord [ws] "=" [ws] word
-     */
-    private int parseParam7(int offset) {
-        int ret = 0, sum = 0, start = offset;
-
-        ret = parseXWord(offset);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-        if (mBuilder != null) {
-            mBuilder.propertyParamType(mBuffer.substring(start, offset));
-        }
-
-        ret = removeWs(offset);
-        offset += ret;
-        sum += ret;
-
-        ret = parseString(offset, "=", true);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-
-        ret = removeWs(offset);
-        offset += ret;
-        sum += ret;
-
-        start = offset;
-        ret = parseWord(offset);
-        if (PARSE_ERROR == ret) {
-            return PARSE_ERROR;
-        }
-        offset += ret;
-        sum += ret;
-        if (mBuilder != null) {
-            mBuilder.propertyParamValue(mBuffer.substring(start, offset));
-        }
-
-        return sum;
-
-    }
-
-    /*
-     * "WAVE" / "PCM" / "VCARD" / XWORD
-     */
-    private int parseKnownType(int offset) {
-        int ret = 0;
-
-        ret = parseString(offset, "WAVE", true);
-        if (PARSE_ERROR != ret) {
-            return ret;
-        }
-
-        ret = parseString(offset, "PCM", true);
-        if (PARSE_ERROR != ret) {
-            return ret;
-        }
-
-        ret = parseString(offset, "VCARD", true);
-        if (PARSE_ERROR != ret) {
-            return ret;
-        }
-
-        ret = parseXWord(offset);
-        if (PARSE_ERROR != ret) {
-            return ret;
-        }
-
-        return PARSE_ERROR;
-    }
-
-    /*
-     * knowntype / Xword
-     */
-    private int parsePtypeval(int offset) {
-        int ret = 0;
-
-        ret = parseKnownType(offset);
-        if (PARSE_ERROR != ret) {
-            return ret;
-        }
-
-        ret = parseXWord(offset);
-        if (PARSE_ERROR != ret) {
-            return ret;
-        }
-
-        return PARSE_ERROR;
-    }
-
-    /**
-     * "ATTENDEE" / "ORGANIZER" / "OWNER" / XWORD
-     */
-    private int parseRoleVal(int offset) {
-        int ret = 0;
-
-        ret = parseString(offset, "ATTENDEE", true);
-        if (PARSE_ERROR != ret) {
-            return ret;
-        }
-
-        ret = parseString(offset, "ORGANIZER", true);
-        if (PARSE_ERROR != ret) {
-            return ret;
-        }
-
-        ret = parseString(offset, "OWNER", true);
-        if (PARSE_ERROR != ret) {
-            return ret;
-        }
-
-        ret = parseXWord(offset);
-        if (PARSE_ERROR != ret) {
-            return ret;
-        }
-
-        return PARSE_ERROR;
-    }
-
-    /**
-     * "ACCEPTED" / "NEED ACTION" / "SENT" / "TENTATIVE" / "CONFIRMED" /
-     * "DECLINED" / "COMPLETED" / "DELEGATED / XWORD
-     */
-    private int parseStatuVal(int offset) {
-        int ret = 0;
-
-        ret = parseString(offset, "ACCEPTED", true);
-        if (PARSE_ERROR != ret) {
-            return ret;
-        }
-
-        ret = parseString(offset, "NEED ACTION", true);
-        if (PARSE_ERROR != ret) {
-            return ret;
-        }
-
-        ret = parseString(offset, "TENTATIVE", true);
-        if (PARSE_ERROR != ret) {
-            return ret;
-        }
-        ret = parseString(offset, "CONFIRMED", true);
-        if (PARSE_ERROR != ret) {
-            return ret;
-        }
-        ret = parseString(offset, "DECLINED", true);
-        if (PARSE_ERROR != ret) {
-            return ret;
-        }
-        ret = parseString(offset, "COMPLETED", true);
-        if (PARSE_ERROR != ret) {
-            return ret;
-        }
-        ret = parseString(offset, "DELEGATED", true);
-        if (PARSE_ERROR != ret) {
-            return ret;
-        }
-
-        ret = parseXWord(offset);
-        if (PARSE_ERROR != ret) {
-            return ret;
-        }
-
-        return PARSE_ERROR;
-    }
-
-    /**
-     * Check 4 special propName and it's value to match Hash.
-     *
-     * @return PARSE_ERROR:value not match. 1:go on,like nothing happen.
-     */
-    private int valueFilter(String propName, ArrayList<String> values) {
-        if (propName == null || propName.equals("") || values == null
-                || values.isEmpty())
-            return 1; // go on, like nothing happen.
-
-        if (mSpecialValueSetMap.containsKey(propName)) {
-            for (String value : values) {
-                if (!mSpecialValueSetMap.get(propName).contains(value)) {
-                    if (!value.startsWith("X-"))
-                        return PARSE_ERROR;
-                }
-            }
-        }
-
-        return 1;
-    }
-
-    /**
-     *
-     * Translate escape characters("\\", "\;") which define in vcalendar1.0
-     * spec. But for fault tolerance, we will translate "\:" and "\,", which
-     * isn't define in vcalendar1.0 explicitly, as the same behavior as other
-     * client.
-     *
-     * Though vcalendar1.0 spec does not defined the value of property
-     * "description", "summary", "aalarm", "dalarm", "malarm" and "palarm" could
-     * contain escape characters, we do support escape characters in these
-     * properties.
-     *
-     * @param str:
-     *            the value string will be translated.
-     * @return the string which do not contain any escape character in
-     *         vcalendar1.0
-     */
-    private String exportEntpropValue(String propName, String str) {
-        if (null == propName || null == str)
-            return null;
-        if ("".equals(propName) || "".equals(str))
-            return "";
-
-        if (!mEscAllowedProps.contains(propName))
-            return str;
-
-        String tmp = str.replace("\\\\", "\n\r\n");
-        tmp = tmp.replace("\\;", ";");
-        tmp = tmp.replace("\\:", ":");
-        tmp = tmp.replace("\\,", ",");
-        tmp = tmp.replace("\n\r\n", "\\");
-        return tmp;
-    }
-}
diff --git a/core/java/android/syncml/pim/vcalendar/VCalParser_V20.java b/core/java/android/syncml/pim/vcalendar/VCalParser_V20.java
deleted file mode 100644
index 5748379..0000000
--- a/core/java/android/syncml/pim/vcalendar/VCalParser_V20.java
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.syncml.pim.vcalendar;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Arrays;
-import java.util.HashSet;
-
-import android.syncml.pim.VBuilder;
-
-public class VCalParser_V20 extends VCalParser_V10 {
-    private static final String V10LINEBREAKER = "\r\n";
-
-    private static final HashSet<String> acceptableComponents = new HashSet<String>(
-            Arrays.asList("VEVENT", "VTODO", "VALARM", "VTIMEZONE"));
-
-    private static final HashSet<String> acceptableV20Props = new HashSet<String>(
-            Arrays.asList("DESCRIPTION", "DTEND", "DTSTART", "DUE",
-                    "COMPLETED", "RRULE", "STATUS", "SUMMARY", "LOCATION"));
-
-    private boolean hasTZ = false; // MUST only have one TZ property
-
-    private String[] lines;
-
-    private int index;
-
-    @Override
-    public boolean parse(InputStream is, String encoding, VBuilder builder)
-            throws IOException {
-        // get useful info for android calendar, and alter to vcal 1.0
-        byte[] bytes = new byte[is.available()];
-        is.read(bytes);
-        String scStr = new String(bytes);
-        StringBuilder v10str = new StringBuilder("");
-
-        lines = splitProperty(scStr);
-        index = 0;
-
-        if ("BEGIN:VCALENDAR".equals(lines[index]))
-            v10str.append("BEGIN:VCALENDAR" + V10LINEBREAKER);
-        else
-            return false;
-        index++;
-        if (false == parseV20Calbody(lines, v10str)
-                || index > lines.length - 1)
-            return false;
-
-        if (lines.length - 1 == index && "END:VCALENDAR".equals(lines[index]))
-            v10str.append("END:VCALENDAR" + V10LINEBREAKER);
-        else
-            return false;
-
-        return super.parse(
-                // use vCal 1.0 parser
-                new ByteArrayInputStream(v10str.toString().getBytes()),
-                encoding, builder);
-    }
-
-    /**
-     * Parse and pick acceptable iCalendar body and translate it to
-     * calendarV1.0 format.
-     * @param lines iCalendar components/properties line list.
-     * @param buffer calendarV10 format string buffer
-     * @return true for success, or false
-     */
-    private boolean parseV20Calbody(String[] lines, StringBuilder buffer) {
-        try {
-            while (!"VERSION:2.0".equals(lines[index]))
-                index++;
-            buffer.append("VERSION:1.0" + V10LINEBREAKER);
-
-            index++;
-            for (; index < lines.length - 1; index++) {
-                String[] keyAndValue = lines[index].split(":", 2);
-                String key = keyAndValue[0];
-                String value = keyAndValue[1];
-
-                if ("BEGIN".equals(key.trim())) {
-                    if (!key.equals(key.trim()))
-                        return false; // MUST be "BEGIN:componentname"
-                    index++;
-                    if (false == parseV20Component(value, buffer))
-                        return false;
-                }
-            }
-        } catch (ArrayIndexOutOfBoundsException e) {
-            return false;
-        }
-
-        return true;
-    }
-
-    /**
-     * Parse and pick acceptable calendar V2.0's component and translate it to
-     * V1.0 format.
-     * @param compName component name
-     * @param buffer calendarV10 format string buffer
-     * @return true for success, or false
-     * @throws ArrayIndexOutOfBoundsException
-     */
-    private boolean parseV20Component(String compName, StringBuilder buffer)
-            throws ArrayIndexOutOfBoundsException {
-        String endTag = "END:" + compName;
-        String[] propAndValue;
-        String propName, value;
-
-        if (acceptableComponents.contains(compName)) {
-            if ("VEVENT".equals(compName) || "VTODO".equals(compName)) {
-                buffer.append("BEGIN:" + compName + V10LINEBREAKER);
-                while (!endTag.equals(lines[index])) {
-                    propAndValue = lines[index].split(":", 2);
-                    propName = propAndValue[0].split(";", 2)[0];
-                    value = propAndValue[1];
-
-                    if ("".equals(lines[index]))
-                        buffer.append(V10LINEBREAKER);
-                    else if (acceptableV20Props.contains(propName)) {
-                        buffer.append(propName + ":" + value + V10LINEBREAKER);
-                    } else if ("BEGIN".equals(propName.trim())) {
-                        // MUST be BEGIN:VALARM
-                        if (propName.equals(propName.trim())
-                                && "VALARM".equals(value)) {
-                            buffer.append("AALARM:default" + V10LINEBREAKER);
-                            while (!"END:VALARM".equals(lines[index]))
-                                index++;
-                        } else
-                            return false;
-                    }
-                    index++;
-                } // end while
-                buffer.append(endTag + V10LINEBREAKER);
-            } else if ("VALARM".equals(compName)) { // VALARM component MUST
-                // only appear within either VEVENT or VTODO
-                return false;
-            } else if ("VTIMEZONE".equals(compName)) {
-                do {
-                    if (false == hasTZ) {// MUST only have 1 time TZ property
-                        propAndValue = lines[index].split(":", 2);
-                        propName = propAndValue[0].split(";", 2)[0];
-
-                        if ("TZOFFSETFROM".equals(propName)) {
-                            value = propAndValue[1];
-                            buffer.append("TZ" + ":" + value + V10LINEBREAKER);
-                            hasTZ = true;
-                        }
-                    }
-                    index++;
-                } while (!endTag.equals(lines[index]));
-            } else
-                return false;
-        } else {
-            while (!endTag.equals(lines[index]))
-                index++;
-        }
-
-        return true;
-    }
-
-    /** split ever property line to String[], not split folding line. */
-    private String[] splitProperty(String scStr) {
-        /*
-         * Property splitted by \n, and unfold folding lines by removing
-         * CRLF+LWSP-char
-         */
-        scStr = scStr.replaceAll("\r\n", "\n").replaceAll("\n ", "")
-                .replaceAll("\n\t", "");
-        String[] strs = scStr.split("\n");
-        return strs;
-    }
-}
diff --git a/core/java/android/syncml/pim/vcalendar/package.html b/core/java/android/syncml/pim/vcalendar/package.html
deleted file mode 100644
index cb4ca46..0000000
--- a/core/java/android/syncml/pim/vcalendar/package.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<HTML>
-<BODY>
-Support classes for SyncML.
-{@hide}
-</BODY>
-</HTML>
\ No newline at end of file
diff --git a/core/java/android/syncml/pim/vcard/ContactStruct.java b/core/java/android/syncml/pim/vcard/ContactStruct.java
index 4b4c394..9782111 100644
--- a/core/java/android/syncml/pim/vcard/ContactStruct.java
+++ b/core/java/android/syncml/pim/vcard/ContactStruct.java
@@ -22,7 +22,9 @@
 import android.content.ContentUris;
 import android.content.ContentValues;
 import android.net.Uri;
+import android.provider.CallLog;
 import android.provider.Contacts;
+import android.provider.CallLog.Calls;
 import android.provider.Contacts.ContactMethods;
 import android.provider.Contacts.Extensions;
 import android.provider.Contacts.GroupMembership;
@@ -49,8 +51,11 @@
  * This class standy by the person-contact in
  * Android system, we must use this class instance as parameter to transmit to
  * VCardComposer so that create vCard string.
+ * 
+ * @deprecated Please use the new code in android.pim.vcard
  */
 // TODO: rename the class name, next step
+@Deprecated
 public class ContactStruct {
     private static final String LOG_TAG = "ContactStruct";
     
@@ -85,6 +90,8 @@
     /** Only for GET. Use addExtension() to PUT */
     public Map<String, List<String>> extensionMap;
 
+    public String timeStamp;
+
     // Use organizationList instead when handling ORG.
     @Deprecated
     public String company;
@@ -145,6 +152,32 @@
     }
 
     /**
+     * Add call history time stamp and call type.
+     * @param type call type
+     * @param timeStamp timeStamp
+     */
+    public void addCallHistoryTimeStamp(int type, String date) {
+        // Extension for call history as defined in
+        // in the Specification for Ic Mobile Communcation - ver 1.1,
+        // Oct 2000. This is used to send the details of the call
+        // history - missed, incoming, outgoing along with date and time
+        // to the requesting device (For example, transferring phone book
+        // when connected over bluetooth)
+        // X-IRMC-CALL-DATETIME;MISSED:20050320T100000
+        String strCallType;
+        if (type == Calls.INCOMING_TYPE) {
+            strCallType = "INCOMING";
+        } else if (type == Calls.OUTGOING_TYPE) {
+            strCallType = "OUTGOING";
+        } else if (type == Calls.MISSED_TYPE) {
+            strCallType = "MISSED";
+        } else {
+            strCallType = "";
+        }
+        timeStamp = "X-IRMC-CALL-DATETIME;" + strCallType + ":" + date;
+    }
+
+    /**
      * Add a contactmethod info to contactmethodList.
      * @param kind integer value defined in Contacts.java
      * (e.g. Contacts.KIND_EMAIL)
diff --git a/core/java/android/syncml/pim/vcard/VCardComposer.java b/core/java/android/syncml/pim/vcard/VCardComposer.java
index 192736a..a5dd053 100644
--- a/core/java/android/syncml/pim/vcard/VCardComposer.java
+++ b/core/java/android/syncml/pim/vcard/VCardComposer.java
@@ -29,7 +29,10 @@
 
 /**
  * Compose VCard string
+ * 
+ * @depricated Please use the code in android.pim.vcard
  */
+@Deprecated
 public class VCardComposer {
     final public static int VERSION_VCARD21_INT = 1;
 
@@ -146,6 +149,10 @@
             appendContactMethodStr(struct.contactmethodList, vcardversion);
         }
 
+        if (!isNull(struct.timeStamp)) {
+            mResult.append(struct.timeStamp).append(mNewline);
+        }
+
         mResult.append("END:VCARD").append(mNewline);
         return mResult.toString();
     }
diff --git a/core/java/android/syncml/pim/vcard/VCardDataBuilder.java b/core/java/android/syncml/pim/vcard/VCardDataBuilder.java
index f2a2733..5fd8fdf 100644
--- a/core/java/android/syncml/pim/vcard/VCardDataBuilder.java
+++ b/core/java/android/syncml/pim/vcard/VCardDataBuilder.java
@@ -47,7 +47,10 @@
  * If we store all VNode entries in memory like VDataBuilder.java,
  * OutOfMemoryError may be thrown. Thus, this class push each VCard entry into
  * ContentResolver immediately.
+ * 
+ * @depricated Please use the code in android.pim.vcard
  */
+@Deprecated
 public class VCardDataBuilder implements VBuilder {
     static private String LOG_TAG = "VCardDataBuilder"; 
     
diff --git a/core/java/android/syncml/pim/vcard/VCardEntryCounter.java b/core/java/android/syncml/pim/vcard/VCardEntryCounter.java
index 03cd1d9..11372ce 100644
--- a/core/java/android/syncml/pim/vcard/VCardEntryCounter.java
+++ b/core/java/android/syncml/pim/vcard/VCardEntryCounter.java
@@ -20,6 +20,10 @@
 
 import android.syncml.pim.VBuilder;
 
+/**
+ * @depricated Please use the code in android.pim.vcard
+ */
+@Deprecated
 public class VCardEntryCounter implements VBuilder {
     private int mCount;
     
diff --git a/core/java/android/syncml/pim/vcard/VCardException.java b/core/java/android/syncml/pim/vcard/VCardException.java
index 35b31ec..326aa7f 100644
--- a/core/java/android/syncml/pim/vcard/VCardException.java
+++ b/core/java/android/syncml/pim/vcard/VCardException.java
@@ -16,6 +16,10 @@
 
 package android.syncml.pim.vcard;
 
+/**
+ * @depricated Please use the code in android.pim.vcard
+ */
+@Deprecated
 public class VCardException extends java.lang.Exception{
     // constructors
 
diff --git a/core/java/android/syncml/pim/vcard/VCardNestedException.java b/core/java/android/syncml/pim/vcard/VCardNestedException.java
index def6f3b7..5c49e40 100644
--- a/core/java/android/syncml/pim/vcard/VCardNestedException.java
+++ b/core/java/android/syncml/pim/vcard/VCardNestedException.java
@@ -18,7 +18,10 @@
 
 /**
  * VCardException thrown when VCard is nested without VCardParser's being notified.
+ *
+ * @depricated Please use the code in android.pim.vcard
  */
+@Deprecated
 public class VCardNestedException extends VCardException {
     public VCardNestedException() {}
     public VCardNestedException(String message) {
diff --git a/core/java/android/syncml/pim/vcard/VCardParser.java b/core/java/android/syncml/pim/vcard/VCardParser.java
index 9a590dd..a562973 100644
--- a/core/java/android/syncml/pim/vcard/VCardParser.java
+++ b/core/java/android/syncml/pim/vcard/VCardParser.java
@@ -23,6 +23,10 @@
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 
+/**
+ * @deprecated Please use the code in android.pim.vcard
+ */
+@Deprecated
 public class VCardParser {
 
     // TODO: fix this.
diff --git a/core/java/android/syncml/pim/vcard/VCardParser_V21.java b/core/java/android/syncml/pim/vcard/VCardParser_V21.java
index d865668..75ce564 100644
--- a/core/java/android/syncml/pim/vcard/VCardParser_V21.java
+++ b/core/java/android/syncml/pim/vcard/VCardParser_V21.java
@@ -31,7 +31,10 @@
 
 /**
  * This class is used to parse vcard. Please refer to vCard Specification 2.1.
+ *
+ * @deprecated Please use the code in android.pim.vcard
  */
+@Deprecated
 public class VCardParser_V21 {
     private static final String LOG_TAG = "VCardParser_V21";
     
diff --git a/core/java/android/syncml/pim/vcard/VCardParser_V30.java b/core/java/android/syncml/pim/vcard/VCardParser_V30.java
index e67525e..3aca258 100644
--- a/core/java/android/syncml/pim/vcard/VCardParser_V30.java
+++ b/core/java/android/syncml/pim/vcard/VCardParser_V30.java
@@ -25,7 +25,10 @@
 /**
  * This class is used to parse vcard3.0. <br>
  * Please refer to vCard Specification 3.0 (http://tools.ietf.org/html/rfc2426)
+ * 
+ * @deprecated Please use the code in android.pim.vcard
  */
+@Deprecated
 public class VCardParser_V30 extends VCardParser_V21 {
     private static final String LOG_TAG = "VCardParser_V30";
     
diff --git a/core/java/android/syncml/pim/vcard/VCardSourceDetector.java b/core/java/android/syncml/pim/vcard/VCardSourceDetector.java
index 8c48391..6873f04 100644
--- a/core/java/android/syncml/pim/vcard/VCardSourceDetector.java
+++ b/core/java/android/syncml/pim/vcard/VCardSourceDetector.java
@@ -26,8 +26,10 @@
 /**
  * Class which tries to detects the source of the vCard from its properties.
  * Currently this implementation is very premature.
- * @hide
+ * 
+ * @deprecated Please use the code in android.pim.vcard
  */
+@Deprecated
 public class VCardSourceDetector implements VBuilder {
     // Should only be used in package. 
     static final int TYPE_UNKNOWN = 0;
diff --git a/core/java/android/syncml/pim/vcard/VCardVersionException.java b/core/java/android/syncml/pim/vcard/VCardVersionException.java
index 1ca88d1..14bb45b 100644
--- a/core/java/android/syncml/pim/vcard/VCardVersionException.java
+++ b/core/java/android/syncml/pim/vcard/VCardVersionException.java
@@ -17,8 +17,11 @@
 package android.syncml.pim.vcard;
 
 /**
- * VCardException used only when the version of the vCard is different. 
+ * VCardException used only when the version of the vCard is different.
+ * 
+ * @deprecated Please use the code in android.pim.vcard
  */
+@Deprecated
 public class VCardVersionException extends VCardException {
     public VCardVersionException() {
     }
diff --git a/core/java/android/test/TimedTest.java b/core/java/android/test/TimedTest.java
new file mode 100644
index 0000000..3a60a25
--- /dev/null
+++ b/core/java/android/test/TimedTest.java
@@ -0,0 +1,32 @@
+/*
+ * 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.test;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * This annotation can be used on an {@link junit.framework.TestCase}'s test
+ * methods. When the annotation is present, the test method is timed and the
+ * results written through instrumentation output. It can also be used on the
+ * class itself, which is equivalent to tagging all test methods with this
+ * annotation.
+ *
+ * {@hide} Pending approval for public API.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+public @interface TimedTest { }
\ No newline at end of file
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index ea879ed9..1426aef 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -124,6 +124,8 @@
     };
     
     boolean mRequestedVisible = false;
+    boolean mWindowVisibility = false;
+    boolean mViewVisibility = false;
     int mRequestedWidth = -1;
     int mRequestedHeight = -1;
     int mRequestedFormat = PixelFormat.OPAQUE;
@@ -176,12 +178,22 @@
         mSession = getWindowSession();
         mLayout.token = getWindowToken();
         mLayout.setTitle("SurfaceView");
+        mViewVisibility = getVisibility() == VISIBLE;
     }
 
     @Override
     protected void onWindowVisibilityChanged(int visibility) {
         super.onWindowVisibilityChanged(visibility);
-        mRequestedVisible = visibility == VISIBLE;
+        mWindowVisibility = visibility == VISIBLE;
+        mRequestedVisible = mWindowVisibility && mViewVisibility;
+        updateWindow(false);
+    }
+
+    @Override
+    public void setVisibility(int visibility) {
+        super.setVisibility(visibility);
+        mViewVisibility = visibility == VISIBLE;
+        mRequestedVisible = mWindowVisibility && mViewVisibility;
         updateWindow(false);
     }
     
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 2f17bbc7..f63c2f1 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -6038,16 +6038,23 @@
      * some form of this public, but should think about the API.
      */
     Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor) {
-        final int width = mRight - mLeft;
-        final int height = mBottom - mTop;
+        int width = mRight - mLeft;
+        int height = mBottom - mTop;
 
-        Bitmap bitmap = Bitmap.createBitmap(width, height, quality);
+        final AttachInfo attachInfo = mAttachInfo;
+        final float scale = attachInfo.mApplicationScale;
+        width = (int) ((width * scale) + 0.5f);
+        height = (int) ((height * scale) + 0.5f);
+        
+        Bitmap bitmap = Bitmap.createBitmap(width > 0 ? width : 1,
+                height > 0 ? height : 1, quality);
         if (bitmap == null) {
             throw new OutOfMemoryError();
         }
 
+        bitmap.setDensity(getResources().getDisplayMetrics().densityDpi);
+        
         Canvas canvas;
-        final AttachInfo attachInfo = mAttachInfo;
         if (attachInfo != null) {
             canvas = attachInfo.mCanvas;
             if (canvas == null) {
@@ -6070,6 +6077,7 @@
 
         computeScroll();
         final int restoreCount = canvas.save();
+        canvas.scale(scale, scale);
         canvas.translate(-mScrollX, -mScrollY);
 
         // Temporarily remove the dirty mask
diff --git a/core/java/android/webkit/BrowserFrame.java b/core/java/android/webkit/BrowserFrame.java
index e96ba11..db6b74f 100644
--- a/core/java/android/webkit/BrowserFrame.java
+++ b/core/java/android/webkit/BrowserFrame.java
@@ -455,8 +455,6 @@
             mJSInterfaceMap.remove(interfaceName);
         }
         mJSInterfaceMap.put(interfaceName, obj);
-        nativeAddJavascriptInterface(0, mJSInterfaceMap.get(interfaceName),
-                interfaceName);
     }
 
     /**
diff --git a/core/java/android/webkit/LoadListener.java b/core/java/android/webkit/LoadListener.java
index 1a5b2eb..aee8a6d 100644
--- a/core/java/android/webkit/LoadListener.java
+++ b/core/java/android/webkit/LoadListener.java
@@ -410,7 +410,8 @@
                 mStatusCode == HTTP_MOVED_PERMANENTLY ||
                 mStatusCode == HTTP_TEMPORARY_REDIRECT) && 
                 mNativeLoader != 0) {
-            if (!mFromCache && URLUtil.isNetworkUrl(mUrl)) {
+            if (!mFromCache && mRequestHandle != null
+                    && !mRequestHandle.getMethod().equals("POST")) {
                 mCacheResult = CacheManager.createCacheFile(mUrl, mStatusCode,
                         headers, mMimeType, false);
             }
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 8a986fa..8446475 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -46,6 +46,7 @@
 import android.util.AttributeSet;
 import android.util.EventLog;
 import android.util.Log;
+import android.util.TypedValue;
 import android.view.Gravity;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
@@ -2048,6 +2049,10 @@
     protected int computeHorizontalScrollRange() {
         if (mDrawHistory) {
             return mHistoryWidth;
+        } else if (mLastWidthSent == mContentWidth) {
+            // special case to avoid rounding error. Otherwise we may get a
+            // faked scrollbar sometimes.
+            return getViewWidth();
         } else {
             return contentToViewDimension(mContentWidth);
         }
@@ -2061,7 +2066,14 @@
         if (mDrawHistory) {
             return mHistoryHeight;
         } else {
-            int height = contentToViewDimension(mContentHeight);
+            int height;
+            // special case to avoid rounding error. Otherwise we may get a
+            // faked scrollbar sometimes.
+            if (mLastHeightSent == mContentHeight) {
+                height = getViewHeight();
+            } else {
+                height = contentToViewDimension(mContentHeight);
+            }
             if (mFindIsUp) {
                 height += FIND_HEIGHT;
             }
@@ -2768,7 +2780,8 @@
                 mZoomScale = 0;
                 if (mNeedToAdjustWebTextView) {
                     mNeedToAdjustWebTextView = false;
-                    mWebTextView.setTextSize(contentToViewDimension(
+                    mWebTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
+                            contentToViewDimension(
                             nativeFocusCandidateTextSize()));
                     Rect bounds = nativeFocusCandidateNodeBounds();
                     Rect vBox = contentToView(bounds);
@@ -3333,7 +3346,8 @@
             // Initialize our generation number.
             mTextGeneration = 0;
         }
-        mWebTextView.setTextSize(contentToViewDimension(nativeFocusCandidateTextSize()));
+        mWebTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
+                contentToViewDimension(nativeFocusCandidateTextSize()));
         Rect visibleRect = new Rect();
         calcOurContentVisibleRect(visibleRect);
         // Note that sendOurVisibleRect calls viewToContent, so the coordinates
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index a611d5a..e98fd13 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -732,7 +732,11 @@
             }
         } else if (digits != null) {
             mInput = DigitsKeyListener.getInstance(digits.toString());
-            mInputType = inputType;
+            // If no input type was specified, we will default to generic
+            // text, since we can't tell the IME about the set of digits
+            // that was selected.
+            mInputType = inputType != EditorInfo.TYPE_NULL
+                    ? inputType : EditorInfo.TYPE_CLASS_TEXT;
         } else if (inputType != EditorInfo.TYPE_NULL) {
             setInputType(inputType, true);
             singleLine = (inputType&(EditorInfo.TYPE_MASK_CLASS
diff --git a/core/java/com/android/internal/app/ShutdownThread.java b/core/java/com/android/internal/app/ShutdownThread.java
index 4c9451e..9e1f325 100644
--- a/core/java/com/android/internal/app/ShutdownThread.java
+++ b/core/java/com/android/internal/app/ShutdownThread.java
@@ -185,7 +185,7 @@
         
         try {
             bluetoothOff = bluetooth == null ||
-                           bluetooth.getBluetoothState() == BluetoothAdapter.BLUETOOTH_STATE_OFF;
+                           bluetooth.getBluetoothState() == BluetoothAdapter.STATE_OFF;
             if (!bluetoothOff) {
                 Log.w(TAG, "Disabling Bluetooth...");
                 bluetooth.disable(false);  // disable but don't persist new state
@@ -213,7 +213,7 @@
             if (!bluetoothOff) {
                 try {
                     bluetoothOff =
-                            bluetooth.getBluetoothState() == BluetoothAdapter.BLUETOOTH_STATE_OFF;
+                            bluetooth.getBluetoothState() == BluetoothAdapter.STATE_OFF;
                 } catch (RemoteException ex) {
                     Log.e(TAG, "RemoteException during bluetooth shutdown", ex);
                     bluetoothOff = true;
diff --git a/core/java/com/android/internal/os/SamplingProfilerIntegration.java b/core/java/com/android/internal/os/SamplingProfilerIntegration.java
index 44bcd16..51d9570 100644
--- a/core/java/com/android/internal/os/SamplingProfilerIntegration.java
+++ b/core/java/com/android/internal/os/SamplingProfilerIntegration.java
@@ -11,7 +11,6 @@
 
 import android.util.Log;
 import android.os.*;
-import android.net.Uri;
 
 /**
  * Integrates the framework with Dalvik's sampling profiler.
@@ -60,14 +59,25 @@
     public static void writeSnapshot(final String name) {
         if (!enabled) return;
 
+        /*
+         * If we're already writing a snapshot, don't bother enqueing another
+         * request right now. This will reduce the number of individual
+         * snapshots and in turn the total amount of memory consumed (one big
+         * snapshot is smaller than N subset snapshots).
+         */
         if (!pending) {
             pending = true;
             snapshotWriter.execute(new Runnable() {
                 public void run() {
                     String dir = "/sdcard/snapshots";
                     if (!dirMade) {
-                        makeDirectory(dir);
-                        dirMade = true;
+                        new File(dir).mkdirs();
+                        if (new File(dir).isDirectory()) {
+                            dirMade = true;
+                        } else {
+                            Log.w(TAG, "Creation of " + dir + " failed.");
+                            return;
+                        }
                     }
                     try {
                         writeSnapshot(dir, name);
@@ -86,7 +96,7 @@
         if (!enabled) return;
 
         String dir = "/data/zygote/snapshots";
-        makeDirectory(dir);
+        new File(dir).mkdirs();
         writeSnapshot(dir, "zygote");
     }
 
@@ -102,7 +112,7 @@
          * we capture two snapshots in rapid succession.
          */
         long start = System.currentTimeMillis();
-        String path = dir + "/" + name.replace(':', '.') + "-"
+        String path = dir + "/" + name.replace(':', '.') + "-" +
                 + System.currentTimeMillis() + ".snapshot";
         try {
             // Try to open the file a few times. The SD card may not be mounted.
@@ -117,7 +127,7 @@
                         Log.e(TAG, "Could not open " + path + ".");
                         return;
                     }
-                    
+
                     // Sleep for a bit and then try again.
                     try {
                         Thread.sleep(2500);
@@ -137,8 +147,4 @@
             Log.e(TAG, "Error writing snapshot.", e);
         }
     }
-
-    private static void makeDirectory(String dir) {
-        new File(dir).mkdirs();
-    }
 }
diff --git a/core/java/com/android/internal/widget/ContactHeaderWidget.java b/core/java/com/android/internal/widget/ContactHeaderWidget.java
index 4dd289c..fe01866 100644
--- a/core/java/com/android/internal/widget/ContactHeaderWidget.java
+++ b/core/java/com/android/internal/widget/ContactHeaderWidget.java
@@ -366,7 +366,8 @@
     public void bindFromPhoneNumber(String number) {
         Cursor c = null;
         try {
-            c = mContentResolver.query(Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, number),
+            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);
diff --git a/core/java/com/android/internal/widget/DialogTitle.java b/core/java/com/android/internal/widget/DialogTitle.java
index 2eef0b6..125d2c5 100644
--- a/core/java/com/android/internal/widget/DialogTitle.java
+++ b/core/java/com/android/internal/widget/DialogTitle.java
@@ -58,14 +58,15 @@
                             android.R.style.TextAppearance_Medium,
                             android.R.styleable.TextAppearance);
                     final int textSize = a.getDimensionPixelSize(
-                            android.R.styleable.TextAppearance_textSize, 20);
+                            android.R.styleable.TextAppearance_textSize,
+                            (int) (20 * getResources().getDisplayMetrics().density));
 
-                    setTextSize(TypedValue.COMPLEX_UNIT_SP, textSize);
+                    // textSize is already expressed in pixels
+                    setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
                     setMaxLines(2);
                     super.onMeasure(widthMeasureSpec, heightMeasureSpec);      
                 }
             }
         }
     }
-   
-}
\ No newline at end of file
+}
diff --git a/core/java/com/android/internal/widget/NumberPicker.java b/core/java/com/android/internal/widget/NumberPicker.java
index 0424ced..ae08eca 100644
--- a/core/java/com/android/internal/widget/NumberPicker.java
+++ b/core/java/com/android/internal/widget/NumberPicker.java
@@ -36,7 +36,7 @@
 
 public class NumberPicker extends LinearLayout implements OnClickListener,
         OnFocusChangeListener, OnLongClickListener {
-        
+
     public interface OnChangedListener {
         void onChanged(NumberPicker picker, int oldVal, int newVal);
     }
@@ -51,7 +51,7 @@
      * most efficient way to do this; it avoids creating temporary objects
      * on every call to format().
      */
-    public static final NumberPicker.Formatter TWO_DIGIT_FORMATTER = 
+    public static final NumberPicker.Formatter TWO_DIGIT_FORMATTER =
             new NumberPicker.Formatter() {
                 final StringBuilder mBuilder = new StringBuilder();
                 final java.util.Formatter mFmt = new java.util.Formatter(mBuilder);
@@ -63,7 +63,7 @@
                     return mFmt.toString();
                 }
         };
-    
+
     private final Handler mHandler;
     private final Runnable mRunnable = new Runnable() {
         public void run() {
@@ -81,21 +81,21 @@
     private final InputFilter mNumberInputFilter;
 
     private String[] mDisplayedValues;
-    private int mStart;
-    private int mEnd;
-    private int mCurrent;
-    private int mPrevious;
+    protected int mStart;
+    protected int mEnd;
+    protected int mCurrent;
+    protected int mPrevious;
     private OnChangedListener mListener;
     private Formatter mFormatter;
     private long mSpeed = 300;
-    
+
     private boolean mIncrement;
     private boolean mDecrement;
-    
+
     public NumberPicker(Context context) {
         this(context, null);
     }
-    
+
     public NumberPicker(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
     }
@@ -117,7 +117,7 @@
         mDecrementButton.setOnClickListener(this);
         mDecrementButton.setOnLongClickListener(this);
         mDecrementButton.setNumberPicker(this);
-        
+
         mText = (EditText) findViewById(R.id.timepicker_input);
         mText.setOnFocusChangeListener(this);
         mText.setFilters(new InputFilter[] {inputFilter});
@@ -127,7 +127,7 @@
             setEnabled(false);
         }
     }
-    
+
     @Override
     public void setEnabled(boolean enabled) {
         super.setEnabled(enabled);
@@ -135,19 +135,19 @@
         mDecrementButton.setEnabled(enabled);
         mText.setEnabled(enabled);
     }
-    
+
     public void setOnChangeListener(OnChangedListener listener) {
         mListener = listener;
     }
-    
+
     public void setFormatter(Formatter formatter) {
         mFormatter = formatter;
     }
-    
+
     /**
      * Set the range of numbers allowed for the number picker. The current
      * value will be automatically set to the start.
-     * 
+     *
      * @param start the start of the range (inclusive)
      * @param end the end of the range (inclusive)
      */
@@ -157,12 +157,12 @@
         mCurrent = start;
         updateView();
     }
-    
+
     /**
      * Set the range of numbers allowed for the number picker. The current
      * value will be automatically set to the start. Also provide a mapping
      * for values used to display to the user.
-     * 
+     *
      * @param start the start of the range (inclusive)
      * @param end the end of the range (inclusive)
      * @param displayedValues the values displayed to the user.
@@ -174,7 +174,7 @@
         mCurrent = start;
         updateView();
     }
-    
+
     public void setCurrent(int current) {
         mCurrent = current;
         updateView();
@@ -187,7 +187,7 @@
     public void setSpeed(long speed) {
         mSpeed = speed;
     }
-    
+
     public void onClick(View v) {
         validateInput(mText);
         if (!mText.hasFocus()) mText.requestFocus();
@@ -199,15 +199,15 @@
             changeCurrent(mCurrent - 1);
         }
     }
-    
+
     private String formatNumber(int value) {
         return (mFormatter != null)
                 ? mFormatter.toString(value)
                 : String.valueOf(value);
     }
- 
-    private void changeCurrent(int current) {
-        
+
+    protected void changeCurrent(int current) {
+
         // Wrap around the values if we go past the start or end
         if (current > mEnd) {
             current = mStart;
@@ -219,15 +219,15 @@
         notifyChange();
         updateView();
     }
-    
-    private void notifyChange() {
+
+    protected void notifyChange() {
         if (mListener != null) {
             mListener.onChanged(this, mPrevious, mCurrent);
         }
     }
 
-    private void updateView() {
-        
+    protected void updateView() {
+
         /* If we don't have displayed values then use the
          * current number else find the correct value in the
          * displayed values for the current number.
@@ -239,7 +239,7 @@
         }
         mText.setSelection(mText.getText().length());
     }
-    
+
     private void validateCurrentView(CharSequence str) {
         int val = getSelectedPos(str.toString());
         if ((val >= mStart) && (val <= mEnd)) {
@@ -253,7 +253,7 @@
     }
 
     public void onFocusChange(View v, boolean hasFocus) {
-        
+
         /* When focus is lost check that the text field
          * has valid values.
          */
@@ -280,12 +280,12 @@
      * to inform us when the long click has ended.
      */
     public boolean onLongClick(View v) {
-        
+
         /* The text view may still have focus so clear it's focus which will
          * trigger the on focus changed and any typed values to be pulled.
          */
         mText.clearFocus();
-        
+
         if (R.id.increment == v.getId()) {
             mIncrement = true;
             mHandler.post(mRunnable);
@@ -295,22 +295,22 @@
         }
         return true;
     }
-    
+
     public void cancelIncrement() {
         mIncrement = false;
     }
-    
+
     public void cancelDecrement() {
         mDecrement = false;
     }
-    
+
     private static final char[] DIGIT_CHARACTERS = new char[] {
         '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
     };
-    
+
     private NumberPickerButton mIncrementButton;
     private NumberPickerButton mDecrementButton;
-    
+
     private class NumberPickerInputFilter implements InputFilter {
         public CharSequence filter(CharSequence source, int start, int end,
                 Spanned dest, int dstart, int dend) {
@@ -331,7 +331,7 @@
             return "";
         }
     }
-    
+
     private class NumberRangeKeyListener extends NumberKeyListener {
 
         // XXX This doesn't allow for range limits when controlled by a
@@ -339,12 +339,12 @@
         public int getInputType() {
             return InputType.TYPE_CLASS_NUMBER;
         }
-        
+
         @Override
         protected char[] getAcceptedChars() {
             return DIGIT_CHARACTERS;
         }
-        
+
         @Override
         public CharSequence filter(CharSequence source, int start, int end,
                 Spanned dest, int dstart, int dend) {
@@ -381,21 +381,21 @@
             return Integer.parseInt(str);
         } else {
             for (int i = 0; i < mDisplayedValues.length; i++) {
-                
+
                 /* Don't force the user to type in jan when ja will do */
                 str = str.toLowerCase();
                 if (mDisplayedValues[i].toLowerCase().startsWith(str)) {
                     return mStart + i;
                 }
             }
-            
+
             /* The user might have typed in a number into the month field i.e.
              * 10 instead of OCT so support that too.
              */
             try {
                 return Integer.parseInt(str);
             } catch (NumberFormatException e) {
-                
+
                 /* Ignore as if it's not a number we don't care */
             }
         }
diff --git a/core/jni/android/graphics/NinePatch.cpp b/core/jni/android/graphics/NinePatch.cpp
index fd5271e..50df0f7 100644
--- a/core/jni/android/graphics/NinePatch.cpp
+++ b/core/jni/android/graphics/NinePatch.cpp
@@ -1,4 +1,25 @@
+/*
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#define LOG_TAG "9patch"
+#define LOG_NDEBUG 1
+
 #include <utils/ResourceTypes.h>
+#include <utils/Log.h>
 
 #include "SkCanvas.h"
 #include "SkRegion.h"
@@ -62,6 +83,9 @@
             
             if (destDensity == srcDensity || destDensity == 0
                     || srcDensity == 0) {
+                LOGV("Drawing unscaled 9-patch: (%g,%g)-(%g,%g)",
+                        SkScalarToFloat(bounds.fLeft), SkScalarToFloat(bounds.fTop),
+                        SkScalarToFloat(bounds.fRight), SkScalarToFloat(bounds.fBottom));
                 NinePatch_Draw(canvas, bounds, *bitmap, *chunk, paint, NULL);
             } else {
                 canvas->save();
@@ -74,6 +98,11 @@
                 bounds.fBottom = SkScalarDiv(bounds.fBottom-bounds.fTop, scale);
                 bounds.fLeft = bounds.fTop = 0;
     
+                LOGV("Drawing scaled 9-patch: (%g,%g)-(%g,%g) srcDensity=%d destDensity=%d",
+                        SkScalarToFloat(bounds.fLeft), SkScalarToFloat(bounds.fTop),
+                        SkScalarToFloat(bounds.fRight), SkScalarToFloat(bounds.fBottom),
+                        srcDensity, destDensity);
+                
                 NinePatch_Draw(canvas, bounds, *bitmap, *chunk, paint, NULL);
     
                 canvas->restore();
diff --git a/core/jni/android/graphics/NinePatchImpl.cpp b/core/jni/android/graphics/NinePatchImpl.cpp
index f82053c..ff24a87 100644
--- a/core/jni/android/graphics/NinePatchImpl.cpp
+++ b/core/jni/android/graphics/NinePatchImpl.cpp
@@ -16,8 +16,10 @@
 */
 
 #define LOG_TAG "NinePatch"
+#define LOG_NDEBUG 1
 
 #include <utils/ResourceTypes.h>
+#include <utils/Log.h>
 
 #include "SkBitmap.h"
 #include "SkCanvas.h"
@@ -25,7 +27,7 @@
 #include "SkPaint.h"
 #include "SkUnPreMultiply.h"
 
-#define USE_TRACEx
+#define USE_TRACE
 
 #ifdef USE_TRACE
     static bool gTrace;
@@ -106,6 +108,13 @@
     if (canvas && canvas->quickReject(bounds, SkCanvas::kBW_EdgeType)) {
         return;
     }
+
+    SkPaint defaultPaint;
+    if (NULL == paint) {
+        // matches default dither in NinePatchDrawable.java.
+        defaultPaint.setDither(true);
+        paint = &defaultPaint;
+    }
     
     // if our canvas is GL, draw this as a mesh, which will be faster than
     // in parts (which is faster for raster)
@@ -123,10 +132,10 @@
 
     SkASSERT(canvas || outRegion);
 
-#if 0
+#ifdef USE_TRACE
     if (canvas) {
         const SkMatrix& m = canvas->getTotalMatrix();
-        SkDebugf("ninepatch [%g %g %g] [%g %g %g]\n",
+        LOGV("ninepatch [%g %g %g] [%g %g %g]\n",
                  SkScalarToFloat(m[0]), SkScalarToFloat(m[1]), SkScalarToFloat(m[2]),
                  SkScalarToFloat(m[3]), SkScalarToFloat(m[4]), SkScalarToFloat(m[5]));
     }
@@ -134,10 +143,10 @@
 
 #ifdef USE_TRACE
     if (gTrace) {
-        SkDEBUGF(("======== ninepatch bounds [%g %g]\n", SkScalarToFloat(bounds.width()), SkScalarToFloat(bounds.height())));
-        SkDEBUGF(("======== ninepatch paint bm [%d,%d]\n", bitmap.width(), bitmap.height()));
-        SkDEBUGF(("======== ninepatch xDivs [%d,%d]\n", chunk.xDivs[0], chunk.xDivs[1]));
-        SkDEBUGF(("======== ninepatch yDivs [%d,%d]\n", chunk.yDivs[0], chunk.yDivs[1]));
+        LOGV("======== ninepatch bounds [%g %g]\n", SkScalarToFloat(bounds.width()), SkScalarToFloat(bounds.height()));
+        LOGV("======== ninepatch paint bm [%d,%d]\n", bitmap.width(), bitmap.height());
+        LOGV("======== ninepatch xDivs [%d,%d]\n", chunk.xDivs[0], chunk.xDivs[1]);
+        LOGV("======== ninepatch yDivs [%d,%d]\n", chunk.yDivs[0], chunk.yDivs[1]);
     }
 #endif
 
@@ -146,7 +155,7 @@
         (paint && paint->getXfermode() == NULL && paint->getAlpha() == 0))
     {
 #ifdef USE_TRACE
-        if (gTrace) SkDEBUGF(("======== abort ninepatch draw\n"));
+        if (gTrace) LOGV("======== abort ninepatch draw\n");
 #endif
         return;
     }
@@ -158,11 +167,6 @@
     if (bitmap.getPixels() == NULL)
         return;
 
-    SkPaint defaultPaint;
-    if (NULL == paint) {
-        paint = &defaultPaint;
-    }
-
     const bool hasXfer = paint->getXfermode() != NULL;
     SkRect      dst;
     SkIRect     src;
@@ -196,8 +200,8 @@
     }
     int numFixedYPixelsRemaining = bitmapHeight - numStretchyYPixelsRemaining;
 
-#if 0
-    SkDebugf("NinePatch [%d %d] bounds [%g %g %g %g] divs [%d %d]\n",
+#ifdef USE_TRACE
+    LOGV("NinePatch [%d %d] bounds [%g %g %g %g] divs [%d %d]\n",
              bitmap.width(), bitmap.height(),
              SkScalarToFloat(bounds.fLeft), SkScalarToFloat(bounds.fTop),
              SkScalarToFloat(bounds.width()), SkScalarToFloat(bounds.height()),
@@ -300,13 +304,13 @@
                 goto nextDiv;
             }
             if (canvas) {
-#if 0
-                SkDebugf("-- src [%d %d %d %d] dst [%g %g %g %g]\n",
+#ifdef USE_TRACE
+                LOGV("-- src [%d %d %d %d] dst [%g %g %g %g]\n",
                          src.fLeft, src.fTop, src.width(), src.height(),
                          SkScalarToFloat(dst.fLeft), SkScalarToFloat(dst.fTop),
                          SkScalarToFloat(dst.width()), SkScalarToFloat(dst.height()));
                 if (2 == src.width() && SkIntToScalar(5) == dst.width()) {
-                    SkDebugf("--- skip patch\n");
+                    LOGV("--- skip patch\n");
                 }
 #endif
                 drawStretchyPatch(canvas, src, dst, bitmap, *paint, initColor,
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
index 8fe7487..e703ed8 100644
--- a/core/jni/android_server_BluetoothEventLoop.cpp
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -45,13 +45,16 @@
 static jmethodID method_onDeviceDisappeared;
 static jmethodID method_onDeviceCreated;
 static jmethodID method_onDeviceRemoved;
+static jmethodID method_onDeviceDisconnectRequested;
 
 static jmethodID method_onCreatePairedDeviceResult;
 static jmethodID method_onGetDeviceServiceChannelResult;
 
 static jmethodID method_onRequestPinCode;
 static jmethodID method_onRequestPasskey;
-static jmethodID method_onRequestConfirmation;
+static jmethodID method_onRequestPasskeyConfirmation;
+static jmethodID method_onRequestPairingConsent;
+static jmethodID method_onDisplayPasskey;
 static jmethodID method_onAgentAuthorize;
 static jmethodID method_onAgentCancel;
 
@@ -84,6 +87,8 @@
                                                   "(Ljava/lang/String;)V");
     method_onDeviceCreated = env->GetMethodID(clazz, "onDeviceCreated", "(Ljava/lang/String;)V");
     method_onDeviceRemoved = env->GetMethodID(clazz, "onDeviceRemoved", "(Ljava/lang/String;)V");
+    method_onDeviceDisconnectRequested = env->GetMethodID(clazz, "onDeviceDisconnectRequested",
+                                                        "(Ljava/lang/String;)V");
 
     method_onCreatePairedDeviceResult = env->GetMethodID(clazz, "onCreatePairedDeviceResult",
                                                          "(Ljava/lang/String;I)V");
@@ -95,7 +100,11 @@
                                                "(Ljava/lang/String;I)V");
     method_onRequestPasskey = env->GetMethodID(clazz, "onRequestPasskey",
                                                "(Ljava/lang/String;I)V");
-    method_onRequestConfirmation = env->GetMethodID(clazz, "onRequestConfirmation",
+    method_onRequestPasskeyConfirmation = env->GetMethodID(clazz, "onRequestPasskeyConfirmation",
+                                               "(Ljava/lang/String;II)V");
+    method_onRequestPairingConsent = env->GetMethodID(clazz, "onRequestPairingConsent",
+                                               "(Ljava/lang/String;I)V");
+    method_onDisplayPasskey = env->GetMethodID(clazz, "onDisplayPasskey",
                                                "(Ljava/lang/String;II)V");
 
     field_mNativeData = env->GetFieldID(clazz, "mNativeData", "I");
@@ -227,7 +236,7 @@
 
 
 const char * get_adapter_path(DBusConnection *conn) {
-    DBusMessage *msg, *reply = NULL;
+    DBusMessage *msg = NULL, *reply = NULL;
     DBusError err;
     const char *device_path = NULL;
     int attempt = 0;
@@ -815,6 +824,14 @@
                             str_array);
         } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
         goto success;
+    } else if (dbus_message_is_signal(msg,
+                                      "org.bluez.Device",
+                                      "DisconnectRequested")) {
+        const char *remote_device_path = dbus_message_get_path(msg);
+        env->CallVoidMethod(nat->me,
+                            method_onDeviceDisconnectRequested,
+                            env->NewStringUTF(remote_device_path));
+        goto success;
     }
 
     ret = a2dp_event_filter(msg, env);
@@ -845,9 +862,7 @@
 
     if (dbus_message_is_method_call(msg,
             "org.bluez.Agent", "Cancel")) {
-
         env->CallVoidMethod(nat->me, method_onAgentCancel);
-
         // reply
         DBusMessage *reply = dbus_message_new_method_return(msg);
         if (!reply) {
@@ -928,6 +943,24 @@
                                        int(msg));
         goto success;
     } else if (dbus_message_is_method_call(msg,
+            "org.bluez.Agent", "DisplayPasskey")) {
+        char *object_path;
+        uint32_t passkey;
+        if (!dbus_message_get_args(msg, NULL,
+                                   DBUS_TYPE_OBJECT_PATH, &object_path,
+                                   DBUS_TYPE_UINT32, &passkey,
+                                   DBUS_TYPE_INVALID)) {
+            LOGE("%s: Invalid arguments for RequestPasskey() method", __FUNCTION__);
+            goto failure;
+        }
+
+        dbus_message_ref(msg);  // increment refcount because we pass to java
+        env->CallVoidMethod(nat->me, method_onDisplayPasskey,
+                                       env->NewStringUTF(object_path),
+                                       passkey,
+                                       int(msg));
+        goto success;
+    } else if (dbus_message_is_method_call(msg,
             "org.bluez.Agent", "RequestConfirmation")) {
         char *object_path;
         uint32_t passkey;
@@ -940,12 +973,27 @@
         }
 
         dbus_message_ref(msg);  // increment refcount because we pass to java
-        env->CallVoidMethod(nat->me, method_onRequestConfirmation,
+        env->CallVoidMethod(nat->me, method_onRequestPasskeyConfirmation,
                                        env->NewStringUTF(object_path),
                                        passkey,
                                        int(msg));
         goto success;
     } else if (dbus_message_is_method_call(msg,
+            "org.bluez.Agent", "RequestPairingConsent")) {
+        char *object_path;
+        if (!dbus_message_get_args(msg, NULL,
+                                   DBUS_TYPE_OBJECT_PATH, &object_path,
+                                   DBUS_TYPE_INVALID)) {
+            LOGE("%s: Invalid arguments for RequestPairingConsent() method", __FUNCTION__);
+            goto failure;
+        }
+
+        dbus_message_ref(msg);  // increment refcount because we pass to java
+        env->CallVoidMethod(nat->me, method_onRequestPairingConsent,
+                                       env->NewStringUTF(object_path),
+                                       int(msg));
+        goto success;
+    } else if (dbus_message_is_method_call(msg,
                   "org.bluez.Agent", "Release")) {
         // reply
         DBusMessage *reply = dbus_message_new_method_return(msg);
@@ -981,6 +1029,8 @@
 #define BOND_RESULT_AUTH_CANCELED 3
 #define BOND_RESULT_REMOTE_DEVICE_DOWN 4
 #define BOND_RESULT_DISCOVERY_IN_PROGRESS 5
+#define BOND_RESULT_AUTH_TIMEOUT 6
+#define BOND_RESULT_REPEATED_ATTEMPTS 7
 
 void onCreatePairedDeviceResult(DBusMessage *msg, void *user, void *n) {
     LOGV(__FUNCTION__);
@@ -1026,6 +1076,12 @@
                    !strcmp(err.message, "Discover in progress")) {
             LOGV("... error = %s (%s)\n", err.name, err.message);
             result = BOND_RESULT_DISCOVERY_IN_PROGRESS;
+        } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.RepeatedAttempts")) {
+            LOGV("... error = %s (%s)\n", err.name, err.message);
+            result = BOND_RESULT_REPEATED_ATTEMPTS;
+        } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationTimeout")) {
+            LOGV("... error = %s (%s)\n", err.name, err.message);
+            result = BOND_RESULT_AUTH_TIMEOUT;
         } else {
             LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
             result = BOND_RESULT_ERROR;
diff --git a/core/jni/android_server_BluetoothService.cpp b/core/jni/android_server_BluetoothService.cpp
index de921f1..0b71acb 100644
--- a/core/jni/android_server_BluetoothService.cpp
+++ b/core/jni/android_server_BluetoothService.cpp
@@ -455,8 +455,8 @@
         }
 
         if (!reply) {
-            LOGE("%s: Cannot create message reply to RequestConfirmation to "
-                 "D-Bus\n", __FUNCTION__);
+            LOGE("%s: Cannot create message reply to RequestPasskeyConfirmation or"
+                  "RequestPairingConsent to D-Bus\n", __FUNCTION__);
             dbus_message_unref(msg);
             return JNI_FALSE;
         }
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 723fd4b..7748aba 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -50,14 +50,6 @@
 #undef __KERNEL__
 #endif
 
-/*
- * List of cgroup names which map to ANDROID_TGROUP_ values in Thread.h
- * and Process.java
- * These names are used to construct the path to the cgroup control dir
- */
-
-static const char *cgroup_names[] = { NULL, "bg_non_interactive", "fg_boost" };
-
 using namespace android;
 
 static void signalExceptionForPriorityError(JNIEnv* env, jobject obj, int err)
@@ -194,14 +186,13 @@
     return -1;
 }
 
-static int add_pid_to_cgroup(int pid, int grp)
+static int add_pid_to_cgroup(int pid, const char *grp_name)
 {
     int fd;
     char path[255];
     char text[64];
 
-    sprintf(path, "/dev/cpuctl/%s/tasks",
-           (cgroup_names[grp] ? cgroup_names[grp] : ""));
+    sprintf(path, "/dev/cpuctl/%s/tasks", grp_name);
 
     if ((fd = open(path, O_WRONLY)) < 0)
         return -1;
@@ -216,6 +207,37 @@
     return 0;
 }
 
+void setSchedPolicy(JNIEnv* env, jobject clazz, int pid, SchedPolicy policy)
+{
+    static int __sys_supports_schedgroups = -1;
+
+    if (__sys_supports_schedgroups < 0) {
+        if (!access("/dev/cpuctl/tasks", F_OK)) {
+            __sys_supports_schedgroups = 1;
+        } else {
+            __sys_supports_schedgroups = 0;
+        }
+    }
+
+    if (__sys_supports_schedgroups) {
+        const char *grp = NULL;
+
+        if (policy == SP_BACKGROUND) {
+            grp = "bg_non_interactive";
+        }
+
+        if (add_pid_to_cgroup(pid, grp)) {
+            if (errno != ESRCH && errno != ENOENT)
+                signalExceptionForGroupError(env, clazz, errno);
+        }
+    } else {
+        struct sched_param param;
+
+        param.sched_priority = 0;
+        sched_setscheduler(pid, (policy == SP_BACKGROUND) ? 5 : 0, &param);
+    }
+}
+
 void android_os_Process_setThreadGroup(JNIEnv* env, jobject clazz, int pid, jint grp)
 {
     if (grp > ANDROID_TGROUP_MAX || grp < 0) { 
@@ -223,11 +245,9 @@
         return;
     }
 
-    if (add_pid_to_cgroup(pid, grp)) {
-        // If the thread exited on us, don't generate an exception
-        if (errno != ESRCH && errno != ENOENT)
-            signalExceptionForGroupError(env, clazz, errno);
-    }
+    setSchedPolicy(env, clazz, pid,
+                   (grp == ANDROID_TGROUP_BG_NONINTERACT) ?
+                           SP_BACKGROUND : SP_FOREGROUND);
 }
 
 void android_os_Process_setProcessGroup(JNIEnv* env, jobject clazz, int pid, jint grp) 
@@ -271,14 +291,9 @@
             continue;
         }
      
-        if (add_pid_to_cgroup(t_pid, grp)) {
-            // If the thread exited on us, ignore it and keep going
-            if (errno != ESRCH && errno != ENOENT) {
-                signalExceptionForGroupError(env, clazz, errno);
-                closedir(d);
-                return;
-            }
-        }
+        setSchedPolicy(env, clazz, t_pid,
+                       (grp == ANDROID_TGROUP_BG_NONINTERACT) ?
+                               SP_BACKGROUND : SP_FOREGROUND);
     }
     closedir(d);
 }
@@ -287,9 +302,9 @@
                                               jint pid, jint pri)
 {
     if (pri >= ANDROID_PRIORITY_BACKGROUND) {
-        add_pid_to_cgroup(pid, ANDROID_TGROUP_BG_NONINTERACT);
+        setSchedPolicy(env, clazz, pid, SP_BACKGROUND);
     } else if (getpriority(PRIO_PROCESS, pid) >= ANDROID_PRIORITY_BACKGROUND) {
-        add_pid_to_cgroup(pid, ANDROID_TGROUP_DEFAULT);
+        setSchedPolicy(env, clazz, pid, SP_FOREGROUND);
     }
 
     if (setpriority(PRIO_PROCESS, pid, pri) < 0) {
diff --git a/core/res/res/anim/activity_close_enter.xml b/core/res/res/anim/activity_close_enter.xml
new file mode 100644
index 0000000..9d1ef53
--- /dev/null
+++ b/core/res/res/anim/activity_close_enter.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+        android:interpolator="@anim/decelerate_interpolator"
+        android:zAdjustment="top">
+	<translate android:fromXDelta="-100%" android:toXDelta="0"
+        android:duration="@android:integer/config_mediumAnimTime"/>
+</set>
diff --git a/core/res/res/anim/activity_close_exit.xml b/core/res/res/anim/activity_close_exit.xml
new file mode 100644
index 0000000..47cb6d6
--- /dev/null
+++ b/core/res/res/anim/activity_close_exit.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+        android:interpolator="@anim/decelerate_interpolator">
+	<translate android:fromXDelta="0%" android:toXDelta="33%"
+        android:duration="@android:integer/config_mediumAnimTime"/>
+</set>
diff --git a/core/res/res/anim/activity_open_enter.xml b/core/res/res/anim/activity_open_enter.xml
new file mode 100644
index 0000000..e4c7e9b
--- /dev/null
+++ b/core/res/res/anim/activity_open_enter.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+        android:interpolator="@anim/decelerate_interpolator">
+	<translate android:fromXDelta="33%" android:toXDelta="0"
+        android:duration="@android:integer/config_mediumAnimTime"/>
+</set>
diff --git a/core/res/res/anim/activity_open_exit.xml b/core/res/res/anim/activity_open_exit.xml
new file mode 100644
index 0000000..9d47b7f
--- /dev/null
+++ b/core/res/res/anim/activity_open_exit.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+        android:interpolator="@anim/decelerate_interpolator"
+        android:zAdjustment="top">
+	<translate android:fromXDelta="0%" android:toXDelta="-100%"
+        android:duration="@android:integer/config_mediumAnimTime"/>
+</set>
diff --git a/core/res/res/anim/task_close_enter.xml b/core/res/res/anim/task_close_enter.xml
index c289869..303cfd6 100644
--- a/core/res/res/anim/task_close_enter.xml
+++ b/core/res/res/anim/task_close_enter.xml
@@ -1,8 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* //device/apps/common/res/anim/options_panel_exit.xml
-**
-** Copyright 2007, The Android Open Source Project
+/*
+** 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. 
@@ -19,8 +18,9 @@
 -->
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
-        android:interpolator="@anim/decelerate_interpolator"
-        android:zAdjustment="top">
-	<translate android:fromXDelta="-100%" android:toXDelta="0"
-        android:duration="@android:integer/config_mediumAnimTime"/>
+        android:interpolator="@anim/decelerate_interpolator">
+    <scale android:fromXScale="2.0" android:toXScale="1.0"
+           android:fromYScale="2.0" android:toYScale="1.0"
+           android:pivotX="50%p" android:pivotY="50%p"
+           android:duration="@android:integer/config_mediumAnimTime" />
 </set>
diff --git a/core/res/res/anim/task_close_exit.xml b/core/res/res/anim/task_close_exit.xml
index 96fff94..a28ac3b 100644
--- a/core/res/res/anim/task_close_exit.xml
+++ b/core/res/res/anim/task_close_exit.xml
@@ -1,8 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* //device/apps/common/res/anim/options_panel_exit.xml
-**
-** Copyright 2007, The Android Open Source Project
+/*
+** 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. 
@@ -19,7 +18,12 @@
 -->
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
-        android:interpolator="@anim/decelerate_interpolator">
-	<translate android:fromXDelta="0%" android:toXDelta="33%"
-        android:duration="@android:integer/config_mediumAnimTime"/>
+        android:interpolator="@anim/decelerate_interpolator"
+        android:zAdjustment="top">
+    <scale android:fromXScale="1.0" android:toXScale=".5"
+           android:fromYScale="1.0" android:toYScale=".5"
+           android:pivotX="50%p" android:pivotY="50%p"
+           android:duration="@android:integer/config_mediumAnimTime" />
+    <alpha android:fromAlpha="1.0" android:toAlpha="0"
+            android:duration="@android:integer/config_mediumAnimTime"/>
 </set>
diff --git a/core/res/res/anim/task_open_enter.xml b/core/res/res/anim/task_open_enter.xml
index 8e7d049..234abb2 100644
--- a/core/res/res/anim/task_open_enter.xml
+++ b/core/res/res/anim/task_open_enter.xml
@@ -1,8 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* //device/apps/common/res/anim/options_panel_exit.xml
-**
-** Copyright 2007, The Android Open Source Project
+/*
+** 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. 
@@ -19,7 +18,12 @@
 -->
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
-        android:interpolator="@anim/decelerate_interpolator">
-	<translate android:fromXDelta="33%" android:toXDelta="0"
-        android:duration="@android:integer/config_mediumAnimTime"/>
+        android:interpolator="@anim/decelerate_interpolator"
+        android:zAdjustment="top">
+    <scale android:fromXScale=".5" android:toXScale="1.0"
+           android:fromYScale=".5" android:toYScale="1.0"
+           android:pivotX="50%p" android:pivotY="50%p"
+           android:duration="@android:integer/config_mediumAnimTime" />
+    <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+            android:duration="@android:integer/config_mediumAnimTime"/>
 </set>
diff --git a/core/res/res/anim/task_open_exit.xml b/core/res/res/anim/task_open_exit.xml
index 5e5c66d..98975fb9 100644
--- a/core/res/res/anim/task_open_exit.xml
+++ b/core/res/res/anim/task_open_exit.xml
@@ -1,8 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* //device/apps/common/res/anim/options_panel_exit.xml
-**
-** Copyright 2007, The Android Open Source Project
+/*
+** 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. 
@@ -21,6 +20,8 @@
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:interpolator="@anim/decelerate_interpolator"
         android:zAdjustment="top">
-	<translate android:fromXDelta="0%" android:toXDelta="-100%"
-        android:duration="@android:integer/config_mediumAnimTime"/>
+    <scale android:fromXScale="1.0" android:toXScale="2.0"
+           android:fromYScale="1.0" android:toYScale="2.0"
+           android:pivotX="50%p" android:pivotY="50%p"
+           android:duration="@android:integer/config_mediumAnimTime" />
 </set>
diff --git a/core/res/res/anim/translucent_enter.xml b/core/res/res/anim/translucent_enter.xml
new file mode 100644
index 0000000..fb4c1c3
--- /dev/null
+++ b/core/res/res/anim/translucent_enter.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+        android:interpolator="@anim/decelerate_interpolator">
+	<translate android:fromXDelta="75%" android:toXDelta="0"
+        android:duration="@android:integer/config_mediumAnimTime"/>
+    <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+            android:duration="@android:integer/config_mediumAnimTime"/>
+</set>
diff --git a/core/res/res/anim/translucent_exit.xml b/core/res/res/anim/translucent_exit.xml
new file mode 100644
index 0000000..1d424e1
--- /dev/null
+++ b/core/res/res/anim/translucent_exit.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License"); 
+** you may not use this file except in compliance with the License. 
+** You may obtain a copy of the License at 
+**
+**     http://www.apache.org/licenses/LICENSE-2.0 
+**
+** Unless required by applicable law or agreed to in writing, software 
+** distributed under the License is distributed on an "AS IS" BASIS, 
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
+** See the License for the specific language governing permissions and 
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+        android:interpolator="@anim/accelerate_interpolator">
+	<translate android:fromXDelta="0%" android:toXDelta="75%"
+        android:duration="@android:integer/config_mediumAnimTime"/>
+    <alpha android:fromAlpha="1.0" android:toAlpha="0"
+            android:duration="@android:integer/config_mediumAnimTime"/>
+</set>
diff --git a/core/res/res/anim/wallpaper_close_enter.xml b/core/res/res/anim/wallpaper_close_enter.xml
index 8e7d049..e4c7e9b 100644
--- a/core/res/res/anim/wallpaper_close_enter.xml
+++ b/core/res/res/anim/wallpaper_close_enter.xml
@@ -1,8 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* //device/apps/common/res/anim/options_panel_exit.xml
-**
-** Copyright 2007, The Android Open Source Project
+/*
+** 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. 
diff --git a/core/res/res/anim/wallpaper_close_exit.xml b/core/res/res/anim/wallpaper_close_exit.xml
index 0a63990..16edec1 100644
--- a/core/res/res/anim/wallpaper_close_exit.xml
+++ b/core/res/res/anim/wallpaper_close_exit.xml
@@ -1,8 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* //device/apps/common/res/anim/options_panel_exit.xml
-**
-** Copyright 2007, The Android Open Source Project
+/*
+** 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. 
@@ -21,10 +20,10 @@
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:interpolator="@anim/decelerate_interpolator"
         android:zAdjustment="top">
-	<translate android:fromXDelta="0%" android:toXDelta="-100%"
-        android:duration="@android:integer/config_mediumAnimTime"/>
     <scale android:fromXScale="1.0" android:toXScale="2.0"
            android:fromYScale="1.0" android:toYScale="2.0"
-           android:pivotX="0%" android:pivotY="50%"
+           android:pivotX="100%p" android:pivotY="50%p"
            android:duration="@android:integer/config_mediumAnimTime" />
+	<translate android:fromXDelta="0%" android:toXDelta="-100%"
+        android:duration="@android:integer/config_mediumAnimTime"/>
 </set>
diff --git a/core/res/res/anim/wallpaper_enter.xml b/core/res/res/anim/wallpaper_enter.xml
index 981f5f6..c240a9a 100644
--- a/core/res/res/anim/wallpaper_enter.xml
+++ b/core/res/res/anim/wallpaper_enter.xml
@@ -1,8 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* //device/apps/common/res/anim/options_panel_exit.xml
-**
-** Copyright 2007, The Android Open Source Project
+/*\
+** 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. 
diff --git a/core/res/res/anim/wallpaper_exit.xml b/core/res/res/anim/wallpaper_exit.xml
index 2306071..742286f 100644
--- a/core/res/res/anim/wallpaper_exit.xml
+++ b/core/res/res/anim/wallpaper_exit.xml
@@ -1,8 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* //device/apps/common/res/anim/options_panel_exit.xml
-**
-** Copyright 2007, The Android Open Source Project
+/*
+** 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. 
diff --git a/core/res/res/anim/wallpaper_intra_close_enter.xml b/core/res/res/anim/wallpaper_intra_close_enter.xml
index b75745d..5c4f5c9 100644
--- a/core/res/res/anim/wallpaper_intra_close_enter.xml
+++ b/core/res/res/anim/wallpaper_intra_close_enter.xml
@@ -1,8 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* //device/apps/common/res/anim/options_panel_exit.xml
-**
-** Copyright 2007, The Android Open Source Project
+/*
+** 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. 
@@ -23,9 +22,9 @@
         android:zAdjustment="top">
     <scale android:fromXScale="2.0" android:toXScale="1.0"
            android:fromYScale="2.0" android:toYScale="1.0"
-           android:pivotX="100%" android:pivotY="50%"
+           android:pivotX="100%p" android:pivotY="50%p"
            android:duration="@android:integer/config_mediumAnimTime" />
-	<translate android:fromXDelta="-150%" android:toXDelta="0"
+	<translate android:fromXDelta="-150%p" android:toXDelta="0%p"
         android:duration="@android:integer/config_mediumAnimTime"/>
     <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
             android:duration="@android:integer/config_mediumAnimTime" />
diff --git a/core/res/res/anim/wallpaper_intra_close_exit.xml b/core/res/res/anim/wallpaper_intra_close_exit.xml
index 6a4e276..acaf773 100644
--- a/core/res/res/anim/wallpaper_intra_close_exit.xml
+++ b/core/res/res/anim/wallpaper_intra_close_exit.xml
@@ -1,8 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* //device/apps/common/res/anim/options_panel_exit.xml
-**
-** Copyright 2007, The Android Open Source Project
+/*
+** 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. 
@@ -22,9 +21,9 @@
         android:interpolator="@anim/accelerate_interpolator">
     <scale android:fromXScale="1.0" android:toXScale=".5"
            android:fromYScale="1.0" android:toYScale=".5"
-           android:pivotX="0%" android:pivotY="50%"
+           android:pivotX="100%p" android:pivotY="50%p"
            android:duration="@android:integer/config_mediumAnimTime" />
-	<translate android:fromXDelta="0%" android:toXDelta="100%"
+	<translate android:fromXDelta="0%p" android:toXDelta="100%p"
         android:duration="@android:integer/config_mediumAnimTime"/>
     <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
             android:duration="@android:integer/config_mediumAnimTime"/>
diff --git a/core/res/res/anim/wallpaper_intra_open_enter.xml b/core/res/res/anim/wallpaper_intra_open_enter.xml
index a46bc42..81c9991 100644
--- a/core/res/res/anim/wallpaper_intra_open_enter.xml
+++ b/core/res/res/anim/wallpaper_intra_open_enter.xml
@@ -1,8 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* //device/apps/common/res/anim/options_panel_exit.xml
-**
-** Copyright 2007, The Android Open Source Project
+/*
+** 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. 
@@ -22,9 +21,9 @@
         android:interpolator="@anim/decelerate_interpolator">
     <scale android:fromXScale=".5" android:toXScale="1.0"
            android:fromYScale=".5" android:toYScale="1.0"
-           android:pivotX="0%" android:pivotY="50%"
+           android:pivotX="100%p" android:pivotY="50%p"
            android:duration="@android:integer/config_mediumAnimTime" />
-    <translate android:fromXDelta="100%" android:toXDelta="0"
+    <translate android:fromXDelta="100%p" android:toXDelta="0"
             android:duration="@android:integer/config_mediumAnimTime"/>
     <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
             android:duration="@android:integer/config_mediumAnimTime" />
diff --git a/core/res/res/anim/wallpaper_intra_open_exit.xml b/core/res/res/anim/wallpaper_intra_open_exit.xml
index 0e9bc4a..28c4287 100644
--- a/core/res/res/anim/wallpaper_intra_open_exit.xml
+++ b/core/res/res/anim/wallpaper_intra_open_exit.xml
@@ -1,8 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* //device/apps/common/res/anim/options_panel_exit.xml
-**
-** Copyright 2007, The Android Open Source Project
+/*
+** 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. 
@@ -23,9 +22,9 @@
         android:zAdjustment="top">
     <scale android:fromXScale="1.0" android:toXScale="2.0"
            android:fromYScale="1.0" android:toYScale="2.0"
-           android:pivotX="100%" android:pivotY="50%"
+           android:pivotX="100%p" android:pivotY="50%p"
            android:duration="@android:integer/config_mediumAnimTime" />
-    <translate android:fromXDelta="0" android:toXDelta="-150%"
+    <translate android:fromXDelta="0" android:toXDelta="-150%p"
             android:duration="@android:integer/config_mediumAnimTime"/>
     <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
             android:duration="@android:integer/config_mediumAnimTime"/>
diff --git a/core/res/res/anim/wallpaper_open_enter.xml b/core/res/res/anim/wallpaper_open_enter.xml
index 9daf925..af22b47 100644
--- a/core/res/res/anim/wallpaper_open_enter.xml
+++ b/core/res/res/anim/wallpaper_open_enter.xml
@@ -1,8 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* //device/apps/common/res/anim/options_panel_exit.xml
-**
-** Copyright 2007, The Android Open Source Project
+/*
+** 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. 
@@ -21,10 +20,10 @@
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:interpolator="@anim/decelerate_interpolator"
         android:zAdjustment="top">
-	<translate android:fromXDelta="-100%" android:toXDelta="0"
-        android:duration="@android:integer/config_mediumAnimTime"/>
     <scale android:fromXScale="2.0" android:toXScale="1.0"
            android:fromYScale="2.0" android:toYScale="1.0"
-           android:pivotX="0%" android:pivotY="50%"
+           android:pivotX="100%p" android:pivotY="50%p"
            android:duration="@android:integer/config_mediumAnimTime" />
+	<translate android:fromXDelta="-100%" android:toXDelta="0"
+        android:duration="@android:integer/config_mediumAnimTime"/>
 </set>
diff --git a/core/res/res/anim/wallpaper_open_exit.xml b/core/res/res/anim/wallpaper_open_exit.xml
index 96fff94..47cb6d6 100644
--- a/core/res/res/anim/wallpaper_open_exit.xml
+++ b/core/res/res/anim/wallpaper_open_exit.xml
@@ -1,8 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-/* //device/apps/common/res/anim/options_panel_exit.xml
-**
-** Copyright 2007, The Android Open Source Project
+/*
+** 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. 
diff --git a/core/res/res/drawable-hdpi/scrollbar_handle_accelerated_anim2.9.png b/core/res/res/drawable-hdpi/scrollbar_handle_accelerated_anim2.9.png
index b540cd3..c916780 100644
--- a/core/res/res/drawable-hdpi/scrollbar_handle_accelerated_anim2.9.png
+++ b/core/res/res/drawable-hdpi/scrollbar_handle_accelerated_anim2.9.png
Binary files differ
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 1fcfe63d..d1cb0bd 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2838,10 +2838,14 @@
         For a more in-depth discussion of search configuration, please refer to
         {@link android.app.SearchManager}. -->
     <declare-styleable name="Searchable">
-        <!-- If provided, this icon will be shown in place of the label.  It is typically used
-             in order to identify a searchable application via a logo or branding, instead of
-             plain text.  This is a reference to a drawable (icon) resource.
-             <i>Optional attribute.</i> -->
+        <!-- If provided, this icon will be shown in place of the label above the search box.
+             This is a reference to a drawable (icon) resource. Note that the application icon
+             is also used as an icon to the left of the search box and you cannot modify this
+             behavior, so including the icon attribute is unecessary and this may be
+             deprecated in the future.
+             <i>Optional attribute.</i>
+             {@deprecated This will create a non-standard UI appearance, because the search bar UI
+              now puts the activity or application icon beside the search box.} -->
         <attr name="icon" />
         <!-- This is the user-displayed name of the searchable activity.  <i>Required
             attribute.</i> -->
@@ -2866,7 +2870,10 @@
           <flag name="showSearchLabelAsBadge" value="0x04" />
           <!-- If set, this flag enables the display of the search target (icon) within the
                search bar.  (Note, overrides showSearchLabel)  If neither bad mode is selected,
-               no badge will be shown.-->
+               no badge will be shown.
+              {@deprecated This will create a non-standard UI appearance, because the search bar UI
+              now puts the activity or application icon beside the search box.}
+               -->
           <flag name="showSearchIconAsBadge" value="0x08" />
           <!-- If set, this flag causes the suggestion column SUGGEST_COLUMN_INTENT_DATA to
                be considered as the text for suggestion query rewriting.  This should only
@@ -3438,6 +3445,10 @@
         <attr name="label"/>
         <!-- the icon of the authenticator. -->
         <attr name="icon"/>
+        <!-- smaller icon of the authenticator -->
+        <attr name="smallIcon" format="reference"/>
+        <!-- a preferences.xml file for authenticator-specific settings -->
+        <attr name="accountPreferences" format="reference"/>
     </declare-styleable>
 
     <!-- =============================== -->
@@ -3469,4 +3480,3 @@
     </declare-styleable>
 
 </resources>
-
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index 6ef6f52..cac26b9 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -65,4 +65,6 @@
   <item type="id" name="startSelectingText" />
   <item type="id" name="stopSelectingText" />
   <item type="id" name="addToDictionary" />
+  <item type="id" name="accountPreferences" />
+  <item type="id" name="smallIcon" />
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 8541c73..c4636f3 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1162,6 +1162,8 @@
   <public type="attr" name="supportsUploading" />
   <public type="attr" name="killAfterRestore" />
   <public type="attr" name="restoreNeedsApplication" />
+  <public type="attr" name="smallIcon" />
+  <public type="attr" name="accountPreferences" />
 
   <public type="style" name="Theme.Wallpaper" />
   <public type="style" name="Theme.Wallpaper.NoTitleBar" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 250612f..0902c21 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1848,7 +1848,7 @@
     <!-- Title of notification shown when ADB is actively connected to the phone. -->
     <string name="adb_active_notification_title">USB debugging connected</string>
     <!-- Message of notification shown when ADB is actively connected to the phone. -->
-    <string name="adb_active_notification_message">A computer is connected to your phone.</string>
+    <string name="adb_active_notification_message">Select to disable USB debugging.</string>
 
     <!-- Used to replace %s in urls retreived from the signin server with locales.  For Some        -->
     <!-- devices we don't support all the locales we ship to and need to replace the '%s' with a    -->
@@ -1858,7 +1858,7 @@
     <string name="locale_replacement">""</string>
 
     <!-- Title of the pop-up dialog in which the user switches input method components. -->
-    <string name="select_input_method">Select Input Method</string>
+    <string name="select_input_method">Select input method</string>
 
     <string name="fast_scroll_alphabet">\u0020ABCDEFGHIJKLMNOPQRSTUVWXYZ</string>
     <string name="fast_scroll_numeric_alphabet">\u00200123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ</string>
@@ -1974,5 +1974,8 @@
     <string name="wallpaper_binding_label">Wallpaper</string>
     <!-- Dialog title for user to select a different wallpaper from service list -->
     <string name="chooser_wallpaper">Change wallpaper</string>
-    
+
+    <!-- Do Not Translate: Alternate eri.xml -->
+    <string name="alternate_eri_file">/data/eri.xml</string>
+
 </resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 18b97657..a2ceb8f 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -49,15 +49,15 @@
         <item name="centerMedium">@android:drawable/popup_center_medium</item>
     </style>
     
-    <!-- Animations -->
+    <!-- Base style for animations.  This style specifies no animations. -->
     <style name="Animation" />
     
     <!-- Standard animations for a full-screen window or activity. -->
     <style name="Animation.Activity">
-        <item name="activityOpenEnterAnimation">@anim/task_open_enter</item>
-        <item name="activityOpenExitAnimation">@anim/task_open_exit</item>
-        <item name="activityCloseEnterAnimation">@anim/task_close_enter</item>
-        <item name="activityCloseExitAnimation">@anim/task_close_exit</item>
+        <item name="activityOpenEnterAnimation">@anim/activity_open_enter</item>
+        <item name="activityOpenExitAnimation">@anim/activity_open_exit</item>
+        <item name="activityCloseEnterAnimation">@anim/activity_close_enter</item>
+        <item name="activityCloseExitAnimation">@anim/activity_close_exit</item>
         <item name="taskOpenEnterAnimation">@anim/task_open_enter</item>
         <item name="taskOpenExitAnimation">@anim/task_open_exit</item>
         <item name="taskCloseEnterAnimation">@anim/task_close_enter</item>
@@ -88,8 +88,15 @@
         <item name="windowExitAnimation">@anim/status_bar_exit</item>
     </style>
 
-    <!-- Standard animations for a translucent window or activity. -->
+    <!-- Standard animations for a translucent window or activity.  This
+         style is <em>not<em> used by default for the translucent theme
+         (since translucent activities are a special case that have no
+         clear UI paradigm), but you can make your own specialized theme
+         with this animation style if you would like to have the standard
+         platform transition animation. -->
     <style name="Animation.Translucent">
+        <item name="windowEnterAnimation">@anim/translucent_enter</item>
+        <item name="windowExitAnimation">@anim/translucent_exit</item>
     </style>
 
     <!-- Standard animations for a non-full-screen window or activity. -->
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index bfdce1e..3b9590d 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -306,19 +306,22 @@
     <style name="Theme.Translucent">
         <item name="android:windowBackground">@android:color/transparent</item>
         <item name="android:windowIsTranslucent">true</item>
-        <item name="android:windowAnimationStyle">@android:style/Animation.Translucent</item>
+        <!-- Note that we use the base animation style here (that is no
+             animations) because we really have no idea how this kind of
+             activity will be used. -->
+        <item name="android:windowAnimationStyle">@android:style/Animation</item>
     </style>
 
     <!-- Variant of the translucent theme with no title bar -->
     <style name="Theme.Translucent.NoTitleBar">
         <item name="android:windowNoTitle">true</item>
+        <item name="android:windowContentOverlay">@null</item>
     </style>
 
     <!-- Variant of the translucent theme that has no title bar and
          fills the entire screen -->
     <style name="Theme.Translucent.NoTitleBar.Fullscreen">
         <item name="android:windowFullscreen">true</item>
-        <item name="android:windowContentOverlay">@null</item>
     </style>
     
     <!-- Default theme for activities that don't actually display a UI; that
diff --git a/docs/html/guide/appendix/api-levels.jd b/docs/html/guide/appendix/api-levels.jd
index a4dcc5e..acf6899 100644
--- a/docs/html/guide/appendix/api-levels.jd
+++ b/docs/html/guide/appendix/api-levels.jd
@@ -100,8 +100,7 @@
 <li>It lets applications describe the framework API revision that they
 require</li>
 <li>It lets the system negotiate the installation of applications on the user's
-device, such that version-incompatible applications are not installed on a
-user's device</li>
+device, such that version-incompatible applications are not installed.</li>
 </ul>
 
 <p>Each Android platform version stores its API Level identifier internally, in
@@ -137,7 +136,7 @@
 the system assumes that the application requires API Level 1. </li>
 <li>If a <code>android:maxSdkVersion</code> attribute is declared, its value
 must be equal to or greater than the system's API Level integer. 
-in the system itself. If not declared, the system assumes that the application
+If not declared, the system assumes that the application
 has no maximum API Level. </li>
 </ul>
 
@@ -154,7 +153,7 @@
 <code>android:minSdkVersion</code> is to tell the Android system that it is
 using APIs that were <em>introduced</em> in the API Level specified. If the
 application were to be somehow installed on a platform with a lower API Level,
-then it would crash at run-time when it tries to access APIs that don't exist.
+then it would crash at run-time when it tried to access APIs that don't exist.
 The system prevents such an outcome by not allowing the application to be
 installed if the lowest API Level it requires is higher than that of the
 platform version on the target device.</p>
@@ -194,7 +193,7 @@
 application and use it successfully, then later receive an OTA update to a new
 version of the Android platform. Once the update is installed, your application
 will run in a new run-time version of the environment, but one that has the API
-and system capabilities that it depends on. </p>
+and system capabilities that your application depends on. </p>
 
 <p>In some cases, changes <em>below</em> the API, such those in the underlying
 system itself, may affect your application when it is run in the new
@@ -222,8 +221,8 @@
 <p>Although it's unlikely that an Android-powered device would be downgraded to
 a previous version of the platform, it's important to realize that there are
 likely to be many devices in the field that run earlier versions of the
-platform. Even among devices that receive OTA updates, some might lag and not
-receive an update for a significant amount of time. </p>
+platform. Even among devices that receive OTA updates, some might lag and
+might not receive an update for a significant amount of time. </p>
 
 <h3 id="platform">Selecting a platform version and API Level</h3>
 
@@ -285,39 +284,32 @@
 of the Android platform it runs. See the table at the top of this document for
 a list of platform versions and their API Levels. </p>
 
-<!--
-The Framework API makeup: the API available in a specific platform version is
-made up of API parts introduced in previous versions, plus some parts that are
-new.
--->
 
 <h2 id="filtering">Filtering the Reference Documentation by API Level</h2>
 
 <p>Reference documentation pages on the Android Developers site offer a "Filter
-by API Level" control in the top-right area of each page. </p>
+by API Level" control in the top-right area of each page. You can use the 
+control to show documentation only for parts of the API that are actually 
+accessible to your application, based on the API Level that it specifies in 
+the <code>android:minSdkVersion</code> attribute of its manifest file. </p>
 
-<p>The "Filter by API Level" lets you show documentation only for parts of the
-API that are actually accessible to your application, based on the API Level
-that it specifies in the <code>minSdkVersion</code> attribute in its manifest 
-file </p>
+<p>To use filtering, set the control to the same API Level as that specified
+by your application. Notice that APIs introduced in a later API Level are 
+then grayed out and their content is masked, since they would not be
+accessible to your application. </p>
 
-<p>When you filter the reference documentation by an API level, only the APIs
-available at that API level are shown. APIs introduced in a later API level are
-grayed out and their content is masked, since they would not be accessible to
-your application. </p>
-
-<p>Note that filtering by API Level in the documentation does not provide a view
-of what is new or introduced in each API Level. Filtering simply provides a way
+<p>Filtering by API Level in the documentation does not provide a view
+of what is new or introduced in each API Level &mdash; it simply provides a way
 to view the entire API associated with a given API Level, while excluding API
 elements introduced in later API Levels.</p>
 
 <p>By default, API Level filtering is enabled and set to show the latest API
-Level. If you do not want to use filtering reference documentation, select the
-highest available API Level.</p>
+Level. If you do not want to use filtering reference documentation, 
+simply select the highest available API Level. </p>
 
-<p>Note that the reference documentation for API elements also specifies the API
-Level at which the element was introduced. The API Level for packages and
-classes is specified as "Since &lt;api level&gt;" at the top-right corner of the
-content area on each documentation page. The API Level for each class member is
-specified in the member's detailed description section header, at the right
-margin. </p>
+<p>Also note that the reference documentation for individual API elements
+specifies the API Level at which the elements were introduced. The API Level 
+for packages and classes is specified as "Since &lt;api level&gt;" at the 
+top-right corner of the content area on each documentation page. The API Level 
+for class members is specified in their detailed description headers, 
+at the right margin. </p>
diff --git a/docs/html/guide/topics/manifest/uses-sdk-element.jd b/docs/html/guide/topics/manifest/uses-sdk-element.jd
index ee8d03d..aa1e8ae 100644
--- a/docs/html/guide/topics/manifest/uses-sdk-element.jd
+++ b/docs/html/guide/topics/manifest/uses-sdk-element.jd
@@ -36,30 +36,27 @@
 <dd>
 <dl class="attr">
   <dt><a name="min"></a>{@code android:minSdkVersion}</dt>
-  <dd>An integer designating the minimum level of the Android API that's required 
-  for the application to run.
+  <dd>An integer designating the minimum API Level required
+  for the application to run. The Android system will prevent the user from installing
+  the application if the system's API Level is lower than the value specified in
+  this attribute. You should always declare this attribute.
   
-  <p>Prior to installing an application, the Android system checks the value of this
-  attribute and allows the installation only if it
-  is less than or equal to the API Level used by the system itself.</p>
-  
-  <p>If you do not declare this attribute, then a value of "1" is assumed, which
+  <p class="caution"><strong>Caution:</strong>
+  If you do not declare this attribute, then a value of "1" is assumed, which
   indicates that your application is compatible with all versions of Android. If your
-  application is <em>not</em> universally compatible (for instance if it uses APIs
-  introduced in Android 1.5) and you have not declared the proper <code>minSdkVersion</code>, 
-  then when installed on a system with a lower API Level, the application 
-  will crash during runtime. For this reason, be certain to declare the appropriate API Level
+  application is <em>not</em> compatible with all versions (for instance, it uses APIs
+  introduced in API Level 3) and you have not declared the proper <code>minSdkVersion</code>,
+  then when installed on a system with an API Level less than 3, the application will crash
+  during runtime when attempting to access the unavailable APIs. For this reason, 
+  be certain to declare the appropriate API Level
   in the <code>minSdkVersion</code> attribute.</p>
   </dd>
   
   <dt><a name="max"></a>{@code android:maxSdkVersion}</dt>
-  <dd>An integer designating the maximum level of the Android API that the application is 
-  compatible with. You can use this to ensure your application is filtered out
-  of later versions of the platform when you know you have incompatibility with them.</p>
-  
-  <p>Prior to installing an application, the Android system checks the value of this
-  attribute and allows the installation only it
-  is greater than or equal to the API Level used by the system itself.</p>
+  <dd>An integer designating the maximum API Level on which the application is 
+  designed to run. The Android system will prevent the user from installing the 
+  application if the system's API Level is higher than the value specified
+  in this attribute. 
   
   <p>Introduced in: API Level 4</p>
   </dd>
diff --git a/docs/html/guide/topics/resources/available-resources.jd b/docs/html/guide/topics/resources/available-resources.jd
index 2a6a6ac..0dfc625 100644
--- a/docs/html/guide/topics/resources/available-resources.jd
+++ b/docs/html/guide/topics/resources/available-resources.jd
@@ -36,6 +36,7 @@
       </ol>
     </li>
     <li><a href="#stylesandthemes">Styles and Themes</a></li>
+    <li><a href="#Searchable">Searchable</a></li>
   </ol>
 
 </div>
@@ -86,7 +87,7 @@
     <code>&lt;color&gt;</code> tags.
 </p>
 <p>
-    <strong>Resource source file location</strong>: res/values/<em>colors</em>.xml (file name is arbitrary)
+    <strong>Resource source file location</strong>: {@code res/values/<em>colors</em>.xml} (File name is arbitrary.)
 </p>
 <p>
     <strong>Compiled resource datatype:</strong> Resource pointer to a Java int.
@@ -183,7 +184,7 @@
     <strong>Source file format:</strong> XML file requiring a <code>&lt;?xml version="1.0" encoding="utf-8"?&gt;</code> declaration, and a root <code>&lt;resources&gt;</code> element containing one or more <code>&lt;string&gt;</code> tags.
 </p>
 <p>
-    <strong>Resource source file location</strong>: res/values/<em>strings</em>.xml (file name is arbitrary)
+    <strong>Resource source file location</strong>: {@code res/values/<em>strings</em>.xml} (File name is arbitrary.)
 </p>
 <p>
     <strong>Compiled resource datatype:</strong> Resource pointer to a Java CharSequence.
@@ -338,8 +339,8 @@
 <code>&lt;resources&gt;</code> element containing one or more
 <code>&lt;dimen&gt;</code> tags.</p>
 
-<p><strong>Resource source file location</strong>: res/values/dimens.xml (File
-name is arbitrary; standard practice is to put all dimensions in one file
+<p><strong>Resource source file location</strong>: {@code res/values/dimens.xml} (File
+name is arbitrary, but standard practice is to put all dimensions in one file
 devoted to dimensions.)</p>
 <p><strong>Compiled resource datatype:</strong> Resource pointer to a
 dimension.</p>
@@ -424,7 +425,7 @@
     <strong>Source file formats:</strong> png (preferred), jpg (acceptable), gif (discouraged). One resource per file.
 </p>
 <p>
-    <strong>Resource file location</strong>: res/drawable/<em>some_file</em>.png or <em>some_file</em>.jpg or <em>some_file</em>.gif.
+    <strong>Resource file location</strong>: {@code res/drawable/<em>some_file</em>.png}
 </p>
 <p>
     <strong>Compiled resource datatype:</strong> Resource pointer to a {@link android.graphics.drawable.BitmapDrawable BitmapDrawable}.
@@ -453,7 +454,8 @@
 <code>&lt;resources&gt;</code> element containing one or more
 <code>&lt;drawable&gt;</code> tags.</p>
 <p>
-    <strong>Resource source file location</strong>: res/values/colors.xml (File name is arbitrary; standard practice is to put the PaintDrawable items in the file along with the <a href="resources-i18n.html#numericcolorresources">numeric color values</a>.)
+    <strong>Resource source file location</strong>: {@code res/values/colors.xml} (File name is arbitrary, but standard practice is to put the PaintDrawable 
+    items in the file along with the <a href="resources-i18n.html#numericcolorresources">numeric color values</a>.)
 </p>
 <p>
     <strong>Compiled resource datatype:</strong> Resource pointer to a {@link android.graphics.drawable.PaintDrawable}.
@@ -540,7 +542,7 @@
     <strong>Source file format:</strong> PNG &mdash; one resource per file
 </p>
 <p>
-    <strong>Resource source file location</strong>: res/drawable/<em>some_name</em>.9.png (must end in .9.png)
+    <strong>Resource source file location</strong>: {@code res/drawable/<em>some_name</em>.9.png} (Filename must end in {@code .9.png})
 </p>
 <p>
     <strong>Compiled resource datatype:</strong> Resource pointer to a {@link android.graphics.drawable.NinePatchDrawable NinePatchDrawable}.
@@ -573,7 +575,7 @@
     <strong>Source file format:</strong> XML file, one resource per file, one root tag with no <code>&lt;?xml&gt;</code> declaration
 </p>
 <p>
-    <strong>Resource file location</strong>: res/anim/<em>some_file</em>.xml
+    <strong>Resource file location</strong>: {@code res/anim/<em>some_file</em>.xml}
 </p>
 <p>
     <strong>Compiled resource datatype:</strong> Resource pointer to an {@link android.view.animation.Animation}.
@@ -1055,7 +1057,7 @@
     <strong>Source file format:</strong> XML file without an <code>&lt;?xml&gt;</code> declaration, and a <code>&lt;resources&gt;</code> root element containing one or more custom element tags.
 </p>
 <p>
-    <strong>Resource file location</strong>: res/values/<em>attrs</em>.xml (file name is arbitrary).
+    <strong>Resource file location</strong>: {@code res/values/<em>attrs</em>.xml} (File name is arbitrary.)
 </p>
 <p>
     <strong>Compiled resource datatype:</strong> Resource pointer to a {@link android.view.View} (or subclass) resource.
@@ -1084,7 +1086,7 @@
     <strong>Source file format:</strong> XML file requiring a <code>&lt;?xml version="1.0" encoding="utf-8"?&gt;</code> declaration, and a root <code>&lt;resources&gt;</code> element containing one or more <code>&lt;style&gt;</code> tags.
 </p>
 <p>
-    <strong>Resource source file location</strong>: res/values/styles.xml (file name is arbitrary). The file name is arbitrary, but standard practice is to put all styles into a file named styles.xml.
+    <strong>Resource source file location</strong>: {@code res/values/styles.xml} (File name is arbitrary, but standard practice is to put all styles into a file named styles.xml.)
 </p>
 <p>
     <strong>Compiled resource datatype:</strong> Resource pointer to a Java CharSequence.
@@ -1133,3 +1135,317 @@
 
 <p>For examples of how to declare and apply styles and themes, read 
 <a href="{@docRoot}guide/topics/ui/themes.html">Applying Styles and Themes</a>.</p>
+
+
+
+<h2 id="Searchable">Searchable</h2>
+
+<p>To make search appear to the user as a seamless system-wide feature, the Android framework 
+offers APIs that let applications control how they are searched.
+Applications can customize how search is invoked, how the search dialog looks, and what type of 
+search results are available, including suggestions that are shown as the user types.</p>
+
+<p>In order to utilize the Android search framework, an application must provide a search configuration
+in the form of an XML resource.
+This section describes the search configuration XML in terms of its syntax and usage. For a more
+complete discussion about how to implement search features for your application, see
+<!-- <a href="{@docRoot}guide/topics/search/index.html">Search</a> -->
+{@link android.app.SearchManager}.</p>
+
+<p>
+  <strong>Source file format:</strong> 
+  XML file requiring a <code>&lt;?xml version="1.0" encoding="utf-8"?&gt;</code> 
+  declaration, and a root <code>&lt;searchable&gt;</code> element.
+</p>
+
+<p>
+  <strong>Resource source file location</strong>: {@code res/xml/searchable.xml} 
+  (The file name is arbitrary, but standard practice is to use searchable.xml.)
+</p>
+
+<p>
+  <strong>Compiled resource datatype:</strong> 
+  Resource pointer to an xml object.
+</p>
+
+<p>
+  <strong>Resource reference name:</strong>
+</p>
+
+<ul>
+  <li>
+    <strong>Java:</strong> 
+    <code>R.xml.<em>filename</em></code>.
+  </li>
+  <li>
+    <strong>XML:</strong> 
+    <code>@[<em>package</em>:]xml/<em>filename</em></code> (e.g., <code>@xml/searchable</code>).
+  </li>
+</ul>
+
+<p>
+  <strong>Syntax</strong>
+</p>
+
+<pre>
+&lt;searchable xmlns:android="http://schemas.android.com/apk/res/android
+     android:label="@string/search_label" 
+     ... &gt;
+     <em>&lt;actionkey
+          android:keycode="KEYCODE_CALL"
+          ... &gt;</em>     
+&lt;/searchable&gt;
+</pre>
+
+<dl>
+  <dt>
+    &lt;searchable&gt;
+  </dt>
+  <dd>
+    Defines all application search configurations, including settings for text and voice searches
+    performed within the application. It accepts the following attributes:
+    <ul>
+      <li>
+        <em>label</em> - <strong>Required</strong>. This is the name for your application, as it 
+        will appear to the user. This will be visible only if <em>searchMode</em> is set to 
+        "showSearchLabelAsBadge" (see below).
+      </li>
+      <li>
+        <em>hint</em> -	This is the text to display in the search text field when no text has 
+        been entered. This is recommended in order to provide context to the search about to be 
+        performed (e.g., "Search the Dictionary").
+      </li>
+      <li>
+        <em>searchMode</em> - If provided and non-zero, this sets additional modes for control
+        of the search presentation. The following mode values are accepted: 
+        <ul>
+          <li>
+            <em>showSearchLabelAsBadge</em> - If set, this enables the display of the 
+            search target (label) within the search bar.
+          </li>
+          <li>
+            <em>queryRewriteFromData</em> - If set, this causes the suggestion column 
+            SUGGEST_COLUMN_INTENT_DATA to be considered as the text for suggestion query 
+            rewriting. This should only be used when the values in 
+            SUGGEST_COLUMN_INTENT_DATA are suitable for user inspection and editing -
+            typically, HTTP/HTTPS Uri's.
+          </li>
+          <li>
+            <em>queryRewriteFromText</em> - If set, this causes the suggestion 
+            column SUGGEST_COLUMN_TEXT_1 to be considered as the text for suggestion query
+            rewriting. This should be used for suggestions in which no query 
+            text is provided and the SUGGEST_COLUMN_INTENT_DATA values are not suitable 
+            for user inspection and editing.
+          </li>
+        </ul>
+        <p>More than one of the above values for <em>searchMode</em> can be used at once. For 
+        example, you can declare two modes at once, like this:
+        <code>searchMode="queryRewriteFromData|queryRewriteFromText"</code>
+      </li>
+      <li>
+        <em>inputType</em> - If provided, supplies a hint about the type of search text 
+        the user will be entering. For most searches, in which free form text is expected, 
+        this attribute is not needed. See
+        {@link android.R.attr#inputType} for a list of suitable values for this attribute.
+      </li>
+      <li>
+        <em>imeOptions</em> - If provided, supplies additional options for the input method. 
+        For most searches, in  which free form text is expected, this attribute is not needed, 
+        and will default to "actionSearch". See 
+        {@link android.R.attr#imeOptions} for a list of suitable values for this attribute.
+      </li>
+    </ul>
+    
+    <p>If you have defined a content provider to generate search suggestions, you need to
+    provide some more searchable metadata in order to configure communications with the content
+    provider. The following are additional {@code &lt;searchable>} attributes for use when 
+    providing search suggestions:</p>
+    
+    <ul>
+      <li>
+        <em>searchSuggestAuthority</em> - <strong>Required to provide search suggestions</strong>. 
+        This value must match the authority string provided in the provider section of your manifest.
+      </li>
+      <li>
+        <em>searchSuggestPath</em> - If provided, this path will be inserted in the suggestions 
+        query Uri, after the authority you have provide but before the standard suggestions path.
+        This is only required if you have a single content provider issuing different types 
+        of suggestions (e.g. for different data types) and you need 
+        a way to disambiguate the suggestions queries when they are received.
+      </li>
+      <li>
+        <em>searchSuggestSelection</em> - If provided, this value will be passed into your 
+        query function as the selection parameter. Typically this will be a WHERE clause for 
+        your database, and will contain a single question mark, which represents the actual query
+        string that has been typed by the user. However, you can also use any non-null value to simply
+        trigger the delivery of the query text (via selection arguments), and then use the query 
+        text in any way appropriate for your provider (ignoring the actual text of the selection parameter.)
+      </li>
+      <li>
+        <em>searchSuggestIntentAction</em> - The default Intent action to be used when a user 
+        clicks on a search suggestion.
+        If provided, and not overridden by the selected suggestion, this value will 
+        be placed in the action field of the {@link android.content.Intent} when the 
+        user clicks a suggestion.
+      </li>
+      <li>
+        <em>searchSuggestIntentData</em> - The default Intent data to be used when a user 
+        clicks on a search suggestion.
+        If provided, and not overridden by the selected suggestion, this value will be 
+        placed in the data field of the {@link android.content.Intent} when the user clicks 
+        a suggestion.
+      </li>
+    </ul>
+    
+    <p>Beyond providing search suggestions while using your application's local search, you 
+    can also configure your search suggestions to be made available to Quick Search Box, 
+    which will allow users so receive search suggestions from your application content from outside
+    your application. The following are additional {@code &lt;searchable>} attributes for use when 
+    providing search suggestions to Quick Search Box:</p>
+    
+    <ul>
+      <li>
+        <em>includeInGlobalSearch</em> - <strong>Required to provide search suggestions in
+        Quick Search Box</strong>. If true, this indicates the search suggestions provided by your 
+        application should be included in the globally accessible Quick Search Box. The user must
+        still enable your application as a searchable item in the system search settings in order
+        for your suggestions to appear in Quick Search Box.
+      </li>
+      <li>
+        <em>searchSettingsDescription</em> - If provided, this provides a brief description
+        of the search suggestions that you provide to Quick Search Box, 
+        and will be displayed in the search settings entry for your application.
+      </li>
+      <li>
+        <em>queryAfterZeroResults</em> - Indicates whether a source should be invoked for 
+        supersets of queries it has returned zero results for in the past. For example, if a
+        source returned zero results for "bo", it would be ignored for "bob". If set to false,
+        this source will only be ignored for a single session; the next time the search dialog
+        is invoked, all sources will be queried. The default value is false.
+      </li>
+      <li>
+        <em>searchSuggestThreshold</em> - Indicates the minimum number of characters needed to
+        trigger a source lookup from Quick Search Box. Only guarantees that a source will not be
+        queried for anything shorter than the threshold. The default value is 0.
+      </li>
+    </ul>
+    
+    <p>To enable voice search for your Activity, you can add fields to the searchable metadata 
+    that enable and configure voice search. The following are additional {@code &lt;searchable>} 
+    attributes for use when implementing voice search:</p>
+    
+    <ul>
+        <li>
+          <em>voiceSearchMode</em> -  <strong>Required to provide voice search 
+          capabilities</strong>. 
+          If provided and non-zero, enables voice search. 
+          (Voice search may not be provided by the device, in which case these flags will
+          have no effect.) The following mode values are accepted:
+          <ul>
+            <li>
+              <em>showVoiceSearchButton</em> - If set, display a voice search button. This only 
+              takes effect if voice search is available on the device. If set, then "launchWebSearch" 
+              or "launchRecognizer" must also be set.
+            </li>
+            <li>
+              <em>launchWebSearch</em> - If set, the voice search button will take the user directly 
+              to a built-in voice web search activity. Most applications will not use this flag, as 
+              it will take the user away from the activity in which search was invoked.
+            </li>
+            <li>
+              <em>launchRecognizer</em> - If set, the voice search button will take 
+              the user directly to a built-in voice recording activity. This activity 
+              will prompt the user to speak, transcribe the spoken text, and forward the resulting 
+              query text to the searchable activity, just as if the user had typed it into the 
+              search UI and clicked the search button.
+            </li>
+          </ul>
+        </li>
+        <li>
+          <em>voiceLanguageModel</em> - A string constant from 
+          {@link android.speech.RecognizerIntent}.
+          If provided, this specifies the language model that 
+          should be used by the voice recognition system. See 
+          {@link android.speech.RecognizerIntent#EXTRA_LANGUAGE_MODEL } for more 
+          information. If not provided, the default value 
+          {@link android.speech.RecognizerIntent#LANGUAGE_MODEL_FREE_FORM } will be used.
+        </li>
+        <li>
+          <em>voicePromptText</em> - A string. If provided, this specifies a prompt 
+          that will be displayed during voice input. If not provided, a default prompt 
+          will be displayed.
+        </li>
+        <li>
+          <em>voiceLanguage</em> - A string constant from {@link java.util.Locale}. 
+          If provided, this specifies the spoken language to be expected. 
+          This is only needed if it is different from the current value of 
+          {@link java.util.Locale#getDefault()}. 
+        </li>
+        <li>
+          <em>voiceMaxResults</em> - If provided, enforces the maximum number of results to return, 
+          including the "best" result which will always be provided as the SEARCH intent's primary 
+          query. Must be one or greater. Use EXTRA_RESULTS to get the results from the intent. 
+          If not provided, the recognizer will choose how many results to return.
+        </li>
+    </ul>
+  </dd>
+  
+  <dt>
+      &lt;actionkey&gt;
+  </dt>
+  <dd>
+    Defines a shortcut key for a search action.
+    <ul>
+      <li>
+        <em>keycode</em> - <strong>Required</strong>. This attribute denotes the action key
+        you wish to respond to. Note that not all action keys are actually supported using 
+        this mechanism, as many of them are used for typing, 
+        navigation, or system functions. This will be added to the 
+        {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} Intent that is passed to your 
+        searchable Activity. To examine the key code, use 
+        {@link android.content.Intent#getIntExtra getIntExtra(SearchManager.ACTION_KEY)}.
+        Note that, in addition to the keycode, you must also provide one or more of 
+        the action specifier attributes below.
+      </li>
+      <li>
+        <em>queryActionMsg</em> - If you wish to handle an action key during normal 
+        search query entry, you must define an action string here. This will be added to the
+        {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} Intent that is 
+        passed to your searchable Activity. To examine the string, use 
+        {@link android.content.Intent#getStringExtra
+        getStringExtra(SearchManager.ACTION_MSG)}.
+      </li>
+      <li>
+        <em>suggestActionMsg</em> - If you wish to handle an action key while a 
+        suggestion is being displayed and selected, there are two ways to handle this. 
+        If all of your suggestions can handle the action key, you can simply define 
+        the action message using this attribute. This will be added to the 
+        {@link android.content.Intent#ACTION_SEARCH} Intent that is passed to your 
+        searchable Activity. To examine the string, 
+        use {@link android.content.Intent#getStringExtra 
+        getStringExtra(SearchManager.ACTION_MSG)}.
+      </li>
+      <li>
+        <em>suggestActionMsgColumn</em> - If you wish to handle an action key while
+        a suggestion is being displayed and selected, but you do not wish to enable
+        this action key for every suggestion, then you can use this attribute to control 
+        it on a suggestion-by-suggestion basis. First, you must define a column 
+        (and name it here) where your suggestions will include the action string. Then,
+        in your content provider, you must provide this column, and when desired, 
+        provide data in this column. The search manager will look at your suggestion cursor, 
+        using the string provided here in order to select a column, and will use 
+        that to select a string from the cursor. That string will be added to the 
+        {@link android.content.Intent#ACTION_SEARCH ACTION_SEARCH} 
+        Intent that is passed to your searchable Activity. To examine 
+        the string, use {@link android.content.Intent#getStringExtra 
+        getStringExtra(SearchManager.ACTION_MSG)}. If the data does not exist for the 
+        selection suggestion, the action key will be ignored.
+      </li>
+    </ul>
+  </dd>
+</dl>
+
+
+
+
+
diff --git a/docs/html/index.jd b/docs/html/index.jd
index 6945f9e..dc8bf2f 100644
--- a/docs/html/index.jd
+++ b/docs/html/index.jd
@@ -15,7 +15,7 @@
                                 <div id="announcement" style="width:275px">
                                   <p>The second Android Developer Challenge has begun! In this contest,
                                   real-world users will help review and score applications and the overall winner will 
-                                  take away $250,000. The deadline for submissions was August 31, 2009 and judging by users has started.</p>
+                                  take away $250,000. The deadline for submissions was August 31, 2009.</p>
                                   <p><a href="http://code.google.com/android/adc/">Learn more about ADC 2 &raquo;</a></p>
                                 </div> <!-- end annoucement -->
                             </div> <!-- end annoucement-block -->  
diff --git a/docs/html/intl/ja/index.jd b/docs/html/intl/ja/index.jd
index a5378c9..3ed2357 100644
--- a/docs/html/intl/ja/index.jd
+++ b/docs/html/intl/ja/index.jd
@@ -56,7 +56,7 @@
                                       <td>
                                               <h2 class="green">公開</h2>
                                               <p>Android マーケットは、アプリケーションを携帯端末に配信するためのオープン サービスです。</p>
-                                              <p><a href="http://www.android.com/market.html">詳細 &raquo;</a></p>
+                                              <p><a href="http://market.android.com/publish/Home">詳細 &raquo;</a></p>
                                       </td>
                               </tr>
                               <tr>
@@ -118,10 +118,10 @@
     'sdk': {
       'layout':"imgLeft",
       'icon':"sdk-small.png",
-      'name':"SDK 1.5 r3",
-      'img':"sdk-large.png",
-      'title':"Android 1.5 SDK",
-      'desc': "<p>Android 1.5 SDK の最新バージョンが公開されました。このリリースには Android 1.5 用の API、最新版デベロッパーツール、複数プラットフォーム(バージョン)サポート、そして Google API のアドオンが含まれています。</p><p><a href='{@docRoot}sdk/1.5_r3/index.html'>Android 1.5 SDK をダウンロード &raquo;</a></p>"
+      'name':"SDK 1.6 r1",
+      'img':"donut-android.png",
+      'title':"Android 1.6 SDK",
+      'desc': "<p>Android 1.6 SDK の最新バージョンが公開されました。このリリースには Android 1.6 用の API、最新版デベロッパーツール、複数プラットフォーム(バージョン)サポート、そして Google API のアドオンが含まれています。</p><p><a href='{@docRoot}sdk/1.6_r1/index.html'>Android 1.6 SDK をダウンロード &raquo;</a></p>"
     },
     
     'io': {
diff --git a/docs/html/sdk/1.6_r1/requirements.jd b/docs/html/sdk/1.6_r1/requirements.jd
index 781ee32..8e698fa 100644
--- a/docs/html/sdk/1.6_r1/requirements.jd
+++ b/docs/html/sdk/1.6_r1/requirements.jd
@@ -11,7 +11,7 @@
 <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 Hardy Heron)</li>
 </ul>
 
 <h3>Supported Development Environments</h3>
diff --git a/docs/html/sdk/1.6_r1/upgrading.jd b/docs/html/sdk/1.6_r1/upgrading.jd
index 2f9cc73..ebe6a95 100644
--- a/docs/html/sdk/1.6_r1/upgrading.jd
+++ b/docs/html/sdk/1.6_r1/upgrading.jd
@@ -219,7 +219,7 @@
 building in alternate support or graceful degradation, or you can specify them 
 as hardware requirements in a 
 <a href="{@docRoot}guide/topics/manifest/uses-configuration-element.html"><code>&lt;uses-configuration&gt;</code>.</a>
-element in the application's manifest file. Also see the <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html"><code>&lt;uses-feature&gt;</code>
+element in the application's manifest file. Also see the <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html"><code>&lt;uses-feature&gt;</code></a>
 manifest element, which lets your application declare a requirement for 
 specific features, such as an OpenGL ES version or a camera that has 
 autofocus capability.
@@ -258,7 +258,7 @@
 starting with Android 1.6, the platform provides a Compatibility Mode that
 automatically scales the UI of applications if they do not explicitly indicate
 support for the current screen in the 
-<a href="{@docRoot}guide/topics/manifest/supports-screen-element.html"><code>&lt;supports-screen&gt;</code>
+<a href="{@docRoot}guide/topics/manifest/supports-screen-element.html"><code>&lt;supports-screen&gt;</code></a>
 element in their manifest files. As part of testing, you should evaluate how
 your application is displayed in Compatibility Mode on different screens. </p>
   </li>
diff --git a/docs/html/sdk/android-1.6-highlights.jd b/docs/html/sdk/android-1.6-highlights.jd
new file mode 100644
index 0000000..74dcd9f
--- /dev/null
+++ b/docs/html/sdk/android-1.6-highlights.jd
@@ -0,0 +1,213 @@
+page.title=Android 1.6 Platform Highlights
+sdk.date=September 2009
+
+@jd:body
+
+
+<style type="text/css">
+#jd-content div.screenshot,
+#jd-content div.video {
+  float:right;
+  clear:right;
+  padding:15px 70px;
+  font-size:.9em;
+  font-weight:bold;
+  line-height:1.7em;
+}
+#jd-content div.video {
+  padding-top:0;
+  margin-top:-15px;
+}
+#jd-content div.screenshot img {
+  margin:0;
+}
+</style>
+
+<div class="video">
+<object width="293" height="180">
+<param name="movie" value="http://www.youtube.com/v/MBRFkLKRwFw&hl=en&fs=1&"></param>
+<param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param>
+<embed src="http://www.youtube.com/v/MBRFkLKRwFw&hl=en&fs=1&" type="application/x-shockwave-flash" 
+allowscriptaccess="always" allowfullscreen="true" width="293" height="180"></embed>
+</object>
+</div>
+
+
+<p>The Android 1.6 platform introduces new features for users and developers. 
+This page provides an overview of some new features and technologies.</p>
+
+<ul>
+  <li><a href="#UserFeatures">New User Features</a></li>
+  <li><a href="#AndroidMarketUpdates">Android Market Updates</a></li>
+  <li><a href="#PlatformTechnologies">New Platform Technologies</a></li>
+</ul>
+
+
+    
+<h2 id="UserFeatures" style="clear:right">New User Features</h2>
+
+<!-- screenshots float right -->
+
+<div class="screenshot">
+<img src="images/search.png" class="screenshot" alt="" /><br/>
+Quick Search Box
+</div>
+ 
+<div class="screenshot">
+<img src="images/camera.png" class="screenshot" alt="" /><br/>
+New Camera/Camcorder UI
+</div>
+
+<div class="screenshot">
+<img src="images/battery.png" class="screenshot" alt="" /><br/>
+Battery Usage Indicator
+</div>
+
+
+<h3 id="QuickSearchBox">Quick Search Box for Android</h3>
+
+<p>Android 1.6  includes a redesigned search framework that provides a quick, 
+effective, and consistent way for users to search across multiple sources&mdash;such as 
+browser bookmarks &amp; history, contacts, and the web&mdash;directly from 
+the home screen.</p>
+
+<p>The system constantly learns which search results are more relevant based on what is 
+clicked. So popular contacts or apps that have previously been picked will bubble up to 
+the top when a user types the first few letters of a relevant query.</p>
+
+<p>The search framework also provides developers a way to easily expose relevant 
+content from their applications in Quick Search Box.</p>
+
+<h3 id="Camera">Camera, Camcorder, and Gallery</h3>
+
+<p>An updated user interface provides an integrated camera, camcorder, and gallery experience. 
+Users can quickly toggle between still and video capture modes. Additionally, the gallery 
+enables users to select multiple photos for deletion.</p>
+
+<p>Android 1.6 also provides a much faster camera experience.
+Compared to the previous release, launching the camera is now 39% faster, 
+and there is a 28% improvement in the time from completing one shot to the next.</p>
+
+
+<h3 id="VPN">VPN, 802.1x</h3>
+
+<p>A new Virtual Private Network (VPN) control panel in Settings allows users 
+to configure and connect to the following types of VPNs:</p>
+
+<ul>
+  <li>L2TP/IPSEC pre-shared key based VPN</li>
+  <li>L2TP/IPsec certificate based VPN</li>
+  <li>L2TP only VPN</li>
+  <li>PPTP only VPN</li>
+</ul>
+
+
+<h3 id="Battery">Battery usage indicator</h3>
+
+<p>A new battery usage screen lets users see which apps and services are consuming 
+battery power. If the user determines that a particular service or application is 
+using too much power, they can take action to save the battery by
+adjusting settings, stopping the application, or uninstalling the application.</p>
+
+
+<h3 id="A11y">Accessibility</h3>
+
+<p>Users will be able to download new accessibility services built
+on the new Accessibility framework and enable them in Settings.</p>
+
+
+
+
+<h2 id="AndroidMarketUpdates" style="clear:right">Android Market Updates</h2>
+
+<div class="screenshot" style="margin-top:-35px">
+<img src="images/market.png" class="screenshot" alt="" /><br/>
+New Android Market UI
+</div>
+
+<p>For devices with Android Market, the latest version improves the overall user experience and makes
+it easier for users to discover great apps and games from developers.</p>
+
+<ul>
+  <li>At the homescreen, users can choose among <em>Apps</em>, <em>Games</em>, and <em>Downloads</em>.</li>
+  <li>Inside a category, users can explore titles that are <em>Top paid</em>, <em>Top free</em>, and <em>Just in</em>.</li>
+  <li>For each title, users can now see screenshots submitted by developers in addition to 
+  reviews from other users.</li>
+</ul>
+    
+    
+
+
+<h2 id="PlatformTechnologies" style="clear:right">New Platform Technologies</h2>
+
+<h3 id="SearchFramework">Expanded Search Framework</h3>
+
+<p>The Android search framework has been redesigned and expanded to provide
+third-party applications the opportunity to surface
+content from their applications in Quick Search Box, the global search tool. 
+To do this, developers will need to make their app "searchable" and provide 
+suggestions in response to user queries.
+To enable application search suggestions, users simply select each application from which 
+they'd like to receive suggestions, under Searchable items in the Search settings.</p>
+
+
+<h3 id="TTS">Text-to-speech engine</h3>
+
+<p>Android 1.6 features a multi-lingual speech synthesis engine called Pico. 
+It allows any Android application to "speak" a string of text with an accent that matches the language. 
+The engine supports the following languages: English (American and British accents), French, 
+Italian, German and Spanish. If you're using a T-Mobile G1 or Dream device, you'll need to download the 
+SpeechSynthesis Data Installer from Android Market, which includes the "voices" needed by the 
+text-to-speech engine.</p>
+
+
+<h3 id="Gestures">Gestures</h3>
+
+<p>A new gestures framework provides application developers with a framework for creating, storing, 
+loading, and recognizing gestures and associating them with specific actions.</p>
+
+<p>Developers can use the new GestureBuilder tool included in the Android 1.6 SDK to generate libraries 
+of gestures to include with their application.</p>
+
+
+<h3 id="A11y">Accessibility</h3>
+
+<p>Android 1.6 provides a new accessibility framework. 
+With this framework, developers can create accessibility plugins that respond to user input, 
+such as making a sound when a new window is shown, vibrating when navigating to the top of 
+a list, and providing spoken feedback.</p>
+
+
+<h3 id="Screens">Expanded support for screen densities and resolutions</h3>
+
+<p>Android 1.6 adds screen support that enables applications to be rendered properly on different 
+display resolutions and densities. Developers can also specify the types of screens supported by their 
+application.</p>
+
+
+<h3 id="CDMA">Telephony support for CDMA</h3>
+
+<p>Android 1.6 includes support for CDMA in the telephony stack.</p>
+
+
+<h3 id="OpenCore">New version of OpenCore</h3>
+
+<p>Android 1.6 includes the updated OpenCore 2 media engine, which has:</p>
+
+<ul>
+  <li>Support for OpenMAX encoders</li>
+  <li>Support for additional audio codecs in AuthorEngine</li>
+  <li>Improved buffering model supports shared buffers allocated in the decoder</li>
+</ul>
+
+<h3 id="LinuxKernel">2.6.29 Linux kernel</h3>
+
+<p>Android 1.6 upgrades the Linux kernel from 2.6.27 to 2.6.29.</p>
+
+
+<h3 id="DeveloperAPIs">New Framework APIs</h3>
+
+<p>For a detailed overview of new APIs, see the 
+<a href="{@docRoot}sdk/android-1.6.html#api-changes">Version Notes</a>. 
+For a complete report of all API changes, see the 
+<a href="{@docRoot}sdk/api_diff/4/changes.html">API Differences Report</a>.
diff --git a/docs/html/sdk/android-1.6.jd b/docs/html/sdk/android-1.6.jd
index 29dceec..5dd2d95 100644
--- a/docs/html/sdk/android-1.6.jd
+++ b/docs/html/sdk/android-1.6.jd
@@ -11,7 +11,7 @@
 
 <ul>
 <li><a href="#overview">Overview</a>
-<li><a href="#features">New Features</a>
+<li><a href="#features">Release Highlights</a>
 <li><a href="#apps">Built-in Applications</a>
 <li><a href="#locs">Locales</a>
 <li><a href="#api-changes">API Changes</a>
@@ -20,9 +20,9 @@
 <h2 id="overview">Overview</h2>
 
 <p>The Android 1.6 system delivered in the SDK (as library and system image) is
-the development counterpart to the Android 1.6 production system image,
-deployable to Android-powered handsets starting September 2009. The system is fully
-compliant and includes no external libraries.</p>
+the development counterpart to the Android 1.6 production system image, which is
+deployable to Android-powered handsets starting October 2009. The system is
+fully compliant and includes no external libraries. </p>
 
 <p>The Android 1.6 system delivers an updated version of the framework
 API. As with previous versions, the Android 1.6 API 
@@ -32,11 +32,11 @@
 the system, prior to installing the application. </p>
 
 <p>For more information about how to use API Level, see the <a
-href="{@docRoot}guide/developing/">API Levels</a> document. </p>
+href="{@docRoot}guide/appendix/api-levels.html">API Levels</a> document. </p>
 
-<h2 id="features">New Features</h2>
+<h2 id="features">Highlights</h2>
 
-<p>For a list of new system features, see the <a
+<p>For a list of new user features and platform highlights, see the <a
 href="http://developer.android.com/sdk/android-1.6-highlights.html">Android 1.6 Platform
 Highlights</a> document.</p>
 
@@ -139,22 +139,45 @@
 </tr>
 </table>
 
-<p>Localized UI strings match the locales that are displayable in 
-the emulator, accessible through the device Settings application.</p>
+<p>Localized UI strings match the locales that are accessible 
+through Settings.</p>
 
 <h2 id="api-changes">API Changes</h2>
 
-<h3 style="padding-top:0">Overview</h3>
+<h4 id="UIFramework">UI framework</h4>
+    <ul>
+      <li>New classes in {@link android.view.animation}
+      to control the behavior of animations:
+        <ul>
+          <li><code>AnticipateInterpolator</code></li>
+          <li><code>AnticipateOvershootInterpolator</code></li>
+          <li><code>BounceInterpolator</code></li>
+          <li><code>OvershootInterpolator</code></li>
+        </ul>
+      </li>
+      <li>New XML attribute <code>android:onClick</code> to specify a View's 
+<a href="/reference/android/view/View.OnClickListener.html">View.OnClickListener</a> 
+from a layout file.
+      </li>
+      <li>New support for dealing with varying screen densities. Density
+information is associated with Bitmap and Canvas for performing the
+correct scaling. The framework will automatically scale bitmaps and
+nine-patches based on the density the resource was found under and the
+density of the screen, etc.
+      </li>
+    </ul>
 
-<ul>
-
-<li>Search framework</li>
+<h4>Search framework</h4>
   <ul>
-    <li>Applications can now expose relevant content to users as search suggestions in the Quick Search Box, a new device-wide search capability that is accessible from the home screen. To support this, the search framework adds new attributes to the searchable metadata file. For complete information, see the {@link android.app.SearchManager SearchManager} documentation.</li>
+    <li>Applications can now expose relevant content to users as search
+suggestions in the Quick Search Box, a new device-wide search capability that is
+accessible from the home screen. To support this, the search framework adds new
+attributes to the searchable metadata file. For complete information, see the
+{@link android.app.SearchManager SearchManager} documentation.
+    </li>
   </ul>
-</li>
 
-<li>Accessibility framework</li>
+<h4>Accessibility framework</h4>
   <ul>
     <li>New {@link android.view.accessibility android.accessibility} package
 that includes classes for capturing accessibility events and forwarding them to
@@ -163,73 +186,139 @@
 that lets your application track user events and provide visual, audible, or
 haptic feedback to the user. </li>
   </ul>
-</li>
 
-<li>Gestures</li>
+<h4>Gesture Input</h4>
   <ul>
     <li>New {@link android.gesture gesture} API for creating, recognizing,
 loading, and saving gestures.</li>
   </ul>
-</li>
 
-<li>Text-to-speech</li>
+<h4>Text-to-speech</h4>
   <ul>
-    <li>New package {@link android.speech.tts android.speech.tts} provides
+    <li>New {@link android.speech.tts android.speech.tts} package provides
 classes for synthesizing speech from text, for immediate playback or to create a
 sound file.</li>
   </ul>
-</li>
 
-<li>Permissions</li>
-  <ul>
-
-    <li>New permissions for 
-{@link android.Manifest.permission#CHANGE_WIFI_MULTICAST_STATE CHANGE_WIFI_MULTICAST_STATE}, 
-{@link android.Manifest.permission#INSTALL_LOCATION_PROVIDER INSTALL_LOCATION_PROVIDER}, 
-{@link android.Manifest.permission#READ_HISTORY_BOOKMARKS READ_HISTORY_BOOKMARKS},
-{@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE WRITE_EXTERNAL_STORAGE}, and  
-{@link android.Manifest.permission#WRITE_HISTORY_BOOKMARKS WRITE_HISTORY_BOOKMARKS}.</li>
-  </ul>
-</li>
-
-<li>Graphics</li>
+<h4>Graphics</h4>
   <ul>
     <li>Classes in {@link android.graphics android.graphics} now support scaling
 for different screen densities.</li>
   </ul>
-</li>
 
-<li>Telephony</li>
+<h4>Telephony</h4>
   <ul>
     <li>New {@link android.telephony.SmsManager SmsManager} and other classes
 for sending and receiving SMS messages.</li>
   </ul>
-</li>
 
-<li>Utilities</li>
+<h4>Utilities</h4>
   <ul>
     <li>New {@link android.util.DisplayMetrics DisplayMetrics} fields for
 determining the density of the current device screen.</li>
   </ul>
-</li>
 
-<li>Application-defined support for various screen densities</li>
-   <p>Applications can now use a new element in their manifest files, <a
-href="{@docRoot}guide/topics/manifest/supports-screen-element.html">&lt;supports-
-screen&gt;</a> to indicate to the specific screen resolutions/densities that
-they are designed to support. When the application is installed on a device
-whose screen is not explicitly supported by the application, the system
-runs the application in Compatibility Mode, where possible. </p>
-</li>
-</ul>
+<h4 id="AndroidManifest">Android Manifest elements</h4>
+
+    <ul>
+      <li>New <a href="{@docRoot}guide/topics/manifest/supports-screens-element.html">{@code 
+      &lt;supports-screens>}</a> element lets you specify the device screen sizes that your 
+      application is designed and tested to support, where "size" is a combination
+      of resolution and density. If your application is run on a device whose screen 
+      size is not specified in the <code>&lt;supports-screen&gt;</code> element, the system 
+      displays the application in <em>compatibility mode</em>, which performs best-effort scaling
+      of the application UI to match the resolution and density of the screen. 
+
+    <p>The attributes available for defining an application's screen support are:
+
+        <ul>
+
+          <li><code>smallScreen</code>: Boolean value that indicates whether the
+            application is designed to run on devices with small screens. 
+            Examples: QVGA low density; VGA high density.
+          </li>
+          <li><code>normalScreens</code>: Boolean value that indicates whether 
+            the application is designed to run on devices with normal screens. 
+            Examples: WQVGA low density; HVGA medium density; WVGA high density.
+          </li>
+          <li><code>largeScreens</code>: Boolean value that indicates whether 
+            the application is designed to run on devices with significantly 
+            larger screens, such that special care may be required on
+            the application's part to make proper use of the screen area. 
+            Examples: VGA medium density; WVGA medium density.
+          </li>
+          <li><code>anyDensity</code>: Boolean value that indicates whether 
+            the application can accommodate any screen density.
+          </li>
+          <li><code>resizable</code>: Boolean value that indicates whether
+            the application can expand its layout to fit slightly larger screens.
+          </li>
+        </ul>
+    </p>
+    </li>
+
+      <li>New <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html">{@code &lt;uses-feature>}</a>
+        element lets an application specify hardware (or other)
+        features that it requires to function normally. When an application
+        specifies such features, the system allows the application to be installed only
+        on devices that offer the required features. The element supports these
+        attributes:
+        <ul>
+          <li><code>name</code>: The name of the feature required by the application. Currently accepts 
+          "android.hardware.camera" and "android.hardware.camera.autofocus" values, which specify that a 
+          camera and camera autofocus are required, respectively.</li>
+          <li><code>glEsVersion</code>: Indicates the minimum version of OpenGL ES required.</li>
+        </ul>
+      </li>
+      <li>New attributes for the 
+      <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html">{@code &lt;uses-sdk>}</a> element:
+        <ul>
+          <li><code>maxSdkVersion</code>: This indicates the maximum API Level on which an application is 
+          designed to run. If an application declares this attribute, the Android system prevents the user 
+          from installing the application if the system's API Level is higher than the value specified in 
+          this attribute. </li>
+          <li><code>targetSdkVersion</code>: This indicates the API Level that the application is targeting. 
+          It is able to run on older versions (down to minSdkVersion), but was explicitly tested to 
+          work with the version specified here. Specifying this version allows the platform to 
+          disable compatibility code that is not required or enable newer features that are not 
+          available to older applications. </li>
+        </ul>
+      </li>
+
+      </li>
+    </ul>
+
+<h4>New Permissions</h4>
+
+    <ul>
+      <li>{@link android.Manifest.permission#CHANGE_WIFI_MULTICAST_STATE
+          CHANGE_WIFI_MULTICAST_STATE}: Allows applications to enter Wi-Fi 
+          Multicast mode.
+      </li>
+      <li>{@link android.Manifest.permission#GLOBAL_SEARCH}: Allows the 
+          global search system to access the data of a specified content provider.
+      </li> 
+      <li>{@link android.Manifest.permission#INSTALL_LOCATION_PROVIDER INSTALL_LOCATION_PROVIDER}: 
+          Allows an application to install a location provider into the Location Manager.
+      </li>
+      <li>{@link android.Manifest.permission#READ_HISTORY_BOOKMARKS READ_HISTORY_BOOKMARKS}: 
+          Allows an application to read (but not write) the user's browsing history 
+          and bookmarks.
+      </li>
+      <li>{@link android.Manifest.permission#WRITE_HISTORY_BOOKMARKS WRITE_HISTORY_BOOKMARKS}: 
+          Allows an application to write (but not read) the user's browsing history 
+          and bookmarks.
+      </li>
+      <li>{@link android.Manifest.permission#WRITE_EXTERNAL_STORAGE WRITE_EXTERNAL_STORAGE}: 
+          Allows an application to write to external storage. Applications using API Level 3
+          and lower will be implicitly granted this permission (and this will be visible to 
+          the user); Applications using API Level 4 or higher must explicitly request this 
+          permission.
+      </li>
+    </ul>
+
 
 <h3 id="api-diff">API Change Details</h3>
 
-<p>For a detailed view of API changes in this platform (API Level 4), see the <a
+<p>For a detailed view of API changes in Android 1.6 (API Level 4), see the <a
 href="{@docRoot}sdk/api_diff/4/changes.html">API Differences Report</a>.</p>
-
-
-
-
-
-
diff --git a/docs/html/sdk/images/battery.png b/docs/html/sdk/images/battery.png
new file mode 100644
index 0000000..10fd16b
--- /dev/null
+++ b/docs/html/sdk/images/battery.png
Binary files differ
diff --git a/docs/html/sdk/images/camera.png b/docs/html/sdk/images/camera.png
new file mode 100644
index 0000000..6078388
--- /dev/null
+++ b/docs/html/sdk/images/camera.png
Binary files differ
diff --git a/docs/html/sdk/images/donut_small_bg.png b/docs/html/sdk/images/donut_small_bg.png
new file mode 100644
index 0000000..f514b50
--- /dev/null
+++ b/docs/html/sdk/images/donut_small_bg.png
Binary files differ
diff --git a/docs/html/sdk/images/market.png b/docs/html/sdk/images/market.png
new file mode 100644
index 0000000..8d11134
--- /dev/null
+++ b/docs/html/sdk/images/market.png
Binary files differ
diff --git a/docs/html/sdk/images/search.png b/docs/html/sdk/images/search.png
new file mode 100644
index 0000000..10ab910
--- /dev/null
+++ b/docs/html/sdk/images/search.png
Binary files differ
diff --git a/docs/html/videos/index.jd b/docs/html/videos/index.jd
index c9c88cf..ddb9f86 100644
--- a/docs/html/videos/index.jd
+++ b/docs/html/videos/index.jd
@@ -37,10 +37,12 @@
  * Each playlist ID is paired with a custom video description.
  */
 var featured = {
+// Android 1.6 Release
+  'MBRFkLKRwFw' : "The Android 1.6 release includes new features and improvements to the Android platform. Here's an introduction to what's new in Android 1.6.",
 // How to Make your Android UI Fast..
   'N6YdwzAvwOA' : "Make your user interface fast, with more efficient AdapterViews, better bitmap scaling, faster redrawing, ViewStub layouts, fewer Views, and more.", 
 // Coding for Life: Battery Life
-  'OUemfrKe65c' : "Learn what kinds of operations consume the most battery and how you can reduce your usage, with tips for parsing and zipping data, using wakelocks, and running a Service.",
+//  'OUemfrKe65c' : "Learn what kinds of operations consume the most battery and how you can reduce your usage, with tips for parsing and zipping data, using wakelocks, and running a Service.",
 // How Do I Code Thee?
   'GARMe7Km_gk' : "If you'd like to augment your Android applications with pieces written in JavaScript or native code, watch this video."
 };
diff --git a/graphics/java/android/graphics/PixelFormat.java b/graphics/java/android/graphics/PixelFormat.java
index 159accc..221c2f8 100644
--- a/graphics/java/android/graphics/PixelFormat.java
+++ b/graphics/java/android/graphics/PixelFormat.java
@@ -52,6 +52,12 @@
      * by the hardware.
      */
     public static final int YCbCr_422_SP= 0x10;
+
+    /** YCbCr format used for images, which uses the NV21 encoding format.   
+     *  This is the default format for camera preview images, when not
+     *  otherwise set with 
+     *  {@link android.hardware.Camera.Parameters#setPreviewFormat(int)}.
+     */
     public static final int YCbCr_420_SP= 0x11;
 
     /**
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index 1755d4f..30cef67 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -56,7 +56,8 @@
  */
 public class BitmapDrawable extends Drawable {
 
-    private static final int DEFAULT_PAINT_FLAGS = Paint.FILTER_BITMAP_FLAG;
+    private static final int DEFAULT_PAINT_FLAGS =
+            Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG;
     private BitmapState mBitmapState;
     private Bitmap mBitmap;
     private final Rect mDstRect = new Rect();   // Gravity.apply() sets this
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index 6b50406..af1a289 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -19,12 +19,23 @@
 import android.graphics.*;
 
 public class DrawableContainer extends Drawable implements Drawable.Callback {
-    
+
+    /**
+     * To be proper, we should have a getter for dither (and alpha, etc.)
+     * so that proxy classes like this can save/restore their delegates'
+     * values, but we don't have getters. Since we do have setters
+     * (e.g. setDither), which this proxy forwards on, we have to have some
+     * default/initial setting.
+     *
+     * The initial setting for dither is now true, since it almost always seems
+     * to improve the quality at negligible cost.
+     */
+    private static final boolean DEFAULT_DITHER = true;
     private DrawableContainerState mDrawableContainerState;
     private Drawable mCurrDrawable;
     private int mAlpha = 0xFF;
     private ColorFilter mColorFilter;
-    private boolean mDither;
+    private boolean mDither = DEFAULT_DITHER;
 
     private int mCurIndex = -1;
     private boolean mMutated;
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index b175bb6..997efb8 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -21,6 +21,7 @@
 import android.content.res.TypedArray;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
+import android.util.Log;
 import android.util.TypedValue;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -36,6 +37,8 @@
  *
  */
 public class NinePatchDrawable extends Drawable {
+    // dithering helps a lot, and is pretty cheap, so default is true
+    private static final boolean DEFAULT_DITHER = true;
     private NinePatchState mNinePatchState;
     private NinePatch mNinePatch;
     private Rect mPadding;
@@ -101,7 +104,11 @@
         mNinePatch = state.mNinePatch;
         mPadding = state.mPadding;
         mTargetDensity = state.mTargetDensity;
-        if (state.mDither) setDither(state.mDither);
+        if (DEFAULT_DITHER != state.mDither) {
+            // avoid calling the setter unless we need to, since it does a
+            // lazy allocation of a paint
+            setDither(state.mDither);
+        }
         if (mNinePatch != null) {
             computeBitmapSize();
         }
@@ -164,6 +171,11 @@
 
     @Override
     public void draw(Canvas canvas) {
+        if (false) {
+            float[] pts = new float[2];
+            canvas.getMatrix().mapPoints(pts);
+            Log.v("9patch", "Drawing 9-patch @ " + pts[0] + "," + pts[1] + ": " + getBounds());
+        }
         mNinePatch.draw(canvas, getBounds(), mPaint);
     }
 
@@ -194,6 +206,14 @@
     }
 
     @Override
+    public void setFilterBitmap(boolean filter) {
+        // at the moment, we see no quality improvement, but a big slowdown
+        // with filtering, so ignore this call for now
+        //
+        //getPaint().setFilterBitmap(filter);
+    }
+
+    @Override
     public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)
             throws XmlPullParserException, IOException {
         super.inflate(r, parser, attrs);
@@ -207,7 +227,8 @@
         }
 
         final boolean dither = a.getBoolean(
-                com.android.internal.R.styleable.NinePatchDrawable_dither, false);
+                com.android.internal.R.styleable.NinePatchDrawable_dither,
+                DEFAULT_DITHER);
         final BitmapFactory.Options options = new BitmapFactory.Options();
         if (dither) {
             options.inDither = false;
@@ -243,10 +264,10 @@
         a.recycle();
     }
 
-
     public Paint getPaint() {
         if (mPaint == null) {
             mPaint = new Paint();
+            mPaint.setDither(DEFAULT_DITHER);
         }
         return mPaint;
     }
@@ -317,7 +338,7 @@
         int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
 
         NinePatchState(NinePatch ninePatch, Rect padding) {
-            this(ninePatch, padding, false);
+            this(ninePatch, padding, DEFAULT_DITHER);
         }
 
         NinePatchState(NinePatch ninePatch, Rect rect, boolean dither) {
diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java
index a8274b1..59cb226 100644
--- a/graphics/java/android/graphics/drawable/StateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/StateListDrawable.java
@@ -50,6 +50,17 @@
  * @attr ref android.R.styleable#DrawableStates_state_pressed
  */
 public class StateListDrawable extends DrawableContainer {
+    /**
+     * To be proper, we should have a getter for dither (and alpha, etc.)
+     * so that proxy classes like this can save/restore their delegates'
+     * values, but we don't have getters. Since we do have setters
+     * (e.g. setDither), which this proxy forwards on, we have to have some
+     * default/initial setting.
+     *
+     * The initial setting for dither is now true, since it almost always seems
+     * to improve the quality at negligible cost.
+     */
+    private static final boolean DEFAULT_DITHER = true;
     private final StateListState mStateListState;
     private boolean mMutated;
 
@@ -105,7 +116,8 @@
         mStateListState.setConstantSize(a.getBoolean(
                 com.android.internal.R.styleable.StateListDrawable_constantSize, false));
 
-        setDither(a.getBoolean(com.android.internal.R.styleable.StateListDrawable_dither, false));
+        setDither(a.getBoolean(com.android.internal.R.styleable.StateListDrawable_dither,
+                               DEFAULT_DITHER));
 
         a.recycle();
 
diff --git a/include/media/stagefright/AMRExtractor.h b/include/media/stagefright/AMRExtractor.h
new file mode 100644
index 0000000..c8710d3
--- /dev/null
+++ b/include/media/stagefright/AMRExtractor.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef AMR_EXTRACTOR_H_
+
+#define AMR_EXTRACTOR_H_
+
+#include <media/stagefright/MediaExtractor.h>
+
+namespace android {
+
+class String8;
+
+class AMRExtractor : public MediaExtractor {
+public:
+    AMRExtractor(const sp<DataSource> &source);
+
+    virtual size_t countTracks();
+    virtual sp<MediaSource> getTrack(size_t index);
+    virtual sp<MetaData> getTrackMetaData(size_t index);
+
+    static sp<MetaData> makeAMRFormat(bool isWide);
+
+protected:
+    virtual ~AMRExtractor();
+
+private:
+    sp<DataSource> mDataSource;
+    status_t mInitCheck;
+    bool mIsWide;
+
+    AMRExtractor(const AMRExtractor &);
+    AMRExtractor &operator=(const AMRExtractor &);
+};
+
+bool SniffAMR(
+        const sp<DataSource> &source, String8 *mimeType, float *confidence);
+
+}  // namespace android
+
+#endif  // AMR_EXTRACTOR_H_
diff --git a/cmds/stagefright/JPEGSource.h b/include/media/stagefright/JPEGSource.h
similarity index 97%
rename from cmds/stagefright/JPEGSource.h
rename to include/media/stagefright/JPEGSource.h
index 051c034..9d0a700 100644
--- a/cmds/stagefright/JPEGSource.h
+++ b/include/media/stagefright/JPEGSource.h
@@ -26,7 +26,6 @@
 class MediaBufferGroup;
 
 struct JPEGSource : public MediaSource {
-    // Assumes ownership of "source".
     JPEGSource(const sp<DataSource> &source);
 
     virtual status_t start(MetaData *params = NULL);
diff --git a/include/media/stagefright/MP3Extractor.h b/include/media/stagefright/MP3Extractor.h
index 4e1f3c3..11ba01d 100644
--- a/include/media/stagefright/MP3Extractor.h
+++ b/include/media/stagefright/MP3Extractor.h
@@ -30,9 +30,9 @@
     // Extractor assumes ownership of "source".
     MP3Extractor(const sp<DataSource> &source);
 
-    size_t countTracks();
-    sp<MediaSource> getTrack(size_t index);
-    sp<MetaData> getTrackMetaData(size_t index);
+    virtual size_t countTracks();
+    virtual sp<MediaSource> getTrack(size_t index);
+    virtual sp<MetaData> getTrackMetaData(size_t index);
 
 protected:
     virtual ~MP3Extractor();
diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
index 5147de9..6b0399f 100644
--- a/include/media/stagefright/MPEG4Writer.h
+++ b/include/media/stagefright/MPEG4Writer.h
@@ -34,9 +34,9 @@
 public:
     MPEG4Writer(const char *filename);
 
-    // Caller retains ownership of both meta and source.
-    void addSource(const sp<MetaData> &meta, const sp<MediaSource> &source);
-    void start();
+    void addSource(const sp<MediaSource> &source);
+    status_t start();
+    bool reachedEOS();
     void stop();
 
     void beginBox(const char *fourcc);
diff --git a/include/media/stagefright/MediaDefs.h b/include/media/stagefright/MediaDefs.h
new file mode 100644
index 0000000..feb66e3
--- /dev/null
+++ b/include/media/stagefright/MediaDefs.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef MEDIA_DEFS_H_
+
+#define MEDIA_DEFS_H_
+
+namespace android {
+
+extern const char *MEDIA_MIMETYPE_IMAGE_JPEG;
+
+extern const char *MEDIA_MIMETYPE_VIDEO_AVC;
+extern const char *MEDIA_MIMETYPE_VIDEO_MPEG4;
+extern const char *MEDIA_MIMETYPE_VIDEO_H263;
+extern const char *MEDIA_MIMETYPE_VIDEO_RAW;
+
+extern const char *MEDIA_MIMETYPE_AUDIO_AMR_NB;
+extern const char *MEDIA_MIMETYPE_AUDIO_AMR_WB;
+extern const char *MEDIA_MIMETYPE_AUDIO_MPEG;
+extern const char *MEDIA_MIMETYPE_AUDIO_AAC;
+extern const char *MEDIA_MIMETYPE_AUDIO_RAW;
+
+extern const char *MEDIA_MIMETYPE_CONTAINER_MPEG4;
+
+}  // namespace android
+
+#endif  // MEDIA_DEFS_H_
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index ac45481..ff7e34a 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -33,7 +33,12 @@
     static sp<OMXCodec> Create(
             const sp<IOMX> &omx,
             const sp<MetaData> &meta, bool createEncoder,
-            const sp<MediaSource> &source);
+            const sp<MediaSource> &source,
+            const char *matchComponentName = NULL);
+
+    static void setComponentRole(
+            const sp<IOMX> &omx, IOMX::node_id node, bool isEncoder,
+            const char *mime);
 
     virtual status_t start(MetaData *params = NULL);
     virtual status_t stop();
@@ -138,6 +143,7 @@
     void setComponentRole();
 
     void setAMRFormat();
+    void setAMRWBFormat();
     void setAACFormat(int32_t numChannels, int32_t sampleRate);
 
     status_t setVideoPortFormatType(
@@ -205,6 +211,32 @@
     OMXCodec &operator=(const OMXCodec &);
 };
 
+struct CodecProfileLevel {
+    OMX_U32 mProfile;
+    OMX_U32 mLevel;
+};
+
+struct CodecCapabilities {
+    String8 mComponentName;
+    Vector<CodecProfileLevel> mProfileLevels;
+};
+
+// Return a vector of componentNames with supported profile/level pairs
+// supporting the given mime type, if queryDecoders==true, returns components
+// that decode content of the given type, otherwise returns components
+// that encode content of the given type.
+// profile and level indications only make sense for h.263, mpeg4 and avc
+// video.
+// The profile/level values correspond to
+// OMX_VIDEO_H263PROFILETYPE, OMX_VIDEO_MPEG4PROFILETYPE,
+// OMX_VIDEO_AVCPROFILETYPE, OMX_VIDEO_H263LEVELTYPE, OMX_VIDEO_MPEG4LEVELTYPE
+// and OMX_VIDEO_AVCLEVELTYPE respectively.
+
+status_t QueryCodecs(
+        const sp<IOMX> &omx,
+        const char *mimeType, bool queryDecoders,
+        Vector<CodecCapabilities> *results);
+
 }  // namespace android
 
 #endif  // OMX_CODEC_H_
diff --git a/include/private/ui/SharedBufferStack.h b/include/private/ui/SharedBufferStack.h
index 2bd5344..6181f55 100644
--- a/include/private/ui/SharedBufferStack.h
+++ b/include/private/ui/SharedBufferStack.h
@@ -85,6 +85,7 @@
 
 public:
     SharedBufferStack();
+    void init(int32_t identity);
     status_t setDirtyRegion(int buffer, const Region& reg);
     Region getDirtyRegion(int buffer) const;
 
@@ -93,12 +94,12 @@
     volatile int32_t available; // number of dequeue-able buffers
     volatile int32_t queued;    // number of buffers waiting for post
     volatile int32_t inUse;     // buffer currently in use by SF
+    volatile status_t status;   // surface's status code
 
     // not part of the conditions
     volatile int32_t reallocMask;
 
     int32_t     identity;       // surface's identity (const)
-    status_t    status;         // surface's status code
     int32_t     reserved32[13];
     FlatRegion  dirtyRegion[NUM_BUFFER_MAX];    // 12*4=48 bytes
 };
@@ -114,7 +115,6 @@
 
     status_t validate(size_t token) const;
     uint32_t getIdentity(size_t token) const;
-    status_t setIdentity(size_t token, uint32_t identity);
 
 private:
     friend class SharedBufferBase;
@@ -168,10 +168,11 @@
 template <typename T>
 status_t SharedBufferBase::waitForCondition(T condition) 
 {
+    const SharedBufferStack& stack( *mSharedStack );
     SharedClient& client( *mSharedClient );
     const nsecs_t TIMEOUT = s2ns(1); 
     Mutex::Autolock _l(client.lock);
-    while (!condition()) {
+    while ((condition()==false) && (stack.status == NO_ERROR)) {
         status_t err = client.cv.waitRelative(client.lock, TIMEOUT);
         
         // handle errors and timeouts
@@ -195,7 +196,7 @@
             }
         }
     }
-    return NO_ERROR;
+    return stack.status;
 }
 
 
@@ -261,13 +262,15 @@
 class SharedBufferServer : public SharedBufferBase
 {
 public:
-    SharedBufferServer(SharedClient* sharedClient, int surface, int num);
+    SharedBufferServer(SharedClient* sharedClient, int surface, int num,
+            int32_t identity);
 
     ssize_t retireAndLock();
     status_t unlock(int buffer);
+    void setStatus(status_t status);
     status_t reallocate();
     status_t assertReallocate(int buffer);
-
+    
     Region getDirtyRegion(int buffer) const;
 
 private:
@@ -283,6 +286,12 @@
         inline ssize_t operator()();
     };
 
+    struct StatusUpdate : public UpdateBase {
+        const status_t status;
+        inline StatusUpdate(SharedBufferBase* sbb, status_t status);
+        inline ssize_t operator()();
+    };
+
     struct ReallocateCondition : public ConditionBase {
         int buf;
         inline ReallocateCondition(SharedBufferBase* sbb, int buf);
diff --git a/include/utils/threads.h b/include/utils/threads.h
index e9b0788..f5304f7 100644
--- a/include/utils/threads.h
+++ b/include/utils/threads.h
@@ -90,6 +90,11 @@
     ANDROID_TGROUP_MAX              = ANDROID_TGROUP_FG_BOOST,
 };
 
+typedef enum {
+    SP_BACKGROUND = 0,
+    SP_FOREGROUND = 1,
+} SchedPolicy;
+
 // Create and run a new thread.
 extern int androidCreateThread(android_thread_func_t, void *);
 
@@ -408,6 +413,9 @@
     volatile bool           mExitPending;
     volatile bool           mRunning;
             sp<Thread>      mHoldSelf;
+#if HAVE_ANDROID_OS
+            int             mTid;
+#endif
 };
 
 
diff --git a/keystore/java/android/security/CertTool.java b/keystore/java/android/security/CertTool.java
index 6caeb3e..88d6e3d 100644
--- a/keystore/java/android/security/CertTool.java
+++ b/keystore/java/android/security/CertTool.java
@@ -16,6 +16,12 @@
 
 package android.security;
 
+import android.content.Context;
+import android.content.Intent;
+import android.security.Keystore;
+import android.text.TextUtils;
+import android.util.Log;
+
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.security.cert.Certificate;
@@ -23,16 +29,11 @@
 import java.security.KeyStoreException;
 import java.security.NoSuchAlgorithmException;
 import java.security.UnrecoverableKeyException;
-
-import android.content.Context;
-import android.content.Intent;
-import android.security.Keystore;
-import android.text.TextUtils;
-import android.util.Log;
+import java.util.ArrayList;
 
 /**
  * The CertTool class provides the functions to list the certs/keys,
- * generate the certificate request(csr) and store the certificate into
+ * generate the certificate request(csr) and store certificates into
  * keystore.
  *
  * {@hide}
@@ -51,19 +52,129 @@
     /** Keystore namespace for user private keys. */
     public static final String USER_KEY = "USRKEY";
 
+    /** Action string for adding certificates to keystore. */
     public static final String ACTION_ADD_CREDENTIAL =
             "android.security.ADD_CREDENTIAL";
-    public static final String KEY_TYPE_NAME = "typeName";
-    public static final String KEY_ITEM = "item";
-    public static final String KEY_NAMESPACE = "namespace";
-    public static final String KEY_DESCRIPTION = "description";
 
+    /** Action string for installing certificates to keystore from sdcard. */
+    public static final String ACTION_INSTALL_CERT_FROM_SDCARD =
+            "android.security.INSTALL_CERT_FROM_SDCARD";
+
+    /** Dialog title for adding a CA certificate. */
     public static final String TITLE_CA_CERT = "CA Certificate";
+
+    /** Dialog title for adding a user certificate. */
     public static final String TITLE_USER_CERT = "User Certificate";
-    public static final String TITLE_PKCS12_KEYSTORE = "PKCS12 Keystore";
+
+    /** Dialog title for adding a user private key. */
     public static final String TITLE_PRIVATE_KEY = "Private Key";
+
+    /** Dialog title for adding a PKCS12 keystore. */
+    public static final String TITLE_PKCS12_KEYSTORE = "PKCS12 Keystore";
+
     public static final int INCORRECT_PKCS12_PASSPHRASE = -100;
 
+    /**
+     * The builder class for building an add-credential-to-keystore intent.
+     */
+    public static class AddCredentialIntentBuilder {
+        private Intent mIntent;
+        private int mCount;
+
+        /**
+         * Creates a builder to build a add-credential-to-keystore intent.
+         *
+         * @param title title of the dialog for adding this credential
+         * @param descriptions description strings to show on the dialog
+         */
+        public AddCredentialIntentBuilder(String title,
+                String... descriptions) {
+            Intent intent = new Intent(ACTION_ADD_CREDENTIAL);
+            intent.putExtra(KEY_TITLE, title);
+
+            int i = 0;
+            for (String description : descriptions) {
+                intent.putExtra(KEY_DESCRIPTION + (i++), description);
+            }
+            mIntent = intent;
+        }
+
+        /**
+         * Adds credential data to the intent.
+         *
+         * @param namespace the namespace of the keystore to add the credential
+         *      data to
+         * @param data the credential data
+         * @return this builder
+         */
+        public AddCredentialIntentBuilder addCredential(String namespace,
+                byte[] data) {
+            mIntent.putExtra(KEY_NAMESPACE + mCount, namespace);
+            mIntent.putExtra(KEY_ITEM + mCount, data);
+            mCount++;
+            return this;
+        }
+
+        /** Returns the intent. */
+        public Intent build() {
+            return mIntent;
+        }
+    }
+
+    /**
+     * Request for adding credential data to keystore.
+     */
+    public static class AddCredentialRequest {
+        private Intent mIntent;
+
+        /**
+         * Creates an add-credential-data-to-keystore request.
+         *
+         * @param intent an add-credential-data-to-keystore intent
+         * @see AddCredentialIntentBuilder
+         */
+        public AddCredentialRequest(Intent intent) {
+            mIntent = intent;
+        }
+
+        /** Returns the dialog title. */
+        public String getTitle() {
+            return mIntent.getStringExtra(KEY_TITLE);
+        }
+
+        /**
+         * Returns the i'th credential data.
+         * @return the data or null if not exists
+         */
+        public byte[] getDataAt(int i) {
+            return mIntent.getByteArrayExtra(KEY_ITEM + i);
+        }
+
+        /**
+         * Returns the namespace of the i'th credential data.
+         * @return the namespace string or null if missing
+         */
+        public String getNamespaceAt(int i) {
+            return mIntent.getStringExtra(KEY_NAMESPACE + i);
+        }
+
+        /** Returns the descriptions of the credential data. */
+        public String[] getDescriptions() {
+            ArrayList<String> list = new ArrayList<String>();
+            for (int i = 0; ; i++) {
+                String s = mIntent.getStringExtra(KEY_DESCRIPTION + i);
+                if (s == null) break;
+                list.add(s);
+            }
+            return list.toArray(new String[list.size()]);
+        }
+    }
+
+    private static final String KEY_TITLE = "typeName";
+    private static final String KEY_ITEM = "item";
+    private static final String KEY_NAMESPACE = "namespace";
+    private static final String KEY_DESCRIPTION = "description";
+
     private static final String TAG = "CertTool";
     private static final String UNKNOWN = "Unknown";
     private static final String ISSUER_NAME = "Issuer Name:";
@@ -86,33 +197,55 @@
     private native String getPrivateKeyPEM(int handle);
     private native void freeX509Certificate(int handle);
 
-    private static CertTool singleton = null;
+    private static CertTool sSingleton = null;
 
     private CertTool() { }
 
     public static final CertTool getInstance() {
-        if (singleton == null) {
-            singleton = new CertTool();
+        if (sSingleton == null) {
+            sSingleton = new CertTool();
         }
-        return singleton;
+        return sSingleton;
     }
 
+    /**
+     * Gets the full key to retrieve the user private key from the keystore.
+     * @see #getAllUserCertificateKeys()
+     */
     public String getUserPrivateKey(String key) {
         return USER_KEY + KEYNAME_DELIMITER + key;
     }
 
+    /**
+     * Gets the full key to retrieve the user certificate from the keystore.
+     * @see #getAllUserCertificateKeys()
+     */
     public String getUserCertificate(String key) {
         return USER_CERTIFICATE + KEYNAME_DELIMITER + key;
     }
 
+    /**
+     * Gets the full key to retrieve the CA certificate from the keystore.
+     * @see #getAllCaCertificateKeys()
+     */
     public String getCaCertificate(String key) {
         return CA_CERTIFICATE + KEYNAME_DELIMITER + key;
     }
 
+    /**
+     * Gets all the keys to the user certificates/private keys stored in the
+     * keystore.
+     * @see #getUserCertificate(String)
+     * @see #getUserPrivateKey(String)
+     */
     public String[] getAllUserCertificateKeys() {
         return sKeystore.listKeys(USER_KEY);
     }
 
+    /**
+     * Gets all the keys to the CA certificates stored in the keystore.
+     * @see #getCaCertificate(String)
+     */
     public String[] getAllCaCertificateKeys() {
         return sKeystore.listKeys(CA_CERTIFICATE);
     }
@@ -126,29 +259,21 @@
         return 1024;
     }
 
+    /**
+     * Generates a key pair.
+     *
+     * @param keyStrengthIndex index to the array of supported key strengths;
+     *      see {@link #getSupportedKeyStrenghs()}
+     * @param challenge the challenge string for generating the pair
+     * @param dirName (not used)
+     * @return a certificate request from the resulted public key
+     */
     public String generateKeyPair(int keyStrengthIndex, String challenge,
             String dirName) {
         return generateCertificateRequest(getKeyLength(keyStrengthIndex),
                 challenge);
     }
 
-    private Intent prepareIntent(String title, byte[] data, String namespace,
-            String issuer, String distinctName) {
-        Intent intent = new Intent(ACTION_ADD_CREDENTIAL);
-        intent.putExtra(KEY_TYPE_NAME, title);
-        intent.putExtra(KEY_ITEM + "0", data);
-        intent.putExtra(KEY_NAMESPACE + "0", namespace);
-        intent.putExtra(KEY_DESCRIPTION + "0", ISSUER_NAME + issuer);
-        intent.putExtra(KEY_DESCRIPTION + "1", DISTINCT_NAME + distinctName);
-        return intent;
-    }
-
-    private void addExtraIntentInfo(Intent intent, String namespace,
-            String data) {
-        intent.putExtra(KEY_ITEM + "1", data.getBytes());
-        intent.putExtra(KEY_NAMESPACE + "1", namespace);
-    }
-
     private int extractAndStoreKeysFromPkcs12(int handle, String keyname) {
         int ret, i = 0;
         String pemData;
@@ -171,6 +296,7 @@
         return 0;
     }
 
+    /** Adds a PKCS12 keystore to the keystore. */
     public int addPkcs12Keystore(byte[] p12Data, String password,
             String keyname) {
         int handle, ret;
@@ -184,27 +310,35 @@
         return ret;
     }
 
+    /**
+     * Adds a certificate to the keystore.
+     *
+     * @param data the certificate data
+     * @param context the context to send an add-credential-to-keystore intent
+     */
     public synchronized void addCertificate(byte[] data, Context context) {
         int handle;
         Intent intent = null;
 
         Log.i("CertTool", "addCertificate()");
         if (isPkcs12Keystore(data)) {
-            intent = prepareIntent(TITLE_PKCS12_KEYSTORE, data, USER_KEY,
-                    UNKNOWN, UNKNOWN);
+            intent = prepareIntent(TITLE_PKCS12_KEYSTORE, UNKNOWN, UNKNOWN)
+                    .addCredential(USER_KEY, data).build();
         } else if ((handle = generateX509Certificate(data)) != 0) {
             String issuer = getIssuerDN(handle);
             String distinctName = getCertificateDN(handle);
             String privateKeyPEM = getPrivateKeyPEM(handle);
             if (isCaCertificate(handle)) {
-                intent = prepareIntent(TITLE_CA_CERT, data, CA_CERTIFICATE,
-                        issuer, distinctName);
+                intent = prepareIntent(TITLE_CA_CERT, issuer, distinctName)
+                        .addCredential(CA_CERTIFICATE, data).build();
             } else {
-                intent = prepareIntent(TITLE_USER_CERT, data, USER_CERTIFICATE,
-                        issuer, distinctName);
+                AddCredentialIntentBuilder builder =
+                        prepareIntent(TITLE_USER_CERT, issuer, distinctName)
+                        .addCredential(USER_CERTIFICATE, data);
                 if (!TextUtils.isEmpty(privateKeyPEM)) {
-                    addExtraIntentInfo(intent, USER_KEY, privateKeyPEM);
+                    builder.addCredential(USER_KEY, privateKeyPEM.getBytes());
                 }
+                intent = builder.build();
             }
             freeX509Certificate(handle);
         }
@@ -214,4 +348,10 @@
             Log.w("CertTool", "incorrect data for addCertificate()");
         }
     }
+
+    private AddCredentialIntentBuilder prepareIntent(
+            String title, String issuer, String distinctName) {
+        return new AddCredentialIntentBuilder(title, ISSUER_NAME + issuer,
+                DISTINCT_NAME + distinctName);
+    }
 }
diff --git a/keystore/java/android/security/Keystore.java b/keystore/java/android/security/Keystore.java
index 9713d29..b47ae12 100644
--- a/keystore/java/android/security/Keystore.java
+++ b/keystore/java/android/security/Keystore.java
@@ -22,8 +22,9 @@
  */
 
 public abstract class Keystore {
-    private static final String TAG = "Keystore";
-    private static final String[] NOTFOUND = new String[0];
+    /** Action to unlock (or initialize) the keystore. */
+    public static final String ACTION_UNLOCK_CREDENTIAL_STORAGE =
+            "android.security.UNLOCK_CREDENTIAL_STORAGE";
 
     // Keystore States
     public static final int BOOTUP = 0;
@@ -31,8 +32,9 @@
     public static final int LOCKED = 2;
     public static final int UNLOCKED = 3;
 
-    /**
-     */
+    private static final String TAG = "Keystore";
+    private static final String[] NOTFOUND = new String[0];
+
     public static Keystore getInstance() {
         return new FileKeystore();
     }
@@ -58,7 +60,7 @@
 
         @Override
         public int lock() {
-            Reply result = mServiceCommand.execute(ServiceCommand.LOCK, null);
+            Reply result = mServiceCommand.execute(ServiceCommand.LOCK);
             return (result != null) ? result.returnCode : -1;
         }
 
@@ -71,15 +73,14 @@
 
         @Override
         public int getState() {
-            Reply result = mServiceCommand.execute(ServiceCommand.GET_STATE,
-                    null);
+            Reply result = mServiceCommand.execute(ServiceCommand.GET_STATE);
             return (result != null) ? result.returnCode : -1;
         }
 
         @Override
         public int changePassword(String oldPassword, String newPassword) {
             Reply result = mServiceCommand.execute(ServiceCommand.PASSWD,
-                    oldPassword + "\0" + newPassword + "\0");
+                    oldPassword, newPassword);
             return (result != null) ? result.returnCode : -1;
         }
 
@@ -104,14 +105,14 @@
         @Override
         public int put(String namespace, String keyname, String value) {
             Reply result = mServiceCommand.execute(ServiceCommand.PUT_KEY,
-                    namespace + "\0" + keyname + "\0" + value);
+                    namespace, keyname, value);
             return (result != null) ? result.returnCode : -1;
         }
 
         @Override
         public String get(String namespace, String keyname) {
             Reply result = mServiceCommand.execute(ServiceCommand.GET_KEY,
-                    namespace + "\0" + keyname + "\0");
+                    namespace, keyname);
             return (result != null) ? ((result.returnCode != 0) ? null :
                     new String(result.data, 0, result.len)) : null;
         }
@@ -119,13 +120,13 @@
         @Override
         public int remove(String namespace, String keyname) {
             Reply result = mServiceCommand.execute(ServiceCommand.REMOVE_KEY,
-                    namespace + "\0" + keyname + "\0");
+                    namespace, keyname);
             return (result != null) ? result.returnCode : -1;
         }
 
         @Override
         public int reset() {
-            Reply result = mServiceCommand.execute(ServiceCommand.RESET, null);
+            Reply result = mServiceCommand.execute(ServiceCommand.RESET);
             return (result != null) ? result.returnCode : -1;
         }
     }
diff --git a/keystore/java/android/security/ServiceCommand.java b/keystore/java/android/security/ServiceCommand.java
index cefae40..ee80014 100644
--- a/keystore/java/android/security/ServiceCommand.java
+++ b/keystore/java/android/security/ServiceCommand.java
@@ -141,10 +141,18 @@
         return reply;
     }
 
-    private boolean writeCommand(int cmd, String _data) {
+    private byte[] convert(String... data) {
+        StringBuilder sb = new StringBuilder();
+        if (data.length >=1) sb.append(data[0]).append("\0");
+        if (data.length >=2) sb.append(data[1]).append("\0");
+        if (data.length >=3) sb.append(data[2]);
+        return sb.toString().getBytes();
+    }
+
+    private boolean writeCommand(int cmd, String... data) {
         byte buf[] = new byte[8];
-        byte[] data = (_data == null) ? new byte[0] : _data.getBytes();
-        int len = data.length;
+        byte[] dataBytes = convert(data);
+        int len = dataBytes.length;
         // the length of data
         buf[0] = (byte) ((len >> 24) & 0xff);
         buf[1] = (byte) ((len >> 16) & 0xff);
@@ -157,7 +165,7 @@
         buf[7] = (byte) (cmd & 0xff);
         try {
             mOut.write(buf, 0, 8);
-            mOut.write(data, 0, len);
+            mOut.write(dataBytes, 0, len);
         } catch (IOException ex) {
             Log.e(mTag,"write error", ex);
             disconnect();
@@ -166,7 +174,7 @@
         return true;
     }
 
-    private Reply executeCommand(int cmd, String data) {
+    private Reply executeCommand(int cmd, String... data) {
         if (!writeCommand(cmd, data)) {
             /* If service died and restarted in the background
              * (unlikely but possible) we'll fail on the next
@@ -181,7 +189,7 @@
         return readReply();
     }
 
-    public synchronized Reply execute(int cmd, String data) {
+    public synchronized Reply execute(int cmd, String... data) {
       Reply result;
       if (!connect()) {
           Log.e(mTag, "connection failed");
diff --git a/keystore/jni/cert.c b/keystore/jni/cert.c
index 91114d6..90f872e 100644
--- a/keystore/jni/cert.c
+++ b/keystore/jni/cert.c
@@ -18,7 +18,6 @@
 #define LOG_TAG "CertTool"
 
 #include <stdio.h>
-#include <openssl/engine.h>
 #include <openssl/pem.h>
 #include <openssl/pkcs12.h>
 #include <openssl/rsa.h>
diff --git a/libs/rs/java/Fall/Android.mk b/libs/rs/java/Fall/Android.mk
deleted file mode 100644
index 6366f63..0000000
--- a/libs/rs/java/Fall/Android.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-#
-# Copyright (C) 2009 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-#LOCAL_STATIC_JAVA_LIBRARIES := android.renderscript
-
-LOCAL_PACKAGE_NAME := FallRS
-
-include $(BUILD_PACKAGE)
diff --git a/libs/rs/java/Fall/AndroidManifest.xml b/libs/rs/java/Fall/AndroidManifest.xml
deleted file mode 100644
index f646d0d..0000000
--- a/libs/rs/java/Fall/AndroidManifest.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.fall.rs">
-
-    <application android:label="FallRS">
-
-        <activity
-            android:screenOrientation="portrait"
-            android:name="Fall"
-            android:theme="@android:style/Theme.NoTitleBar">
-
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-
-        </activity>
-
-    </application>
-
-</manifest>
diff --git a/libs/rs/java/Fall/res/drawable-hdpi/leaves.png b/libs/rs/java/Fall/res/drawable-hdpi/leaves.png
deleted file mode 100644
index 9eddd66..0000000
--- a/libs/rs/java/Fall/res/drawable-hdpi/leaves.png
+++ /dev/null
Binary files differ
diff --git a/libs/rs/java/Fall/res/drawable-hdpi/riverbed.jpg b/libs/rs/java/Fall/res/drawable-hdpi/riverbed.jpg
deleted file mode 100644
index 1698f28b..0000000
--- a/libs/rs/java/Fall/res/drawable-hdpi/riverbed.jpg
+++ /dev/null
Binary files differ
diff --git a/libs/rs/java/Fall/res/drawable-hdpi/sky.jpg b/libs/rs/java/Fall/res/drawable-hdpi/sky.jpg
deleted file mode 100644
index 565a63b..0000000
--- a/libs/rs/java/Fall/res/drawable-hdpi/sky.jpg
+++ /dev/null
Binary files differ
diff --git a/libs/rs/java/Fall/res/raw/fall.c b/libs/rs/java/Fall/res/raw/fall.c
deleted file mode 100644
index e04e1ff..0000000
--- a/libs/rs/java/Fall/res/raw/fall.c
+++ /dev/null
@@ -1,478 +0,0 @@
-// Copyright (C) 2009 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma version(1)
-#pragma stateVertex(PVSky)
-#pragma stateFragment(PFBackground)
-#pragma stateFragmentStore(PFSBackground)
-
-#define RSID_STATE 0
-#define RSID_RIPPLE_MAP 1
-#define RSID_REFRACTION_MAP 2
-#define RSID_LEAVES 3
-#define RSID_DROP 4
-
-#define LEAF_STRUCT_FIELDS_COUNT 11
-#define LEAF_STRUCT_X 0
-#define LEAF_STRUCT_Y 1
-#define LEAF_STRUCT_SCALE 2
-#define LEAF_STRUCT_ANGLE 3
-#define LEAF_STRUCT_SPIN 4
-#define LEAF_STRUCT_U1 5
-#define LEAF_STRUCT_U2 6
-#define LEAF_STRUCT_ALTITUDE 7
-#define LEAF_STRUCT_RIPPLED 8
-#define LEAF_STRUCT_DELTAX 9
-#define LEAF_STRUCT_DELTAY 10
-
-#define LEAVES_TEXTURES_COUNT 4
-
-#define LEAF_SIZE 0.55f
-
-#define REFRACTION 1.333f
-#define DAMP 3
-
-#define DROP_RADIUS 2
-// The higher, the smaller the ripple
-#define RIPPLE_HEIGHT 10.0f
-
-float g_SkyOffsetX;
-float g_SkyOffsetY;
-
-struct vert_s {
-    float nx;
-    float ny;
-    float nz;
-    float s;
-    float t;
-    float x;
-    float y;
-    float z;
-};
-
-int offset(int x, int y, int width) {
-    return x + 1 + (y + 1) * (width + 2);
-}
-
-void dropWithStrength(int x, int y, int r, int s) {
-    int width = State->meshWidth;
-    int height = State->meshHeight;
-
-    if (x < r) x = r;
-    if (y < r) y = r;
-    if (x >= width - r) x = width - r - 1;
-    if (y >= height - r) y = height - r - 1;
-
-    x = width - x;
-
-    int rippleMapSize = State->rippleMapSize;
-    int index = State->rippleIndex;
-    int origin = offset(0, 0, width);
-
-    int* current = loadArrayI32(RSID_RIPPLE_MAP, index * rippleMapSize + origin);
-    int sqr = r * r;
-    float invs = 1.0f / s;
-
-    int h = 0;
-    for ( ; h < r; h += 1) {
-        int sqv = h * h;
-        int yn = origin + (y - h) * (width + 2);
-        int yp = origin + (y + h) * (width + 2);
-        int w = 0;
-        for ( ; w < r; w += 1) {
-            int squ = w * w;
-            if (squ + sqv < sqr) {
-                int v = -sqrtf((sqr - (squ + sqv)) << 16) * invs;
-                current[yn + x + w] = v;
-                current[yp + x + w] = v;
-                current[yn + x - w] = v;
-                current[yp + x - w] = v;
-            }
-        }
-    }
-}
-
-void drop(int x, int y, int r) {
-    dropWithStrength(x, y, r, 1);
-}
-
-void updateRipples() {
-    int rippleMapSize = State->rippleMapSize;
-    int width = State->meshWidth;
-    int height = State->meshHeight;
-    int index = State->rippleIndex;
-    int origin = offset(0, 0, width);
-
-    int* current = loadArrayI32(RSID_RIPPLE_MAP, index * rippleMapSize + origin);
-    int* next = loadArrayI32(RSID_RIPPLE_MAP, (1 - index) * rippleMapSize + origin);
-
-    storeI32(RSID_STATE, OFFSETOF_WorldState_rippleIndex, 1 - index);
-
-    int a = 1;
-    int b = width + 2;
-    int h = height;
-    while (h) {
-        int w = width;
-        while (w) {
-            int droplet = ((current[-b] + current[b] + current[-a] + current[a]) >> 1) - *next;
-            droplet -= (droplet >> DAMP);
-            *next = droplet;
-            current += 1;
-            next += 1;
-            w -= 1;
-        }
-        current += 2;
-        next += 2;
-        h -= 1;
-    }
-}
-
-int refraction(int d, int wave, int *map) {
-    int i = d;
-    if (i < 0) i = -i;
-    if (i > 512) i = 512;
-    int w = (wave + 0x10000) >> 8;
-    w &= ~(w >> 31);
-    int r = (map[i] * w) >> 3;
-    if (d < 0) {
-        return -r;
-    }
-    return r;
-}
-
-void generateRipples() {
-    int rippleMapSize = loadI32(RSID_STATE, OFFSETOF_WorldState_rippleMapSize);
-    int width = State->meshWidth;
-    int height = State->meshHeight;
-    int index = State->rippleIndex;
-    int origin = offset(0, 0, width);
-
-    int b = width + 2;
-
-    int* current = loadArrayI32(RSID_RIPPLE_MAP, index * rippleMapSize + origin);
-    int *map = loadArrayI32(RSID_REFRACTION_MAP, 0);
-    float *vertices = loadTriangleMeshVerticesF(NAMED_WaterMesh);
-    struct vert_s *vert = (struct vert_s *)vertices;
-
-    float fw = 1.f / width;
-    float fh = 1.f / height;
-    float fy = (1.0f / 512.0f) * (1.0f / RIPPLE_HEIGHT);
-
-    int h = height - 1;
-    while (h >= 0) {
-        int w = width - 1;
-        int wave = *current;
-        int offset = h * width;
-        struct vert_s *vtx = vert + offset + w;
-
-        while (w >= 0) {
-            int nextWave = current[1];
-            int dx = nextWave - wave;
-            int dy = current[b] - wave;
-
-            int offsetx = refraction(dx, wave, map) >> 16;
-            int u = (width - w) + offsetx;
-            u &= ~(u >> 31);
-            if (u >= width) u = width - 1;
-
-            int offsety = refraction(dy, wave, map) >> 16;
-            int v = (height - h) + offsety;
-            v &= ~(v >> 31);
-            if (v >= height) v = height - 1;
-
-            vtx->s = u * fw;
-            vtx->t = v * fh;
-            vtx->z = dy * fy;
-            vtx --;
-
-            w -= 1;
-            current += 1;
-            wave = nextWave;
-        }
-        h -= 1;
-        current += 2;
-    }
-
-    // Compute the normals for lighting
-    int y = 0;
-    for ( ; y < height; y += 1) {
-        int x = 0;
-        int yOffset = y * width;
-        struct vert_s *v = vert;
-
-        for ( ; x < width; x += 1) {
-            struct vec3_s n1, n2, n3;
-            vec3Sub(&n1, (struct vec3_s *)&(v+1)->x, (struct vec3_s *)&v->x);
-            vec3Sub(&n2, (struct vec3_s *)&(v+width)->x, (struct vec3_s *)&v->x);
-            vec3Cross(&n3, &n1, &n2);
-            vec3Norm(&n3);
-
-            // Average of previous normal and N1 x N2
-            vec3Sub(&n1, (struct vec3_s *)&(v+width+1)->x, (struct vec3_s *)&v->x);
-            vec3Cross(&n2, &n1, &n2);
-            vec3Add(&n3, &n3, &n2);
-            vec3Norm(&n3);
-
-            v->nx = n3.x;
-            v->ny = n3.y;
-            v->nz = -n3.z;
-            v += 1;
-
-            // reset Z
-            //vertices[(yOffset + x) << 3 + 7] = 0.0f;
-        }
-    }
-}
-
-float averageZ(float x1, float x2, float y1, float y2, float* vertices,
-        int meshWidth, int meshHeight, float glWidth, float glHeight) {
-
-    x1 = ((x1 + glWidth * 0.5f) / glWidth) * meshWidth;
-    x2 = ((x2 + glWidth * 0.5f) / glWidth) * meshWidth;
-    y1 = ((y1 + glHeight * 0.5f) / glHeight) * meshHeight;
-    y2 = ((y2 + glHeight * 0.5f) / glHeight) * meshHeight;
-
-    int quadX1 = clamp(x1, 0, meshWidth);
-    int quadX2 = clamp(x2, 0, meshWidth);
-    int quadY1 = clamp(y1, 0, meshHeight);
-    int quadY2 = clamp(y2, 0, meshHeight);
-
-    float z = 0.0f;
-    int vertexCount = 0;
-
-    int y = quadY1;
-    for ( ; y < quadY2; y += 1) {
-        int x = quadX1;
-        int yOffset = y * meshWidth;
-        for ( ; x < quadX2; x += 1) {
-            z += vertices[(yOffset + x) << 3 + 7];
-            vertexCount += 1;
-        }
-    }
-
-    return 55.0f * z / vertexCount;
-}
-
-void drawLeaf(int index, float* vertices, int meshWidth, int meshHeight,
-        float glWidth, float glHeight) {
-
-    float *leafStruct = loadArrayF(RSID_LEAVES, index);
-
-    float x = leafStruct[LEAF_STRUCT_X];
-    float x1 = x - LEAF_SIZE;
-    float x2 = x + LEAF_SIZE;
-
-    float y = leafStruct[LEAF_STRUCT_Y];
-    float y1 = y - LEAF_SIZE;
-    float y2 = y + LEAF_SIZE;
-
-    float u1 = leafStruct[LEAF_STRUCT_U1];
-    float u2 = leafStruct[LEAF_STRUCT_U2];
-
-    float z1 = 0.0f;
-    float z2 = 0.0f;
-    float z3 = 0.0f;
-    float z4 = 0.0f;
-
-    float a = leafStruct[LEAF_STRUCT_ALTITUDE];
-    float s = leafStruct[LEAF_STRUCT_SCALE];
-    float r = leafStruct[LEAF_STRUCT_ANGLE];
-
-    float tz = 0.0f;
-    if (a > 0.0f) {
-        tz = -a;
-    } else {
-//        z1 = averageZ(x1, x, y1, y, vertices, meshWidth, meshHeight, glWidth, glHeight);
-//        z2 = averageZ(x, x2, y1, y, vertices, meshWidth, meshHeight, glWidth, glHeight);
-//        z3 = averageZ(x, x2, y, y2, vertices, meshWidth, meshHeight, glWidth, glHeight);
-//        z4 = averageZ(x1, x, y, y2, vertices, meshWidth, meshHeight, glWidth, glHeight);
-    }
-
-    x1 -= x;
-    x2 -= x;
-    y1 -= y;
-    y2 -= y;
-
-    float matrix[16];
-    matrixLoadIdentity(matrix);
-    matrixTranslate(matrix, x, y, tz);
-    matrixScale(matrix, s, s, 1.0f);
-    matrixRotate(matrix, r, 0.0f, 0.0f, 1.0f);
-    vpLoadModelMatrix(matrix);
-
-    drawQuadTexCoords(x1, y1, z1, u1, 1.0f,
-                      x2, y1, z2, u2, 1.0f,
-                      x2, y2, z3, u2, 0.0f,
-                      x1, y2, z4, u1, 0.0f);
-
-    float spin = leafStruct[LEAF_STRUCT_SPIN];
-    if (a <= 0.0f) {
-        float rippled = leafStruct[LEAF_STRUCT_RIPPLED];
-        if (rippled < 0.0f) {
-            drop(((x + glWidth * 0.5f) / glWidth) * meshWidth,
-                 meshHeight - ((y + glHeight * 0.5f) / glHeight) * meshHeight,
-                 DROP_RADIUS);
-            spin /= 4.0f;
-            leafStruct[LEAF_STRUCT_SPIN] = spin;
-            leafStruct[LEAF_STRUCT_RIPPLED] = 1.0f;
-        } else {
-//            dropWithStrength(((x + glWidth / 2.0f) / glWidth) * meshWidth,
-//                meshHeight - ((y + glHeight / 2.0f) / glHeight) * meshHeight,
-//                2, 5);
-        }
-        leafStruct[LEAF_STRUCT_X] = x + leafStruct[LEAF_STRUCT_DELTAX];
-        leafStruct[LEAF_STRUCT_Y] = y + leafStruct[LEAF_STRUCT_DELTAY];
-        r += spin;
-        leafStruct[LEAF_STRUCT_ANGLE] = r;
-    } else {
-        a -= 0.005f;
-        leafStruct[LEAF_STRUCT_ALTITUDE] = a;
-        r += spin * 2.0f;
-        leafStruct[LEAF_STRUCT_ANGLE] = r;
-    }
-
-    if (-LEAF_SIZE * s + x > glWidth / 2.0f || LEAF_SIZE * s + x < -glWidth / 2.0f ||
-        LEAF_SIZE * s + y < -glHeight / 2.0f) {
-
-        int sprite = randf(LEAVES_TEXTURES_COUNT);
-        leafStruct[LEAF_STRUCT_X] = randf2(-1.0f, 1.0f);
-        leafStruct[LEAF_STRUCT_Y] = glHeight / 2.0f + LEAF_SIZE * 2 * randf(1.0f);
-        leafStruct[LEAF_STRUCT_SCALE] = randf2(0.4f, 0.5f);
-        leafStruct[LEAF_STRUCT_SPIN] = degf(randf2(-0.02f, 0.02f)) / 4.0f;
-        leafStruct[LEAF_STRUCT_U1] = sprite / (float) LEAVES_TEXTURES_COUNT;
-        leafStruct[LEAF_STRUCT_U2] = (sprite + 1) / (float) LEAVES_TEXTURES_COUNT;
-        leafStruct[LEAF_STRUCT_DELTAX] = randf2(-0.02f, 0.02f) / 60.0f;
-        leafStruct[LEAF_STRUCT_DELTAY] = -0.08f * randf2(0.9f, 1.1f) / 60.0f;
-    }
-}
-
-void drawLeaves() {
-    bindProgramFragment(NAMED_PFBackground);
-    bindProgramFragmentStore(NAMED_PFSLeaf);
-    bindProgramVertex(NAMED_PVSky);
-    bindTexture(NAMED_PFBackground, 0, NAMED_TLeaves);
-
-    int leavesCount = State->leavesCount;
-    int count = leavesCount * LEAF_STRUCT_FIELDS_COUNT;
-    int width = State->meshWidth;
-    int height = State->meshHeight;
-    float glWidth = State->glWidth;
-    float glHeight = State->glHeight;
-
-    float *vertices = loadTriangleMeshVerticesF(NAMED_WaterMesh);
-
-    int i = 0;
-    for ( ; i < count; i += LEAF_STRUCT_FIELDS_COUNT) {
-        drawLeaf(i, vertices, width, height, glWidth, glHeight);
-    }
-
-    float matrix[16];
-    matrixLoadIdentity(matrix);
-    vpLoadModelMatrix(matrix);
-}
-
-void drawRiverbed() {
-    bindTexture(NAMED_PFBackground, 0, NAMED_TRiverbed);
-
-    drawTriangleMesh(NAMED_WaterMesh);
-}
-
-void drawSky() {
-    color(1.0f, 1.0f, 1.0f, 0.8f);
-
-    bindProgramFragment(NAMED_PFSky);
-    bindProgramFragmentStore(NAMED_PFSLeaf);
-    bindTexture(NAMED_PFSky, 0, NAMED_TSky);
-
-    float x = g_SkyOffsetX + State->skySpeedX;
-    float y = g_SkyOffsetY + State->skySpeedY;
-
-    if (x > 1.0f) x = 0.0f;
-    if (x < -1.0f) x = 0.0f;
-    if (y > 1.0f) y = 0.0f;
-
-    g_SkyOffsetX = x;
-    g_SkyOffsetY = y;
-
-    float matrix[16];
-    matrixLoadTranslate(matrix, x, y, 0.0f);
-    vpLoadTextureMatrix(matrix);
-
-    drawTriangleMesh(NAMED_WaterMesh);
-
-    matrixLoadIdentity(matrix);
-    vpLoadTextureMatrix(matrix);
-}
-
-void drawLighting() {
-    ambient(0.0f, 0.0f, 0.0f, 1.0f);
-    diffuse(0.0f, 0.0f, 0.0f, 1.0f);
-    specular(0.44f, 0.44f, 0.44f, 1.0f);
-    shininess(40.0f);
-
-    bindProgramFragmentStore(NAMED_PFSBackground);
-    bindProgramFragment(NAMED_PFLighting);
-    bindProgramVertex(NAMED_PVLight);
-
-    drawTriangleMesh(NAMED_WaterMesh);
-}
-
-void drawNormals() {
-    int width = State->meshWidth;
-    int height = State->meshHeight;
-
-    float *vertices = loadTriangleMeshVerticesF(NAMED_WaterMesh);
-
-    bindProgramVertex(NAMED_PVSky);
-    bindProgramFragment(NAMED_PFLighting);
-
-    color(1.0f, 0.0f, 0.0f, 1.0f);
-
-    float scale = 1.0f / 10.0f;
-    int y = 0;
-    for ( ; y < height; y += 1) {
-        int yOffset = y * width;
-        int x = 0;
-        for ( ; x < width; x += 1) {
-            int offset = (yOffset + x) << 3;
-            float vx = vertices[offset + 5];
-            float vy = vertices[offset + 6];
-            float vz = vertices[offset + 7];
-            float nx = vertices[offset + 0];
-            float ny = vertices[offset + 1];
-            float nz = vertices[offset + 2];
-            drawLine(vx, vy, vz, vx + nx * scale, vy + ny * scale, vz + nz * scale);
-        }
-    }
-}
-
-int main(int index) {
-    if (Drop->dropX != -1) {
-        drop(Drop->dropX, Drop->dropY, DROP_RADIUS);
-        Drop->dropX = -1;
-        Drop->dropY = -1;
-    }
-
-    updateRipples();
-    generateRipples();
-    updateTriangleMesh(NAMED_WaterMesh);
-
-    drawRiverbed();
-    drawSky();
-    drawLighting();
-    drawLeaves();
-    //drawNormals();
-
-    return 1;
-}
diff --git a/libs/rs/java/Fall/src/com/android/fall/rs/Fall.java b/libs/rs/java/Fall/src/com/android/fall/rs/Fall.java
deleted file mode 100644
index b1d9b1d..0000000
--- a/libs/rs/java/Fall/src/com/android/fall/rs/Fall.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-package com.android.fall.rs;
-
-import android.app.Activity;
-import android.os.Bundle;
-
-public class Fall extends Activity {
-    private FallView mView;
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-
-        mView = new FallView(this);
-        setContentView(mView);
-    }
-
-    @Override
-    protected void onResume() {
-        super.onResume();
-        mView.onResume();
-    }
-
-    @Override
-    protected void onPause() {
-        super.onPause();
-        mView.onPause();
-
-        Runtime.getRuntime().exit(0);
-    }
-}
diff --git a/libs/rs/java/Fall/src/com/android/fall/rs/FallRS.java b/libs/rs/java/Fall/src/com/android/fall/rs/FallRS.java
deleted file mode 100644
index 33aa9ab..0000000
--- a/libs/rs/java/Fall/src/com/android/fall/rs/FallRS.java
+++ /dev/null
@@ -1,435 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.fall.rs;
-
-import android.content.res.Resources;
-import android.renderscript.RenderScript;
-import android.renderscript.ScriptC;
-import android.renderscript.ProgramFragment;
-import android.renderscript.ProgramStore;
-import android.renderscript.ProgramVertex;
-import android.renderscript.Allocation;
-import android.renderscript.Sampler;
-import android.renderscript.Element;
-import android.renderscript.Light;
-import android.renderscript.Type;
-import static android.renderscript.Sampler.Value.LINEAR;
-import static android.renderscript.Sampler.Value.WRAP;
-import static android.renderscript.ProgramStore.DepthFunc.*;
-import static android.renderscript.ProgramStore.BlendDstFunc;
-import static android.renderscript.ProgramStore.BlendSrcFunc;
-import static android.renderscript.ProgramFragment.EnvMode.*;
-import static android.renderscript.Element.*;
-import android.graphics.BitmapFactory;
-import android.graphics.Bitmap;
-import static android.util.MathUtils.*;
-
-import java.util.TimeZone;
-
-class FallRS {
-    private static final int MESH_RESOLUTION = 48;
-
-    private static final int RSID_STATE = 0;
-
-    private static final int TEXTURES_COUNT = 3;
-    private static final int LEAVES_TEXTURES_COUNT = 4;
-    private static final int RSID_TEXTURE_RIVERBED = 0;
-    private static final int RSID_TEXTURE_LEAVES = 1;
-    private static final int RSID_TEXTURE_SKY = 2;
-
-    private static final int RSID_RIPPLE_MAP = 1;
-
-    private static final int RSID_REFRACTION_MAP = 2;
-
-    private static final int RSID_LEAVES = 3;
-    private static final int LEAVES_COUNT = 14;
-    private static final int LEAF_STRUCT_FIELDS_COUNT = 11;
-    private static final int LEAF_STRUCT_X = 0;
-    private static final int LEAF_STRUCT_Y = 1;
-    private static final int LEAF_STRUCT_SCALE = 2;
-    private static final int LEAF_STRUCT_ANGLE = 3;
-    private static final int LEAF_STRUCT_SPIN = 4;
-    private static final int LEAF_STRUCT_U1 = 5;
-    private static final int LEAF_STRUCT_U2 = 6;
-    private static final int LEAF_STRUCT_ALTITUDE = 7;
-    private static final int LEAF_STRUCT_RIPPLED = 8;
-    private static final int LEAF_STRUCT_DELTAX = 9;
-    private static final int LEAF_STRUCT_DELTAY = 10;
-
-    class Leaf {
-        float x;
-        float y;
-        float scale;
-        float angle;
-        float spin;
-        float u1;
-        float u2;
-        float altitude;
-        float rippled;
-        float deltaX;
-        float deltaY;
-    }
-
-    private static final int RSID_DROP = 4;
-
-    private Resources mResources;
-    private RenderScript mRS;
-
-    private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options();
-
-    private final int mWidth;
-    private final int mHeight;
-
-    @SuppressWarnings({"FieldCanBeLocal"})
-    private ProgramFragment mPfBackground;
-    @SuppressWarnings({"FieldCanBeLocal"})
-    private ProgramFragment mPfLighting;
-    @SuppressWarnings({"FieldCanBeLocal"})
-    private ProgramFragment mPfSky;
-    @SuppressWarnings({"FieldCanBeLocal"})
-    private ProgramStore mPfsBackground;
-    @SuppressWarnings({"FieldCanBeLocal"})
-    private ProgramStore mPfsLeaf;
-    @SuppressWarnings({"FieldCanBeLocal"})
-    private ProgramVertex mPvLight;
-    @SuppressWarnings({"FieldCanBeLocal"})
-    private ProgramVertex mPvSky;
-
-    private Allocation mState;
-    private Allocation mDropState;
-    private DropState mDrop;
-    private Type mStateType;
-    private Type mDropType;
-    private int mMeshWidth;
-
-    private int mMeshHeight;
-    @SuppressWarnings({"FieldCanBeLocal"})
-    private RenderScript.TriangleMesh mMesh;
-
-    private Allocation mRippleMap;
-    private Allocation mRefractionMap;
-
-    private Allocation mLeaves;
-    private float mGlHeight;
-
-    public FallRS(int width, int height) {
-        mWidth = width;
-        mHeight = height;
-        mOptionsARGB.inScaled = false;
-        mOptionsARGB.inPreferredConfig = Bitmap.Config.ARGB_8888;
-    }
-
-    public void init(RenderScript rs, Resources res) {
-        mRS = rs;
-        mResources = res;
-        initRS();
-    }
-
-    private void initRS() {
-        createProgramVertex();
-        createProgramFragmentStore();
-        createProgramFragment();
-        createMesh();
-        createScriptStructures();
-        loadTextures();
-
-        ScriptC.Builder sb = new ScriptC.Builder(mRS);
-        sb.setType(mStateType, "State", RSID_STATE);
-        sb.setType(mDropType, "Drop", RSID_DROP);
-        sb.setScript(mResources, R.raw.fall);
-        sb.setRoot(true);
-
-        ScriptC script = sb.create();
-        script.setClearColor(0.0f, 0.0f, 0.0f, 1.0f);
-        script.setTimeZone(TimeZone.getDefault().getID());
-
-        script.bindAllocation(mState, RSID_STATE);
-        script.bindAllocation(mRippleMap, RSID_RIPPLE_MAP);
-        script.bindAllocation(mRefractionMap, RSID_REFRACTION_MAP);
-        script.bindAllocation(mLeaves, RSID_LEAVES);
-        script.bindAllocation(mDropState, RSID_DROP);
-
-        mRS.contextBindRootScript(script);
-    }
-
-    private void createMesh() {
-        final RenderScript rs = mRS;
-        rs.triangleMeshBegin(Element.NORM_ST_XYZ_F32, Element.INDEX_16);
-
-        int wResolution;
-        int hResolution;
-
-        final int width = mWidth;
-        final int height = mHeight;
-
-        if (width < height) {
-            wResolution = MESH_RESOLUTION;
-            hResolution = (int) (MESH_RESOLUTION * height / (float) width);
-        } else {
-            wResolution = (int) (MESH_RESOLUTION * width / (float) height);
-            hResolution = MESH_RESOLUTION;
-        }
-
-        mGlHeight = 2.0f * height / (float) width;
-        final float glHeight = mGlHeight;
-
-        float quadWidth = 2.0f / (float) wResolution;
-        float quadHeight = glHeight / (float) hResolution;
-
-        wResolution += 2;
-        hResolution += 2;
-
-        for (int y = 0; y <= hResolution; y++) {
-            final boolean shift = (y & 0x1) == 0;
-            final float yOffset = y * quadHeight - glHeight / 2.0f - quadHeight;
-            final float t = 1.0f - y / (float) hResolution;
-            for (int x = 0; x <= wResolution; x++) {
-                if (shift) {
-                    rs.triangleMeshAddVertex_XYZ_ST_NORM(
-                            -1.0f + x * quadWidth - quadWidth, yOffset, 0.0f,
-                            x / (float) wResolution, t,
-                            0.0f, 0.0f, -1.0f);
-                } else {
-                    rs.triangleMeshAddVertex_XYZ_ST_NORM(
-                            -1.0f + x * quadWidth - quadWidth * 0.5f, yOffset, 0.0f,
-                            x / (float) wResolution, t,
-                            0.0f, 0.0f, -1.0f);
-                }
-            }
-        }
-
-        for (int y = 0; y < hResolution; y++) {
-            final boolean shift = (y & 0x1) == 0;
-            final int yOffset = y * (wResolution + 1);
-            for (int x = 0; x < wResolution; x++) {
-                final int index = yOffset + x;
-                final int iWR1 = index + wResolution + 1;
-                if (shift) {
-                    rs.triangleMeshAddTriangle(index, index + 1, iWR1);
-                    rs.triangleMeshAddTriangle(index + 1, iWR1 + 1, iWR1);
-                } else {
-                    rs.triangleMeshAddTriangle(index, iWR1 + 1, iWR1);
-                    rs.triangleMeshAddTriangle(index, index + 1, iWR1 + 1);
-                }
-            }
-        }
-
-        mMesh = rs.triangleMeshCreate();
-        mMesh.setName("WaterMesh");
-
-        mMeshWidth = wResolution + 1;
-        mMeshHeight = hResolution + 1;
-    }
-
-    private void createScriptStructures() {
-        final int rippleMapSize = (mMeshWidth + 2) * (mMeshHeight + 2);
-
-        createState(rippleMapSize);
-        createRippleMap(rippleMapSize);
-        createRefractionMap();
-        createLeaves();
-    }
-
-    private void createLeaves() {
-        final float[] leaves = new float[LEAVES_COUNT * LEAF_STRUCT_FIELDS_COUNT];
-        mLeaves = Allocation.createSized(mRS, USER_FLOAT, leaves.length);
-        for (int i = 0; i < leaves.length; i += LEAF_STRUCT_FIELDS_COUNT) {
-            createLeaf(leaves, i);
-        }
-        mLeaves.data(leaves);
-    }
-
-    private void createRefractionMap() {
-        final int[] refractionMap = new int[513];
-        float ir = 1.0f / 1.333f;
-        for (int i = 0; i < refractionMap.length; i++) {
-            float d = (float) Math.tan(Math.asin(Math.sin(Math.atan(i * (1.0f / 256.0f))) * ir));
-            refractionMap[i] = (int) Math.floor(d * (1 << 16) + 0.5f);
-        }
-        mRefractionMap = Allocation.createSized(mRS, USER_I32, refractionMap.length);
-        mRefractionMap.data(refractionMap);
-    }
-
-    private void createRippleMap(int rippleMapSize) {
-        final int[] rippleMap = new int[rippleMapSize * 2];
-        mRippleMap = Allocation.createSized(mRS, USER_I32, rippleMap.length);
-        mRippleMap.data(rippleMap);
-    }
-
-    static class WorldState {
-        public int frameCount;
-        public int width;
-        public int height;
-        public int meshWidth;
-        public int meshHeight;
-        public int rippleMapSize;
-        public int rippleIndex;
-        public int leavesCount;
-        public float glWidth;
-        public float glHeight;
-        public float skySpeedX;
-        public float skySpeedY;
-    }
-
-    static class DropState {
-        public int dropX;
-        public int dropY;
-    }
-
-    private void createState(int rippleMapSize) {
-        WorldState worldState = new WorldState();
-        worldState.width = mWidth;
-        worldState.height = mHeight;
-        worldState.meshWidth = mMeshWidth;
-        worldState.meshHeight = mMeshHeight;
-        worldState.rippleMapSize = rippleMapSize;
-        worldState.rippleIndex = 0;
-        worldState.leavesCount = LEAVES_COUNT;
-        worldState.glWidth = 2.0f;
-        worldState.glHeight = mGlHeight;
-        worldState.skySpeedX = random(-0.001f, 0.001f);
-        worldState.skySpeedY = random(0.00008f, 0.0002f);
-
-        mStateType = Type.createFromClass(mRS, WorldState.class, 1, "WorldState");
-        mState = Allocation.createTyped(mRS, mStateType);
-        mState.data(worldState);
-
-        mDrop = new DropState();
-        mDrop.dropX = -1;
-        mDrop.dropY = -1;
-
-        mDropType = Type.createFromClass(mRS, DropState.class, 1, "DropState");
-        mDropState = Allocation.createTyped(mRS, mDropType);
-        mDropState.data(mDrop);
-    }
-
-    private void createLeaf(float[] leaves, int index) {
-        int sprite = random(LEAVES_TEXTURES_COUNT);
-        //noinspection PointlessArithmeticExpression
-        leaves[index + LEAF_STRUCT_X] = random(-1.0f, 1.0f);
-        leaves[index + LEAF_STRUCT_Y] = random(-mGlHeight / 2.0f, mGlHeight / 2.0f);
-        leaves[index + LEAF_STRUCT_SCALE] = random(0.4f, 0.5f);
-        leaves[index + LEAF_STRUCT_ANGLE] = random(0.0f, 360.0f);
-        leaves[index + LEAF_STRUCT_SPIN] = degrees(random(-0.02f, 0.02f)) / 4.0f;
-        leaves[index + LEAF_STRUCT_U1] = sprite / (float) LEAVES_TEXTURES_COUNT;
-        leaves[index + LEAF_STRUCT_U2] = (sprite + 1) / (float) LEAVES_TEXTURES_COUNT;
-        leaves[index + LEAF_STRUCT_ALTITUDE] = -1.0f;
-        leaves[index + LEAF_STRUCT_RIPPLED] = 1.0f;
-        leaves[index + LEAF_STRUCT_DELTAX] = random(-0.02f, 0.02f) / 60.0f;
-        leaves[index + LEAF_STRUCT_DELTAY] = -0.08f * random(0.9f, 1.1f) / 60.0f;
-    }
-
-    private void loadTextures() {
-        final Allocation[] textures = new Allocation[TEXTURES_COUNT];
-        textures[RSID_TEXTURE_RIVERBED] = loadTexture(R.drawable.riverbed, "TRiverbed");
-        textures[RSID_TEXTURE_LEAVES] = loadTextureARGB(R.drawable.leaves, "TLeaves");
-        textures[RSID_TEXTURE_SKY] = loadTextureARGB(R.drawable.sky, "TSky");
-
-        final int count = textures.length;
-        for (int i = 0; i < count; i++) {
-            final Allocation texture = textures[i];
-            texture.uploadToTexture(0);
-        }
-    }
-
-    private Allocation loadTexture(int id, String name) {
-        final Allocation allocation = Allocation.createFromBitmapResource(mRS, mResources,
-                id, RGB_565, false);
-        allocation.setName(name);
-        return allocation;
-    }
-
-    private Allocation loadTextureARGB(int id, String name) {
-        Bitmap b = BitmapFactory.decodeResource(mResources, id, mOptionsARGB);
-        final Allocation allocation = Allocation.createFromBitmap(mRS, b, RGBA_8888, false);
-        allocation.setName(name);
-        return allocation;
-    }
-
-    private void createProgramFragment() {
-        Sampler.Builder sampleBuilder = new Sampler.Builder(mRS);
-        sampleBuilder.setMin(LINEAR);
-        sampleBuilder.setMag(LINEAR);
-        sampleBuilder.setWrapS(WRAP);
-        sampleBuilder.setWrapT(WRAP);
-        Sampler sampler = sampleBuilder.create();
-
-        ProgramFragment.Builder builder = new ProgramFragment.Builder(mRS, null, null);
-        builder.setTexEnable(true, 0);
-        builder.setTexEnvMode(REPLACE, 0);
-        mPfBackground = builder.create();
-        mPfBackground.setName("PFBackground");
-        mPfBackground.bindSampler(sampler, 0);
-
-        builder = new ProgramFragment.Builder(mRS, null, null);
-        builder.setTexEnable(false, 0);
-        mPfLighting = builder.create();
-        mPfLighting.setName("PFLighting");
-        mPfLighting.bindSampler(sampler, 0);
-
-        builder = new ProgramFragment.Builder(mRS, null, null);
-        builder.setTexEnable(true, 0);
-        builder.setTexEnvMode(MODULATE, 0);
-        mPfSky = builder.create();
-        mPfSky.setName("PFSky");
-        mPfSky.bindSampler(sampler, 0);
-    }
-
-    private void createProgramFragmentStore() {
-        ProgramStore.Builder builder = new ProgramStore.Builder(mRS, null, null);
-        builder.setDepthFunc(ALWAYS);
-        builder.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ONE);
-        builder.setDitherEnable(false);
-        builder.setDepthMask(true);
-        mPfsBackground = builder.create();
-        mPfsBackground.setName("PFSBackground");
-
-        builder = new ProgramStore.Builder(mRS, null, null);
-        builder.setDepthFunc(ALWAYS);
-        builder.setBlendFunc(BlendSrcFunc.SRC_ALPHA, BlendDstFunc.ONE_MINUS_SRC_ALPHA);
-        builder.setDitherEnable(false);
-        builder.setDepthMask(true);
-        mPfsLeaf = builder.create();
-        mPfsLeaf.setName("PFSLeaf");
-    }
-
-    private void createProgramVertex() {
-        ProgramVertex.MatrixAllocation pvOrthoAlloc = new ProgramVertex.MatrixAllocation(mRS);
-        pvOrthoAlloc.setupProjectionNormalized(mWidth, mHeight);
-
-        Light light = new Light.Builder(mRS).create();
-        light.setPosition(0.0f, 2.0f, -8.0f);
-
-        ProgramVertex.Builder builder = new ProgramVertex.Builder(mRS, null, null);
-        builder.addLight(light);
-        mPvLight = builder.create();
-        mPvLight.bindAllocation(pvOrthoAlloc);
-        mPvLight.setName("PVLight");
-
-        builder = new ProgramVertex.Builder(mRS, null, null);
-        builder.setTextureMatrixEnable(true);
-        mPvSky = builder.create();
-        mPvSky.bindAllocation(pvOrthoAlloc);
-        mPvSky.setName("PVSky");
-    }
-
-    void addDrop(float x, float y) {
-        mDrop.dropX = (int) ((x / mWidth) * mMeshWidth);
-        mDrop.dropY = (int) ((y / mHeight) * mMeshHeight);
-        mDropState.data(mDrop);
-    }
-}
diff --git a/libs/rs/java/Fall/src/com/android/fall/rs/FallView.java b/libs/rs/java/Fall/src/com/android/fall/rs/FallView.java
deleted file mode 100644
index 7468d2b..0000000
--- a/libs/rs/java/Fall/src/com/android/fall/rs/FallView.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-package com.android.fall.rs;
-
-import android.content.Context;
-import android.view.SurfaceHolder;
-import android.view.MotionEvent;
-import android.view.KeyEvent;
-import android.renderscript.RenderScript;
-import android.renderscript.RSSurfaceView;
-
-class FallView extends RSSurfaceView {
-    private FallRS mRender;
-
-    public FallView(Context context) {
-        super(context);
-        setFocusable(true);
-        setFocusableInTouchMode(true);
-    }
-
-    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
-        super.surfaceChanged(holder, format, w, h);
-
-        RenderScript RS = createRenderScript(false);
-        mRender = new FallRS(w, h);
-        mRender.init(RS, getResources());
-    }
-
-    @Override
-    public boolean onTouchEvent(MotionEvent event) {
-        switch (event.getAction()) {
-            case MotionEvent.ACTION_DOWN:
-            case MotionEvent.ACTION_MOVE:
-                mRender.addDrop(event.getX(), event.getY());
-                try {
-                    Thread.sleep(16);
-                } catch (InterruptedException e) {
-                    // Ignore
-                }
-                break;
-        }
-        return true;
-    }
-}
diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index 651e7cf..d893f0a 100644
--- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -103,10 +103,22 @@
     }
 
     // initialize EGL
-    const EGLint attribs[] = {
+    EGLint attribs[] = {
             EGL_SURFACE_TYPE,   EGL_WINDOW_BIT,
+            EGL_NONE,           0,
             EGL_NONE
     };
+
+    // debug: disable h/w rendering
+    char property[PROPERTY_VALUE_MAX];
+    if (property_get("debug.sf.hw", property, NULL) > 0) {
+        if (atoi(property) == 0) {
+            LOGW("H/W composition disabled");
+            attribs[2] = EGL_CONFIG_CAVEAT;
+            attribs[3] = EGL_SLOW_CONFIG;
+        }
+    }
+
     EGLint w, h, dummy;
     EGLint numConfigs=0;
     EGLSurface surface;
@@ -193,7 +205,6 @@
     mDpiY = mNativeWindow->ydpi;
     mRefreshRate = fbDev->fps; 
     
-    char property[PROPERTY_VALUE_MAX];
     /* Read density from build-specific ro.sf.lcd_density property
      * except if it is overridden by qemu.sf.lcd_density.
      */
diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp
index ecb6b32..6275910 100644
--- a/libs/surfaceflinger/Layer.cpp
+++ b/libs/surfaceflinger/Layer.cpp
@@ -49,13 +49,12 @@
 
 Layer::Layer(SurfaceFlinger* flinger, DisplayID display, 
         const sp<Client>& c, int32_t i)
-    :   LayerBaseClient(flinger, display, c, i), lcblk(NULL),
+    :   LayerBaseClient(flinger, display, c, i),
         mSecure(false),
         mNeedsBlending(true)
 {
     // no OpenGL operation is possible here, since we might not be
     // in the OpenGL thread.
-    lcblk = new SharedBufferServer(c->ctrlblk, i, NUM_BUFFERS);
     mFrontBufferIndex = lcblk->getFrontBuffer();
 }
 
@@ -63,8 +62,14 @@
 {
     destroy();
     // the actual buffers will be destroyed here
-    delete lcblk;
+}
 
+// called with SurfaceFlinger::mStateLock as soon as the layer is entered
+// in the purgatory list
+void Layer::onRemoved()
+{
+    // wake up the condition
+    lcblk->setStatus(NO_INIT);
 }
 
 void Layer::destroy()
@@ -79,7 +84,9 @@
             eglDestroyImageKHR(dpy, mTextures[i].image);
             mTextures[i].image = EGL_NO_IMAGE_KHR;
         }
+        Mutex::Autolock _l(mLock);
         mBuffers[i].clear();
+        mWidth = mHeight = 0;
     }
     mSurface.clear();
 }
@@ -213,6 +220,16 @@
 
 sp<SurfaceBuffer> Layer::requestBuffer(int index, int usage)
 {
+    sp<Buffer> buffer;
+
+    // this ensures our client doesn't go away while we're accessing
+    // the shared area.
+    sp<Client> ourClient(client.promote());
+    if (ourClient == 0) {
+        // oops, the client is already gone
+        return buffer;
+    }
+
     /*
      * This is called from the client's Surface::dequeue(). This can happen
      * at any time, especially while we're in the middle of using the
@@ -225,12 +242,21 @@
      */
     status_t err = lcblk->assertReallocate(index);
     LOGE_IF(err, "assertReallocate(%d) failed (%s)", index, strerror(-err));
+    if (err != NO_ERROR) {
+        // the surface may have died
+        return buffer;
+    }
 
-    Mutex::Autolock _l(mLock);
-    uint32_t w = mWidth;
-    uint32_t h = mHeight;
-    
-    sp<Buffer>& buffer(mBuffers[index]);
+    uint32_t w, h;
+    { // scope for the lock
+        Mutex::Autolock _l(mLock);
+        w = mWidth;
+        h = mHeight;
+        buffer = mBuffers[index];
+        mBuffers[index].clear();
+    }
+
+
     if (buffer->getStrongCount() == 1) {
         err = buffer->reallocate(w, h, mFormat, usage, mBufferFlags);
     } else {
@@ -253,8 +279,16 @@
     }
 
     if (err == NO_ERROR && buffer->handle != 0) {
-        // texture is now dirty...
-        mTextures[index].dirty = true;
+        Mutex::Autolock _l(mLock);
+        if (mWidth && mHeight) {
+            // and we have new buffer
+            mBuffers[index] = buffer;
+            // texture is now dirty...
+            mTextures[index].dirty = true;
+        } else {
+            // oops we got killed while we were allocating the buffer
+            buffer.clear();
+        }
     }
     return buffer;
 }
diff --git a/libs/surfaceflinger/Layer.h b/libs/surfaceflinger/Layer.h
index 3b4489e..2e8173d 100644
--- a/libs/surfaceflinger/Layer.h
+++ b/libs/surfaceflinger/Layer.h
@@ -51,10 +51,6 @@
     static const char* const typeID;
     virtual char const* getTypeID() const { return typeID; }
     virtual uint32_t getTypeInfo() const { return typeInfo; }
-
-    
-    SharedBufferServer*     lcblk;
-
     
                  Layer(SurfaceFlinger* flinger, DisplayID display,
                          const sp<Client>& client, int32_t i);
@@ -88,6 +84,8 @@
         return mBuffers[mFrontBufferIndex];
     }
  
+    virtual void onRemoved();
+
     void reloadTexture(const Region& dirty);
 
     sp<SurfaceBuffer> requestBuffer(int index, int usage);
diff --git a/libs/surfaceflinger/LayerBase.cpp b/libs/surfaceflinger/LayerBase.cpp
index 62e41b0..1f22488 100644
--- a/libs/surfaceflinger/LayerBase.cpp
+++ b/libs/surfaceflinger/LayerBase.cpp
@@ -642,9 +642,12 @@
 
 LayerBaseClient::LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,
         const sp<Client>& client, int32_t i)
-    : LayerBase(flinger, display), client(client),
+    : LayerBase(flinger, display), lcblk(NULL), client(client),
       mIndex(i), mIdentity(uint32_t(android_atomic_inc(&sIdentity)))
 {
+    lcblk = new SharedBufferServer(
+            client->ctrlblk, i, NUM_BUFFERS,
+            mIdentity);
 }
 
 void LayerBaseClient::onFirstRef()
@@ -652,8 +655,6 @@
     sp<Client> client(this->client.promote());
     if (client != 0) {
         client->bindLayer(this, mIndex);
-        // Initialize this layer's identity
-        client->ctrlblk->setIdentity(mIndex, mIdentity);
     }
 }
 
@@ -663,6 +664,7 @@
     if (client != 0) {
         client->free(mIndex);
     }
+    delete lcblk;
 }
 
 int32_t LayerBaseClient::serverIndex() const 
diff --git a/libs/surfaceflinger/LayerBase.h b/libs/surfaceflinger/LayerBase.h
index 78bb4bf..3a52240 100644
--- a/libs/surfaceflinger/LayerBase.h
+++ b/libs/surfaceflinger/LayerBase.h
@@ -292,13 +292,16 @@
     virtual char const* getTypeID() const { return typeID; }
     virtual uint32_t getTypeInfo() const { return typeInfo; }
 
+    // lcblk is (almost) only accessed from the main SF thread, in the places
+    // where it's not, a reference to Client must be held
+    SharedBufferServer*     lcblk;
+
     LayerBaseClient(SurfaceFlinger* flinger, DisplayID display, 
             const sp<Client>& client, int32_t i);
     virtual ~LayerBaseClient();
     virtual void onFirstRef();
 
-    wp<Client>              client;
-//    SharedBufferServer*     lcblk;
+    const wp<Client>    client;
 
     inline  uint32_t    getIdentity() const { return mIdentity; }
     inline  int32_t     clientIndex() const { return mIndex; }
@@ -308,6 +311,7 @@
             sp<Surface> getSurface();
     virtual sp<Surface> createSurface() const;
     
+    virtual void onRemoved() { }
 
     class Surface : public BnSurface 
     {
diff --git a/libs/surfaceflinger/LayerBlur.cpp b/libs/surfaceflinger/LayerBlur.cpp
index 00abd5a..e14f35b 100644
--- a/libs/surfaceflinger/LayerBlur.cpp
+++ b/libs/surfaceflinger/LayerBlur.cpp
@@ -24,6 +24,7 @@
 #include <GLES/gl.h>
 #include <GLES/glext.h>
 
+#include "clz.h"
 #include "BlurFilter.h"
 #include "LayerBlur.h"
 #include "SurfaceFlinger.h"
@@ -40,7 +41,8 @@
 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)
+     mRefreshCache(true), mCacheAge(0), mTextureName(-1U), 
+     mWidthScale(1.0f), mHeightScale(1.0f)
 {
 }
 
@@ -164,11 +166,26 @@
             bl.format = GGL_PIXEL_FORMAT_RGB_565;
             bl.data = (GGLubyte*)pixels;            
             blurFilter(&bl, 8, 2);
-            
-            // NOTE: this works only because we have POT. we'd have to round the
-            // texture size up, otherwise.
-            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0,
-                    GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixels);
+
+            if (mFlags & (DisplayHardware::NPOT_EXTENSION)) {
+                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0,
+                        GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixels);
+                mWidthScale  = 1.0f / w;
+                mHeightScale =-1.0f / h;
+                mYOffset = 0;
+            } else {
+                GLuint tw = 1 << (31 - clz(w));
+                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);
+                glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, w, h, 
+                        GL_RGB, GL_UNSIGNED_SHORT_5_6_5, pixels);
+                mWidthScale  = 1.0f / tw;
+                mHeightScale =-1.0f / th;
+                mYOffset = th-h;
+            }
 
             free((void*)pixels);
         }
@@ -184,7 +201,12 @@
             glDisable(GL_BLEND);
         }
 
-        glDisable(GL_DITHER);
+        if (mFlags & DisplayHardware::SLOW_CONFIG) {
+            glDisable(GL_DITHER);
+        } else {
+            glEnable(GL_DITHER);
+        }
+
         glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
         glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
         glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
@@ -194,8 +216,8 @@
             // This is a very rare scenario.
             glMatrixMode(GL_TEXTURE);
             glLoadIdentity();
-            glScalef(1.0f/w, -1.0f/h, 1);
-            glTranslatef(-x, -y, 0);
+            glScalef(mWidthScale, mHeightScale, 1);
+            glTranslatef(-x, mYOffset - y, 0);
             glEnableClientState(GL_TEXTURE_COORD_ARRAY);
             glVertexPointer(2, GL_FIXED, 0, mVertices);
             glTexCoordPointer(2, GL_FIXED, 0, mVertices);
@@ -205,6 +227,7 @@
                 glScissor(r.left, sy, r.width(), r.height());
                 glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 
             }       
+            glDisableClientState(GL_TEXTURE_COORD_ARRAY);
         } else {
             // NOTE: this is marginally faster with the software gl, because
             // glReadPixels() reads the fb bottom-to-top, however we'll
@@ -221,8 +244,6 @@
             }
         }
     }
-
-    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 }
 
 // ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/LayerBlur.h b/libs/surfaceflinger/LayerBlur.h
index 0c3e6eb..bf36ae4 100644
--- a/libs/surfaceflinger/LayerBlur.h
+++ b/libs/surfaceflinger/LayerBlur.h
@@ -56,6 +56,9 @@
     mutable bool    mAutoRefreshPending;
             nsecs_t mCacheAge;
     mutable GLuint  mTextureName;
+    mutable GLfloat mWidthScale;
+    mutable GLfloat mHeightScale;
+    mutable GLfloat mYOffset;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/libs/surfaceflinger/LayerBuffer.cpp b/libs/surfaceflinger/LayerBuffer.cpp
index 433b48e..bbfc54b9 100644
--- a/libs/surfaceflinger/LayerBuffer.cpp
+++ b/libs/surfaceflinger/LayerBuffer.cpp
@@ -133,6 +133,14 @@
     return false;
 }
 
+void LayerBuffer::serverDestroy()
+{
+    sp<Source> source(clearSource());
+    if (source != 0) {
+        source->destroy();
+    }
+}
+
 /**
  * This creates a "buffer" source for this surface
  */
@@ -354,7 +362,7 @@
 {    
     ISurface::BufferHeap buffers;
     { // scope for the lock
-        Mutex::Autolock _l(mLock);
+        Mutex::Autolock _l(mBufferSourceLock);
         buffers = mBufferHeap;
         if (buffers.heap != 0) {
             const size_t memorySize = buffers.heap->getSize();
@@ -379,7 +387,7 @@
 
 void LayerBuffer::BufferSource::unregisterBuffers()
 {
-    Mutex::Autolock _l(mLock);
+    Mutex::Autolock _l(mBufferSourceLock);
     mBufferHeap.heap.clear();
     mBuffer.clear();
     mLayer.invalidate();
@@ -387,13 +395,13 @@
 
 sp<LayerBuffer::Buffer> LayerBuffer::BufferSource::getBuffer() const
 {
-    Mutex::Autolock _l(mLock);
+    Mutex::Autolock _l(mBufferSourceLock);
     return mBuffer;
 }
 
 void LayerBuffer::BufferSource::setBuffer(const sp<LayerBuffer::Buffer>& buffer)
 {
-    Mutex::Autolock _l(mLock);
+    Mutex::Autolock _l(mBufferSourceLock);
     mBuffer = buffer;
 }
 
@@ -413,7 +421,7 @@
 
     status_t err = NO_ERROR;
     NativeBuffer src(ourBuffer->getBuffer());
-    const Rect& transformedBounds = mLayer.getTransformedBounds();
+    const Rect transformedBounds(mLayer.getTransformedBounds());
     copybit_device_t* copybit = mBlitEngine;
 
     if (copybit)  {
@@ -493,7 +501,7 @@
                 }
             }
 
-            const Rect& transformedBounds = mLayer.getTransformedBounds();
+            const Rect transformedBounds(mLayer.getTransformedBounds());
             const copybit_rect_t& drect =
                 reinterpret_cast<const copybit_rect_t&>(transformedBounds);
             const State& s(mLayer.drawingState());
@@ -583,9 +591,7 @@
 
     mOverlayHandle = overlay->getHandleRef(overlay);
     
-    // NOTE: here it's okay to acquire a reference to "this"m as long as
-    // the reference is not released before we leave the ctor.
-    sp<OverlayChannel> channel = new OverlayChannel(this);
+    sp<OverlayChannel> channel = new OverlayChannel( &layer );
 
     *overlayRef = new OverlayRef(mOverlayHandle, channel,
             mWidth, mHeight, mFormat, mWidthStride, mHeightStride);
@@ -601,7 +607,6 @@
 
 void LayerBuffer::OverlaySource::onDraw(const Region& clip) const
 {
-    GLclampx color = 0x000018; //dark blue
     GLclampx red = 0;
     GLclampx green = 0;
     GLclampx blue = 0x1818;
@@ -626,14 +631,14 @@
         if (mVisibilityChanged || !mInitialized) {
             mVisibilityChanged = false;
             mInitialized = true;
-            const Rect& bounds = mLayer.getTransformedBounds();
+            const Rect bounds(mLayer.getTransformedBounds());
             int x = bounds.left;
             int y = bounds.top;
             int w = bounds.width();
             int h = bounds.height();
             
             // we need a lock here to protect "destroy"
-            Mutex::Autolock _l(mLock);
+            Mutex::Autolock _l(mOverlaySourceLock);
             if (mOverlay) {
                 overlay_control_device_t* overlay_dev = mOverlayDevice;
                 overlay_dev->setPosition(overlay_dev, mOverlay, x,y,w,h);
@@ -645,17 +650,11 @@
     }
 }
 
-void LayerBuffer::OverlaySource::serverDestroy() 
-{
-    mLayer.clearSource();
-    destroyOverlay();
-}
-
-void LayerBuffer::OverlaySource::destroyOverlay() 
+void LayerBuffer::OverlaySource::destroy()
 {
     // we need a lock here to protect "onVisibilityResolved"
-    Mutex::Autolock _l(mLock);
-    if (mOverlay) {
+    Mutex::Autolock _l(mOverlaySourceLock);
+    if (mOverlay && mOverlayDevice) {
         overlay_control_device_t* overlay_dev = mOverlayDevice;
         overlay_dev->destroyOverlay(overlay_dev, mOverlay);
         mOverlay = 0;
diff --git a/libs/surfaceflinger/LayerBuffer.h b/libs/surfaceflinger/LayerBuffer.h
index e539f68..0452818 100644
--- a/libs/surfaceflinger/LayerBuffer.h
+++ b/libs/surfaceflinger/LayerBuffer.h
@@ -49,6 +49,7 @@
         virtual void postBuffer(ssize_t offset);
         virtual void unregisterBuffers();
         virtual bool transformed() const;
+        virtual void destroy() { }
     protected:
         LayerBuffer& mLayer;
     };
@@ -81,10 +82,12 @@
     sp<Source> getSource() const;
     sp<Source> clearSource();
     void setNeedsBlending(bool blending);
-    const Rect& getTransformedBounds() const {
+    Rect getTransformedBounds() const {
         return mTransformedBounds;
     }
 
+    void serverDestroy();
+
 private:
     struct NativeBuffer {
         copybit_image_t   img;
@@ -123,8 +126,9 @@
         virtual void postBuffer(ssize_t offset);
         virtual void unregisterBuffers();
         virtual bool transformed() const;
+        virtual void destroy() { }
     private:
-        mutable Mutex                   mLock;
+        mutable Mutex                   mBufferSourceLock;
         sp<Buffer>                      mBuffer;
         status_t                        mStatus;
         ISurface::BufferHeap            mBufferHeap;
@@ -143,28 +147,23 @@
         virtual void onDraw(const Region& clip) const;
         virtual void onTransaction(uint32_t flags);
         virtual void onVisibilityResolved(const Transform& planeTransform);
+        virtual void destroy();
     private:
-        void serverDestroy(); 
-        void destroyOverlay(); 
+
         class OverlayChannel : public BnOverlay {
-            mutable Mutex mLock;
-            sp<OverlaySource> mSource;
+            wp<LayerBuffer> mLayer;
             virtual void destroy() {
-                sp<OverlaySource> source;
-                { // scope for the lock;
-                    Mutex::Autolock _l(mLock);
-                    source = mSource;
-                    mSource.clear();
-                }
-                if (source != 0) {
-                    source->serverDestroy();
+                sp<LayerBuffer> layer(mLayer.promote());
+                if (layer != 0) {
+                    layer->serverDestroy();
                 }
             }
         public:
-            OverlayChannel(const sp<OverlaySource>& source)
-                : mSource(source) {
+            OverlayChannel(const sp<LayerBuffer>& layer)
+                : mLayer(layer) {
             }
         };
+        
         friend class OverlayChannel;
         bool mVisibilityChanged;
 
@@ -176,7 +175,7 @@
         int32_t mFormat;
         int32_t mWidthStride;
         int32_t mHeightStride;
-        mutable Mutex mLock;
+        mutable Mutex mOverlaySourceLock;
         bool mInitialized;
     };
 
@@ -199,7 +198,7 @@
             return static_cast<LayerBuffer*>(Surface::getOwner().get());
         }
     };
-    
+
     mutable Mutex   mLock;
     sp<Source>      mSource;
     sp<Surface>     mSurface;
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index b368db6..8685f99 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -654,6 +654,7 @@
         // some layers might have been removed, so
         // we need to update the regions they're exposing.
         if (mLayersRemoved) {
+            mLayersRemoved = false;
             mVisibleRegionsDirty = true;
             const LayerVector& previousLayers(mDrawingState.layersSortedByZ);
             const size_t count = previousLayers.size();
@@ -1093,9 +1094,6 @@
 
 void SurfaceFlinger::free_resources_l()
 {
-    // Destroy layers that were removed
-    mLayersRemoved = false;
-    
     // free resources associated with disconnected clients
     Vector< sp<Client> >& disconnectedClients(mDisconnectedClients);
     const size_t count = disconnectedClients.size();
@@ -1321,11 +1319,15 @@
      * to wait for all client's references to go away first).
      */
 
+    status_t err = NAME_NOT_FOUND;
     Mutex::Autolock _l(mStateLock);
     sp<LayerBaseClient> layer = getLayerUser_l(index);
-    status_t err = purgatorizeLayer_l(layer);
-    if (err == NO_ERROR) {
-        setTransactionFlags(eTransactionNeeded);
+    if (layer != 0) {
+        err = purgatorizeLayer_l(layer);
+        if (err == NO_ERROR) {
+            layer->onRemoved();
+            setTransactionFlags(eTransactionNeeded);
+        }
     }
     return err;
 }
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
index 348dd68..9577044 100644
--- a/libs/ui/Android.mk
+++ b/libs/ui/Android.mk
@@ -40,4 +40,8 @@
 
 LOCAL_MODULE:= libui
 
+ifeq ($(TARGET_SIMULATOR),true)
+    LOCAL_LDLIBS += -lpthread
+endif
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/libs/ui/SharedBufferStack.cpp b/libs/ui/SharedBufferStack.cpp
index 5995af5..436d793 100644
--- a/libs/ui/SharedBufferStack.cpp
+++ b/libs/ui/SharedBufferStack.cpp
@@ -53,21 +53,20 @@
     return uint32_t(surfaces[token].identity);
 }
 
-status_t SharedClient::setIdentity(size_t token, uint32_t identity) {
-    if (token >= NUM_LAYERS_MAX)
-        return BAD_INDEX;
-    surfaces[token].identity = identity;
-    return NO_ERROR;
-}
-
 // ----------------------------------------------------------------------------
 
 
 SharedBufferStack::SharedBufferStack()
-    : inUse(-1), identity(-1), status(NO_ERROR)
 {
 }
 
+void SharedBufferStack::init(int32_t i)
+{
+    inUse = -1;
+    status = NO_ERROR;
+    identity = i;
+}
+
 status_t SharedBufferStack::setDirtyRegion(int buffer, const Region& dirty)
 {
     if (uint32_t(buffer) >= NUM_BUFFER_MAX)
@@ -231,16 +230,46 @@
     return head;
 }
 
+SharedBufferServer::StatusUpdate::StatusUpdate(
+        SharedBufferBase* sbb, status_t status)
+    : UpdateBase(sbb), status(status) {
+}
+
+ssize_t SharedBufferServer::StatusUpdate::operator()() {
+    android_atomic_write(status, &stack.status);
+    return NO_ERROR;
+}
+
 // ============================================================================
 
 SharedBufferClient::SharedBufferClient(SharedClient* sharedClient,
         int surface, int num)
     : SharedBufferBase(sharedClient, surface, num), tail(0)
 {
+    SharedBufferStack& stack( *mSharedStack );
+    int32_t avail;
+    int32_t head;
+    // we need to make sure we read available and head coherently,
+    // w.r.t RetireUpdate.
+    do {
+        avail = stack.available;
+        head = stack.head;
+    } while (stack.available != avail);
+    tail = head - avail + 1;
+    if (tail < 0) {
+        tail += num;
+    }
 }
 
 ssize_t SharedBufferClient::dequeue()
 {
+    SharedBufferStack& stack( *mSharedStack );
+
+    if (stack.head == tail && stack.available == 2) {
+        LOGW("dequeue: tail=%d, head=%d, avail=%d, queued=%d",
+                tail, stack.head, stack.available, stack.queued);
+    }
+
     //LOGD("[%d] about to dequeue a buffer",
     //        mSharedStack->identity);
     DequeueCondition condition(this);
@@ -248,8 +277,6 @@
     if (err != NO_ERROR)
         return ssize_t(err);
 
-
-    SharedBufferStack& stack( *mSharedStack );
     // NOTE: 'stack.available' is part of the conditions, however
     // decrementing it, never changes any conditions, so we don't need
     // to do this as part of an update.
@@ -261,6 +288,7 @@
     tail = ((tail+1 >= mNumBuffers) ? 0 : tail+1);
     LOGD_IF(DEBUG_ATOMICS, "dequeued=%d, tail=%d, %s",
             dequeued, tail, dump("").string());
+
     return dequeued;
 }
 
@@ -302,9 +330,10 @@
 // ----------------------------------------------------------------------------
 
 SharedBufferServer::SharedBufferServer(SharedClient* sharedClient,
-        int surface, int num)
+        int surface, int num, int32_t identity)
     : SharedBufferBase(sharedClient, surface, num)
 {
+    mSharedStack->init(identity);
     mSharedStack->head = num-1;
     mSharedStack->available = num;
     mSharedStack->queued = 0;
@@ -316,7 +345,7 @@
 {
     RetireUpdate update(this, mNumBuffers);
     ssize_t buf = updateCondition( update );
-    LOGD_IF(DEBUG_ATOMICS, "retire=%d, %s", int(buf), dump("").string());
+    LOGD_IF(DEBUG_ATOMICS && buf>=0, "retire=%d, %s", int(buf), dump("").string());
     return buf;
 }
 
@@ -327,6 +356,12 @@
     return err;
 }
 
+void SharedBufferServer::setStatus(status_t status)
+{
+    StatusUpdate update(this, status);
+    updateCondition( update );
+}
+
 status_t SharedBufferServer::reallocate()
 {
     SharedBufferStack& stack( *mSharedStack );
diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp
index 6be372c..ec3db09 100644
--- a/libs/utils/Threads.cpp
+++ b/libs/utils/Threads.cpp
@@ -655,6 +655,11 @@
     wp<Thread> weak(strong);
     self->mHoldSelf.clear();
 
+#if HAVE_ANDROID_OS
+    // this is very useful for debugging with gdb
+    self->mTid = gettid();
+#endif
+
     bool first = true;
 
     do {
@@ -685,7 +690,7 @@
             self->mExitPending = true;
             self->mLock.lock();
             self->mRunning = false;
-            self->mThreadExitedCondition.signal();
+            self->mThreadExitedCondition.broadcast();
             self->mLock.unlock();
             break;
         }
@@ -693,7 +698,7 @@
         // Release our strong reference, to let a chance to the thread
         // to die a peaceful death.
         strong.clear();
-        // And immediately, reacquire a strong reference for the next loop
+        // And immediately, re-acquire a strong reference for the next loop
         strong = weak.promote();
     } while(strong != 0);
     
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 754d5a2..307cf22 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -25,7 +25,6 @@
 import android.bluetooth.BluetoothA2dp;
 import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothIntent;
 import android.bluetooth.BluetoothHeadset;
 
 import android.content.pm.PackageManager;
@@ -265,8 +264,8 @@
         // Register for device connection intent broadcasts.
         IntentFilter intentFilter =
                 new IntentFilter(Intent.ACTION_HEADSET_PLUG);
-        intentFilter.addAction(BluetoothA2dp.SINK_STATE_CHANGED_ACTION);
-        intentFilter.addAction(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION);
+        intentFilter.addAction(BluetoothA2dp.ACTION_SINK_STATE_CHANGED);
+        intentFilter.addAction(BluetoothHeadset.ACTION_STATE_CHANGED);
         context.registerReceiver(mReceiver, intentFilter);
 
     }
@@ -758,6 +757,9 @@
 
     /** @see AudioManager#setSpeakerphoneOn() */
     public void setSpeakerphoneOn(boolean on){
+        if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
+            return;
+        }
         if (on) {
             AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_SPEAKER);
             mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
@@ -778,6 +780,9 @@
 
     /** @see AudioManager#setBluetoothScoOn() */
     public void setBluetoothScoOn(boolean on){
+        if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
+            return;
+        }
         if (on) {
             AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_BT_SCO);
             AudioSystem.setForceUse(AudioSystem.FOR_RECORD, AudioSystem.FORCE_BT_SCO);
@@ -1366,10 +1371,10 @@
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
 
-            if (action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) {
-                int state = intent.getIntExtra(BluetoothA2dp.SINK_STATE,
+            if (action.equals(BluetoothA2dp.ACTION_SINK_STATE_CHANGED)) {
+                int state = intent.getIntExtra(BluetoothA2dp.EXTRA_SINK_STATE,
                                                BluetoothA2dp.STATE_DISCONNECTED);
-                BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothIntent.DEVICE);
+                BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                 String address = btDevice.getAddress();
                 boolean isConnected = (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) &&
                                        ((String)mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)).equals(address));
@@ -1389,19 +1394,17 @@
                     mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP),
                             address);
                 }
-            } else if (action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION)) {
-                int state = intent.getIntExtra(BluetoothIntent.HEADSET_STATE,
+            } else if (action.equals(BluetoothHeadset.ACTION_STATE_CHANGED)) {
+                int state = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE,
                                                BluetoothHeadset.STATE_ERROR);
                 int device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
-                BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothIntent.DEVICE);
+                BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                 String address = null;
-                int btClass = BluetoothClass.ERROR;
                 if (btDevice != null) {
                     address = btDevice.getAddress();
-                    btClass = btDevice.getBluetoothClass();
-                    if (BluetoothClass.Device.Major.getDeviceMajor(btClass) ==
-                                BluetoothClass.Device.Major.AUDIO_VIDEO) {
-                        switch (BluetoothClass.Device.getDevice(btClass)) {
+                    BluetoothClass btClass = btDevice.getBluetoothClass();
+                    if (btClass != null) {
+                        switch (btClass.getDeviceClass()) {
                         case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
                         case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
                             device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
@@ -1409,8 +1412,6 @@
                         case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
                             device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
                             break;
-                        default:
-                            break;
                         }
                     }
                 }
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index fcc76ca5..f6d30e0 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -493,6 +493,22 @@
             doScanFile(path, mimeType, lastModified, fileSize, false);
         }
 
+        private boolean isMetadataSupported(int fileType) {
+            if (mFileType == MediaFile.FILE_TYPE_MP3 ||
+                    mFileType == MediaFile.FILE_TYPE_MP4 ||
+                    mFileType == MediaFile.FILE_TYPE_M4A ||
+                    mFileType == MediaFile.FILE_TYPE_3GPP ||
+                    mFileType == MediaFile.FILE_TYPE_3GPP2 ||
+                    mFileType == MediaFile.FILE_TYPE_OGG ||
+                    mFileType == MediaFile.FILE_TYPE_AAC ||
+                    mFileType == MediaFile.FILE_TYPE_MID ||
+                    mFileType == MediaFile.FILE_TYPE_WMA) {
+                // we only extract metadata from MP3, M4A, OGG, MID, AAC and WMA files.
+                // check MP4 files, to determine if they contain only audio.
+                return true;
+            }
+            return false;
+        }
         public Uri doScanFile(String path, String mimeType, long lastModified, long fileSize, boolean scanAlways) {
             Uri result = null;
 //            long t1 = System.currentTimeMillis();
@@ -508,16 +524,7 @@
                     boolean music = (lowpath.indexOf(MUSIC_DIR) > 0) ||
                         (!ringtones && !notifications && !alarms && !podcasts);
 
-                    if (mFileType == MediaFile.FILE_TYPE_MP3 ||
-                            mFileType == MediaFile.FILE_TYPE_MP4 ||
-                            mFileType == MediaFile.FILE_TYPE_M4A ||
-                            mFileType == MediaFile.FILE_TYPE_3GPP ||
-                            mFileType == MediaFile.FILE_TYPE_3GPP2 ||
-                            mFileType == MediaFile.FILE_TYPE_OGG ||
-                            mFileType == MediaFile.FILE_TYPE_MID ||
-                            mFileType == MediaFile.FILE_TYPE_WMA) {
-                        // we only extract metadata from MP3, M4A, OGG, MID and WMA files.
-                        // check MP4 files, to determine if they contain only audio.
+                    if( isMetadataSupported(mFileType) ) {
                         processFile(path, mimeType, this);
                     } else if (MediaFile.isImageFileType(mFileType)) {
                         // we used to compute the width and height but it's not worth it
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index 59ecde6..93b7a3a 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -10,13 +10,21 @@
     MediaRecorderClient.cpp     \
     MediaPlayerService.cpp      \
     MetadataRetrieverClient.cpp \
-    StagefrightPlayer.cpp       \
     TestPlayerStub.cpp          \
     VorbisPlayer.cpp            \
     VorbisMetadataRetriever.cpp \
     MidiMetadataRetriever.cpp \
     MidiFile.cpp
 
+ifeq ($(BUILD_WITH_FULL_STAGEFRIGHT),true)
+
+LOCAL_SRC_FILES +=              \
+    StagefrightPlayer.cpp
+
+LOCAL_CFLAGS += -DBUILD_WITH_FULL_STAGEFRIGHT=1
+
+endif
+
 ifeq ($(TARGET_OS)-$(TARGET_SIMULATOR),linux-true)
 LOCAL_LDLIBS += -ldl -lpthread
 endif
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 8998f10..8b1c9dc 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -602,11 +602,13 @@
 }
 
 static player_type getDefaultPlayerType() {
+#if BUILD_WITH_FULL_STAGEFRIGHT
     char value[PROPERTY_VALUE_MAX];
     if (property_get("media.stagefright.enable-player", value, NULL)
         && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
         return STAGEFRIGHT_PLAYER;
     }
+#endif
 
     return PV_PLAYER;
 }
@@ -684,10 +686,12 @@
             LOGV(" create VorbisPlayer");
             p = new VorbisPlayer();
             break;
+#if BUILD_WITH_FULL_STAGEFRIGHT
         case STAGEFRIGHT_PLAYER:
             LOGV(" create StagefrightPlayer");
             p = new StagefrightPlayer;
             break;
+#endif
         case TEST_PLAYER:
             LOGV("Create Test Player stub");
             p = new TestPlayerStub();
diff --git a/media/libstagefright/AMRExtractor.cpp b/media/libstagefright/AMRExtractor.cpp
new file mode 100644
index 0000000..8d85ce2
--- /dev/null
+++ b/media/libstagefright/AMRExtractor.cpp
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "AMRExtractor"
+#include <utils/Log.h>
+
+#include <media/stagefright/AMRExtractor.h>
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaBufferGroup.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <utils/String8.h>
+
+namespace android {
+
+class AMRSource : public MediaSource {
+public:
+    AMRSource(const sp<DataSource> &source, bool isWide);
+
+    virtual status_t start(MetaData *params = NULL);
+    virtual status_t stop();
+
+    virtual sp<MetaData> getFormat();
+
+    virtual status_t read(
+            MediaBuffer **buffer, const ReadOptions *options = NULL);
+
+protected:
+    virtual ~AMRSource();
+
+private:
+    sp<DataSource> mDataSource;
+    bool mIsWide;
+
+    off_t mOffset;
+    int64_t mCurrentTimeUs;
+    bool mStarted;
+    MediaBufferGroup *mGroup;
+
+    AMRSource(const AMRSource &);
+    AMRSource &operator=(const AMRSource &);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+AMRExtractor::AMRExtractor(const sp<DataSource> &source)
+    : mDataSource(source),
+      mInitCheck(NO_INIT) {
+    String8 mimeType;
+    float confidence;
+    if (SniffAMR(mDataSource, &mimeType, &confidence)) {
+        mInitCheck = OK;
+        mIsWide = (mimeType == MEDIA_MIMETYPE_AUDIO_AMR_WB);
+    }
+}
+
+AMRExtractor::~AMRExtractor() {
+}
+
+size_t AMRExtractor::countTracks() {
+    return mInitCheck == OK ? 1 : 0;
+}
+
+sp<MediaSource> AMRExtractor::getTrack(size_t index) {
+    if (mInitCheck != OK || index != 0) {
+        return NULL;
+    }
+
+    return new AMRSource(mDataSource, mIsWide);
+}
+
+sp<MetaData> AMRExtractor::getTrackMetaData(size_t index) {
+    if (mInitCheck != OK || index != 0) {
+        return NULL;
+    }
+
+    return makeAMRFormat(mIsWide);
+}
+
+// static
+sp<MetaData> AMRExtractor::makeAMRFormat(bool isWide) {
+    sp<MetaData> meta = new MetaData;
+    meta->setCString(
+            kKeyMIMEType, isWide ? MEDIA_MIMETYPE_AUDIO_AMR_WB
+                                 : MEDIA_MIMETYPE_AUDIO_AMR_NB);
+
+    meta->setInt32(kKeyChannelCount, 1);
+    meta->setInt32(kKeySampleRate, isWide ? 16000 : 8000);
+
+    return meta;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+AMRSource::AMRSource(const sp<DataSource> &source, bool isWide)
+    : mDataSource(source),
+      mIsWide(isWide),
+      mOffset(mIsWide ? 9 : 6),
+      mCurrentTimeUs(0),
+      mStarted(false),
+      mGroup(NULL) {
+}
+
+AMRSource::~AMRSource() {
+    if (mStarted) {
+        stop();
+    }
+}
+
+status_t AMRSource::start(MetaData *params) {
+    CHECK(!mStarted);
+
+    mOffset = mIsWide ? 9 : 6;
+    mCurrentTimeUs = 0;
+    mGroup = new MediaBufferGroup;
+    mGroup->add_buffer(new MediaBuffer(128));
+    mStarted = true;
+
+    return OK;
+}
+
+status_t AMRSource::stop() {
+    CHECK(mStarted);
+
+    delete mGroup;
+    mGroup = NULL;
+
+    mStarted = false;
+    return OK;
+}
+
+sp<MetaData> AMRSource::getFormat() {
+    return AMRExtractor::makeAMRFormat(mIsWide);
+}
+
+status_t AMRSource::read(
+        MediaBuffer **out, const ReadOptions *options) {
+    *out = NULL;
+
+    uint8_t header;
+    ssize_t n = mDataSource->read_at(mOffset, &header, 1);
+
+    if (n < 1) {
+        return ERROR_IO;
+    }
+
+    MediaBuffer *buffer;
+    status_t err = mGroup->acquire_buffer(&buffer);
+    if (err != OK) {
+        return err;
+    }
+
+    if (header & 0x83) {
+        // Padding bits must be 0.
+
+        return ERROR_MALFORMED;
+    }
+
+    unsigned FT = (header >> 3) & 0x0f;
+
+    if (FT > 8 || (!mIsWide && FT > 7)) {
+        return ERROR_MALFORMED;
+    }
+
+    static const size_t kFrameSizeNB[8] = {
+        95, 103, 118, 134, 148, 159, 204, 244
+    };
+    static const size_t kFrameSizeWB[9] = {
+        132, 177, 253, 285, 317, 365, 397, 461, 477
+    };
+
+    size_t frameSize = mIsWide ? kFrameSizeWB[FT] : kFrameSizeNB[FT];
+
+    // Round up bits to bytes and add 1 for the header byte.
+    frameSize = (frameSize + 7) / 8 + 1;
+
+    n = mDataSource->read_at(mOffset, buffer->data(), frameSize);
+
+    if (n != (ssize_t)frameSize) {
+        buffer->release();
+        buffer = NULL;
+
+        return ERROR_IO;
+    }
+
+    buffer->set_range(0, frameSize);
+    buffer->meta_data()->setInt32(
+            kKeyTimeUnits, (mCurrentTimeUs + 500) / 1000);
+    buffer->meta_data()->setInt32(
+            kKeyTimeScale, 1000);
+
+    mOffset += frameSize;
+    mCurrentTimeUs += 20000;  // Each frame is 20ms
+
+    *out = buffer;
+
+    return OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+bool SniffAMR(
+        const sp<DataSource> &source, String8 *mimeType, float *confidence) {
+    char header[9];
+
+    if (source->read_at(0, header, sizeof(header)) != sizeof(header)) {
+        return false;
+    }
+
+    if (!memcmp(header, "#!AMR\n", 6)) {
+        *mimeType = MEDIA_MIMETYPE_AUDIO_AMR_NB;
+        *confidence = 0.5;
+
+        return true;
+    } else if (!memcmp(header, "#!AMR-WB\n", 9)) {
+        *mimeType = MEDIA_MIMETYPE_AUDIO_AMR_WB;
+        *confidence = 0.5;
+
+        return true;
+    }
+
+    return false;
+}
+
+}  // namespace android
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 20b0da2..79a32b5 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -2,32 +2,41 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:=                 \
+        ESDS.cpp                  \
+        MediaBuffer.cpp           \
+        MediaBufferGroup.cpp      \
+        MediaDefs.cpp             \
+        MediaSource.cpp           \
+        MetaData.cpp              \
+        OMXCodec.cpp              \
+        Utils.cpp                 \
+        OMXClient.cpp
+
+ifeq ($(BUILD_WITH_FULL_STAGEFRIGHT),true)
+
+LOCAL_SRC_FILES +=                \
+        AMRExtractor.cpp          \
         CachingDataSource.cpp     \
         DataSource.cpp            \
         FileSource.cpp            \
         HTTPDataSource.cpp        \
         HTTPStream.cpp            \
+        JPEGSource.cpp            \
+        MediaExtractor.cpp        \
         MP3Extractor.cpp          \
         MPEG4Extractor.cpp        \
         MPEG4Writer.cpp           \
-        MediaBuffer.cpp           \
-        MediaBufferGroup.cpp      \
-        MediaExtractor.cpp        \
         MediaPlayerImpl.cpp       \
-        MediaSource.cpp           \
-        MetaData.cpp              \
         MmapSource.cpp            \
-        OMXCodec.cpp              \
         SampleTable.cpp           \
         ShoutcastSource.cpp       \
         TimeSource.cpp            \
         TimedEventQueue.cpp       \
-        Utils.cpp                 \
         AudioPlayer.cpp           \
-        ESDS.cpp                  \
-        OMXClient.cpp             \
         string.cpp
 
+endif
+
 LOCAL_C_INCLUDES:= \
         $(TOP)/external/opencore/extern_libs_v2/khronos/openmax/include \
         $(TOP)/external/opencore/android
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index 140bc68..319488e 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -20,6 +20,7 @@
 #include <media/AudioTrack.h>
 #include <media/stagefright/AudioPlayer.h>
 #include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 
@@ -61,7 +62,7 @@
     const char *mime;
     bool success = format->findCString(kKeyMIMEType, &mime);
     CHECK(success);
-    CHECK(!strcasecmp(mime, "audio/raw"));
+    CHECK(!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW));
 
     success = format->findInt32(kKeySampleRate, &mSampleRate);
     CHECK(success);
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index f75b173..596ab67 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -155,7 +155,7 @@
 
 sp<MetaData> CameraSource::getFormat() {
     sp<MetaData> meta = new MetaData;
-    meta->setCString(kKeyMIMEType, "video/raw");
+    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
     meta->setInt32(kKeyColorFormat, OMX_COLOR_FormatYUV420SemiPlanar);
     meta->setInt32(kKeyWidth, 480);
     meta->setInt32(kKeyHeight, 320);
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index 02a276b..daac539 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <media/stagefright/AMRExtractor.h>
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MP3Extractor.h>
@@ -84,6 +85,7 @@
 void DataSource::RegisterDefaultSniffers() {
     RegisterSniffer(SniffMP3);
     RegisterSniffer(SniffMPEG4);
+    RegisterSniffer(SniffAMR);
 }
 
 }  // namespace android
diff --git a/cmds/stagefright/JPEGSource.cpp b/media/libstagefright/JPEGSource.cpp
similarity index 97%
rename from cmds/stagefright/JPEGSource.cpp
rename to media/libstagefright/JPEGSource.cpp
index 4e9ca4e..d1dfd83 100644
--- a/cmds/stagefright/JPEGSource.cpp
+++ b/media/libstagefright/JPEGSource.cpp
@@ -18,11 +18,11 @@
 #define LOG_TAG "JPEGSource"
 #include <utils/Log.h>
 
-#include "JPEGSource.h"
-
 #include <media/stagefright/DataSource.h>
+#include <media/stagefright/JPEGSource.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
 
@@ -99,7 +99,7 @@
 
 sp<MetaData> JPEGSource::getFormat() {
     sp<MetaData> meta = new MetaData;
-    meta->setCString(kKeyMIMEType, "image/jpeg");
+    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_IMAGE_JPEG);
     meta->setInt32(kKeyWidth, mWidth);
     meta->setInt32(kKeyHeight, mHeight);
     meta->setInt32(kKeyMaxInputSize, mSize);
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp
index 14f3e0c..7fd699f 100644
--- a/media/libstagefright/MP3Extractor.cpp
+++ b/media/libstagefright/MP3Extractor.cpp
@@ -23,6 +23,7 @@
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
@@ -330,7 +331,7 @@
 
         mMeta = new MetaData;
 
-        mMeta->setCString(kKeyMIMEType, "audio/mpeg");
+        mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
         mMeta->setInt32(kKeySampleRate, sample_rate);
         mMeta->setInt32(kKeyBitRate, bitrate);
         mMeta->setInt32(kKeyChannelCount, num_channels);
@@ -510,7 +511,7 @@
         return false;
     }
 
-    *mimeType = "audio/mpeg";
+    *mimeType = MEDIA_MIMETYPE_AUDIO_MPEG;
     *confidence = 0.3f;
 
     return true;
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 894d46c..9174d19 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -29,6 +29,7 @@
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaSource.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/SampleTable.h>
@@ -116,22 +117,25 @@
     }
 }
 
-static const char *const FourCC2MIME(uint32_t fourcc) {
+static const char *FourCC2MIME(uint32_t fourcc) {
     switch (fourcc) {
         case FOURCC('m', 'p', '4', 'a'):
-            return "audio/mp4a-latm";
+            return MEDIA_MIMETYPE_AUDIO_AAC;
 
         case FOURCC('s', 'a', 'm', 'r'):
-            return "audio/3gpp";
+            return MEDIA_MIMETYPE_AUDIO_AMR_NB;
+
+        case FOURCC('s', 'a', 'w', 'b'):
+            return MEDIA_MIMETYPE_AUDIO_AMR_WB;
 
         case FOURCC('m', 'p', '4', 'v'):
-            return "video/mp4v-es";
+            return MEDIA_MIMETYPE_VIDEO_MPEG4;
 
         case FOURCC('s', '2', '6', '3'):
-            return "video/3gpp";
+            return MEDIA_MIMETYPE_VIDEO_H263;
 
         case FOURCC('a', 'v', 'c', '1'):
-            return "video/avc";
+            return MEDIA_MIMETYPE_VIDEO_AVC;
 
         default:
             CHECK(!"should not be here.");
@@ -189,6 +193,10 @@
         --index;
     }
 
+    if (track == NULL) {
+        return NULL;
+    }
+
     return track->meta;
 }
 
@@ -472,6 +480,7 @@
 
         case FOURCC('m', 'p', '4', 'a'):
         case FOURCC('s', 'a', 'm', 'r'):
+        case FOURCC('s', 'a', 'w', 'b'):
         {
             if (mHandlerType != FOURCC('s', 'o', 'u', 'n')) {
                 return ERROR_MALFORMED;
@@ -491,7 +500,10 @@
             uint16_t data_ref_index = U16_AT(&buffer[6]);
             uint16_t num_channels = U16_AT(&buffer[16]);
 
-            if (!strcasecmp("audio/3gpp", FourCC2MIME(chunk_type))) {
+            if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB,
+                            FourCC2MIME(chunk_type))
+                || !strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB,
+                               FourCC2MIME(chunk_type))) {
                 // AMR audio is always mono.
                 num_channels = 1;
             }
@@ -705,6 +717,10 @@
         --index;
     }
 
+    if (track == NULL) {
+        return NULL;
+    }
+
     return new MPEG4Source(
             track->meta, mDataSource, track->sampleTable);
 }
@@ -733,7 +749,7 @@
     success = mFormat->findInt32(kKeyTimeScale, &mTimescale);
     CHECK(success);
 
-    mIsAVC = !strcasecmp(mime, "video/avc");
+    mIsAVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
 }
 
 MPEG4Source::~MPEG4Source() {
@@ -965,7 +981,7 @@
 
     if (!memcmp(header, "ftyp3gp", 7) || !memcmp(header, "ftypmp42", 8)
         || !memcmp(header, "ftypisom", 8) || !memcmp(header, "ftypM4V ", 8)) {
-        *mimeType = "video/mp4";
+        *mimeType = MEDIA_MIMETYPE_CONTAINER_MPEG4;
         *confidence = 0.1;
 
         return true;
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 90b1b9a..fa35768 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -23,6 +23,7 @@
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaSource.h>
 #include <media/stagefright/Utils.h>
 
@@ -30,12 +31,12 @@
 
 class MPEG4Writer::Track {
 public:
-    Track(MPEG4Writer *owner,
-          const sp<MetaData> &meta, const sp<MediaSource> &source);
+    Track(MPEG4Writer *owner, const sp<MediaSource> &source);
     ~Track();
 
-    void start();
+    status_t start();
     void stop();
+    bool reachedEOS();
 
     int64_t getDuration() const;
     void writeTrackHeader(int32_t trackID);
@@ -58,6 +59,8 @@
     void *mCodecSpecificData;
     size_t mCodecSpecificDataSize;
 
+    bool mReachedEOS;
+
     static void *ThreadWrapper(void *me);
     void threadEntry();
 
@@ -82,15 +85,14 @@
     mTracks.clear();
 }
 
-void MPEG4Writer::addSource(
-        const sp<MetaData> &meta, const sp<MediaSource> &source) {
-    Track *track = new Track(this, meta, source);
+void MPEG4Writer::addSource(const sp<MediaSource> &source) {
+    Track *track = new Track(this, source);
     mTracks.push_back(track);
 }
 
-void MPEG4Writer::start() {
+status_t MPEG4Writer::start() {
     if (mFile == NULL) {
-        return;
+        return UNKNOWN_ERROR;
     }
 
     beginBox("ftyp");
@@ -104,8 +106,19 @@
 
     for (List<Track *>::iterator it = mTracks.begin();
          it != mTracks.end(); ++it) {
-        (*it)->start();
+        status_t err = (*it)->start();
+
+        if (err != OK) {
+            for (List<Track *>::iterator it2 = mTracks.begin();
+                 it2 != it; ++it2) {
+                (*it2)->stop();
+            }
+
+            return err;
+        }
     }
+
+    return OK;
 }
 
 void MPEG4Writer::stop() {
@@ -252,17 +265,30 @@
     mOffset += size;
 }
 
+bool MPEG4Writer::reachedEOS() {
+    bool allDone = true;
+    for (List<Track *>::iterator it = mTracks.begin();
+         it != mTracks.end(); ++it) {
+        if (!(*it)->reachedEOS()) {
+            allDone = false;
+            break;
+        }
+    }
+
+    return allDone;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 MPEG4Writer::Track::Track(
-        MPEG4Writer *owner,
-        const sp<MetaData> &meta, const sp<MediaSource> &source)
+        MPEG4Writer *owner, const sp<MediaSource> &source)
     : mOwner(owner),
-      mMeta(meta),
+      mMeta(source->getFormat()),
       mSource(source),
       mDone(false),
       mCodecSpecificData(NULL),
-      mCodecSpecificDataSize(0) {
+      mCodecSpecificDataSize(0),
+      mReachedEOS(false) {
 }
 
 MPEG4Writer::Track::~Track() {
@@ -274,19 +300,25 @@
     }
 }
 
-void MPEG4Writer::Track::start() {
-    mSource->start();
+status_t MPEG4Writer::Track::start() {
+    status_t err = mSource->start();
+
+    if (err != OK) {
+        mDone = mReachedEOS = true;
+        return err;
+    }
 
     pthread_attr_t attr;
     pthread_attr_init(&attr);
     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
 
     mDone = false;
+    mReachedEOS = false;
 
-    int err = pthread_create(&mThread, &attr, ThreadWrapper, this);
-    CHECK_EQ(err, 0);
-
+    pthread_create(&mThread, &attr, ThreadWrapper, this);
     pthread_attr_destroy(&attr);
+
+    return OK;
 }
 
 void MPEG4Writer::Track::stop() {
@@ -302,6 +334,10 @@
     mSource->stop();
 }
 
+bool MPEG4Writer::Track::reachedEOS() {
+    return mReachedEOS;
+}
+
 // static
 void *MPEG4Writer::Track::ThreadWrapper(void *me) {
     Track *track = static_cast<Track *>(me);
@@ -316,7 +352,7 @@
     sp<MetaData> meta = mSource->getFormat();
     const char *mime;
     meta->findCString(kKeyMIMEType, &mime);
-    is_mpeg4 = !strcasecmp(mime, "video/mp4v-es");
+    is_mpeg4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4);
 
     MediaBuffer *buffer;
     while (!mDone && mSource->read(&buffer) == OK) {
@@ -378,6 +414,8 @@
         buffer->release();
         buffer = NULL;
     }
+
+    mReachedEOS = true;
 }
 
 int64_t MPEG4Writer::Track::getDuration() const {
@@ -490,7 +528,17 @@
             mOwner->writeInt32(0);               // version=0, flags=0
             mOwner->writeInt32(1);               // entry count
             if (is_audio) {
-                mOwner->beginBox("xxxx");          // audio format XXX
+                const char *fourcc = NULL;
+                if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) {
+                    fourcc = "samr";
+                } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
+                    fourcc = "sawb";
+                } else {
+                    LOGE("Unknown mime type '%s'.", mime);
+                    CHECK(!"should not be here, unknown mime type.");
+                }
+
+                mOwner->beginBox(fourcc);          // audio format
                   mOwner->writeInt32(0);           // reserved
                   mOwner->writeInt16(0);           // reserved
                   mOwner->writeInt16(0);           // data ref index
@@ -508,11 +556,12 @@
                   mOwner->writeInt32(samplerate << 16);
                 mOwner->endBox();
             } else {
-                if (!strcasecmp("video/mp4v-es", mime)) {
+                if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
                     mOwner->beginBox("mp4v");
-                } else if (!strcasecmp("video/3gpp", mime)) {
+                } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
                     mOwner->beginBox("s263");
                 } else {
+                    LOGE("Unknown mime type '%s'.", mime);
                     CHECK(!"should not be here, unknown mime type.");
                 }
 
@@ -542,7 +591,7 @@
 
                   CHECK(23 + mCodecSpecificDataSize < 128);
 
-                  if (!strcasecmp("video/mp4v-es", mime)) {
+                  if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
                       mOwner->beginBox("esds");
 
                         mOwner->writeInt32(0);           // version=0, flags=0
@@ -577,7 +626,7 @@
                         mOwner->write(kData2, sizeof(kData2));
 
                       mOwner->endBox();  // esds
-                  } else if (!strcasecmp("video/3gpp", mime)) {
+                  } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
                       mOwner->beginBox("d263");
 
                           mOwner->writeInt32(0);  // vendor
diff --git a/media/libstagefright/MediaDefs.cpp b/media/libstagefright/MediaDefs.cpp
new file mode 100644
index 0000000..87b5b24
--- /dev/null
+++ b/media/libstagefright/MediaDefs.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <media/stagefright/MediaDefs.h>
+
+namespace android {
+
+const char *MEDIA_MIMETYPE_IMAGE_JPEG = "image/jpeg";
+
+const char *MEDIA_MIMETYPE_VIDEO_AVC = "video/avc";
+const char *MEDIA_MIMETYPE_VIDEO_MPEG4 = "video/mp4v-es";
+const char *MEDIA_MIMETYPE_VIDEO_H263 = "video/3gpp";
+const char *MEDIA_MIMETYPE_VIDEO_RAW = "video/raw";
+
+const char *MEDIA_MIMETYPE_AUDIO_AMR_NB = "audio/3gpp";
+const char *MEDIA_MIMETYPE_AUDIO_AMR_WB = "audio/amr-wb";
+const char *MEDIA_MIMETYPE_AUDIO_MPEG = "audio/mpeg";
+const char *MEDIA_MIMETYPE_AUDIO_AAC = "audio/mp4a-latm";
+const char *MEDIA_MIMETYPE_AUDIO_RAW = "audio/raw";
+
+const char *MEDIA_MIMETYPE_CONTAINER_MPEG4 = "video/mpeg4";
+
+}  // namespace android
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index 5f78e12..8535f52 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -18,7 +18,9 @@
 #define LOG_TAG "MediaExtractor"
 #include <utils/Log.h>
 
+#include <media/stagefright/AMRExtractor.h>
 #include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MP3Extractor.h>
 #include <media/stagefright/MPEG4Extractor.h>
 #include <media/stagefright/MediaExtractor.h>
@@ -43,10 +45,14 @@
              mime, confidence);
     }
 
-    if (!strcasecmp(mime, "video/mp4") || !strcasecmp(mime, "audio/mp4")) {
+    if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4)
+            || !strcasecmp(mime, "audio/mp4")) {
         return new MPEG4Extractor(source);
-    } else if (!strcasecmp(mime, "audio/mpeg")) {
+    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
         return new MP3Extractor(source);
+    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)
+            || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) {
+        return new AMRExtractor(source);
     }
 
     return NULL;
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index d01d6af..a964d17 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -26,6 +26,7 @@
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaExtractor.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/MmapSource.h>
@@ -44,39 +45,43 @@
 };
 
 static const CodecInfo kDecoderInfo[] = {
-    { "image/jpeg", "OMX.TI.JPEG.decode" },
-    { "audio/mpeg", "OMX.TI.MP3.decode" },
-    { "audio/mpeg", "OMX.PV.mp3dec" },
-    { "audio/3gpp", "OMX.TI.AMR.decode" },
-    { "audio/3gpp", "OMX.PV.amrdec" },
-    { "audio/mp4a-latm", "OMX.TI.AAC.decode" },
-    { "audio/mp4a-latm", "OMX.PV.aacdec" },
-    { "video/mp4v-es", "OMX.qcom.video.decoder.mpeg4" },
-    { "video/mp4v-es", "OMX.TI.Video.Decoder" },
-    { "video/mp4v-es", "OMX.PV.mpeg4dec" },
-    { "video/3gpp", "OMX.qcom.video.decoder.h263" },
-    { "video/3gpp", "OMX.TI.Video.Decoder" },
-    { "video/3gpp", "OMX.PV.h263dec" },
-    { "video/avc", "OMX.qcom.video.decoder.avc" },
-    { "video/avc", "OMX.TI.Video.Decoder" },
-    { "video/avc", "OMX.PV.avcdec" },
+    { MEDIA_MIMETYPE_IMAGE_JPEG, "OMX.TI.JPEG.decode" },
+    { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.TI.MP3.decode" },
+    { MEDIA_MIMETYPE_AUDIO_MPEG, "OMX.PV.mp3dec" },
+    { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.TI.AMR.decode" },
+    { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.PV.amrdec" },
+    { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.TI.WBAMR.decode" },
+    { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.PV.amrdec" },
+    { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.TI.AAC.decode" },
+    { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.PV.aacdec" },
+    { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.video.decoder.mpeg4" },
+    { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.Video.Decoder" },
+    { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.PV.mpeg4dec" },
+    { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.video.decoder.h263" },
+    { MEDIA_MIMETYPE_VIDEO_H263, "OMX.TI.Video.Decoder" },
+    { MEDIA_MIMETYPE_VIDEO_H263, "OMX.PV.h263dec" },
+    { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.qcom.video.decoder.avc" },
+    { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.Video.Decoder" },
+    { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.PV.avcdec" },
 };
 
 static const CodecInfo kEncoderInfo[] = {
-    { "audio/3gpp", "OMX.TI.AMR.encode" },
-    { "audio/3gpp", "OMX.PV.amrencnb" },
-    { "audio/mp4a-latm", "OMX.TI.AAC.encode" },
-    { "audio/mp4a-latm", "OMX.PV.aacenc" },
-    { "video/mp4v-es", "OMX.qcom.video.encoder.mpeg4" },
-    { "video/mp4v-es", "OMX.TI.Video.encoder" },
-    { "video/mp4v-es", "OMX.PV.mpeg4enc" },
-    { "video/3gpp", "OMX.qcom.video.encoder.h263" },
-    { "video/3gpp", "OMX.TI.Video.encoder" },
-    { "video/3gpp", "OMX.PV.h263enc" },
-    { "video/avc", "OMX.TI.Video.encoder" },
-    { "video/avc", "OMX.PV.avcenc" },
+    { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.TI.AMR.encode" },
+    { MEDIA_MIMETYPE_AUDIO_AMR_NB, "OMX.PV.amrencnb" },
+    { MEDIA_MIMETYPE_AUDIO_AMR_WB, "OMX.TI.WBAMR.encode" },
+    { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.TI.AAC.encode" },
+    { MEDIA_MIMETYPE_AUDIO_AAC, "OMX.PV.aacenc" },
+    { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.qcom.video.encoder.mpeg4" },
+    { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.TI.Video.encoder" },
+    { MEDIA_MIMETYPE_VIDEO_MPEG4, "OMX.PV.mpeg4enc" },
+    { MEDIA_MIMETYPE_VIDEO_H263, "OMX.qcom.video.encoder.h263" },
+    { MEDIA_MIMETYPE_VIDEO_H263, "OMX.TI.Video.encoder" },
+    { MEDIA_MIMETYPE_VIDEO_H263, "OMX.PV.h263enc" },
+    { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.TI.Video.encoder" },
+    { MEDIA_MIMETYPE_VIDEO_AVC, "OMX.PV.avcenc" },
 };
 
+#define CODEC_LOGI(x, ...) LOGI("[%s] "x, mComponentName, ##__VA_ARGS__)
 #define CODEC_LOGV(x, ...) LOGV("[%s] "x, mComponentName, ##__VA_ARGS__)
 
 struct OMXCodecObserver : public BnOMXObserver {
@@ -165,7 +170,8 @@
 sp<OMXCodec> OMXCodec::Create(
         const sp<IOMX> &omx,
         const sp<MetaData> &meta, bool createEncoder,
-        const sp<MediaSource> &source) {
+        const sp<MediaSource> &source,
+        const char *matchComponentName) {
     const char *mime;
     bool success = meta->findCString(kKeyMIMEType, &mime);
     CHECK(success);
@@ -187,6 +193,11 @@
             return NULL;
         }
 
+        // If a specific codec is requested, skip the non-matching ones.
+        if (matchComponentName && strcmp(componentName, matchComponentName)) {
+            continue;
+        }
+
         LOGV("Attempting to allocate OMX node '%s'", componentName);
 
         status_t err = omx->allocate_node(componentName, &node);
@@ -314,10 +325,13 @@
         }
     }
 
-    if (!strcasecmp("audio/3gpp", mime)) {
+    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) {
         codec->setAMRFormat();
     }
-    if (!strcasecmp("audio/mp4a-latm", mime)) {
+    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
+        codec->setAMRWBFormat();
+    }
+    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
         int32_t numChannels, sampleRate;
         CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
         CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
@@ -336,7 +350,7 @@
             codec->setVideoOutputFormat(mime, width, height);
         }
     }
-    if (!strcasecmp(mime, "image/jpeg")
+    if (!strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_JPEG)
         && !strcmp(componentName, "OMX.TI.JPEG.decode")) {
         OMX_COLOR_FORMATTYPE format =
             OMX_COLOR_Format32bitARGB8888;
@@ -418,7 +432,7 @@
         // CHECK_EQ(format.nIndex, index);
 
 #if 1
-        LOGI("portIndex: %ld, index: %ld, eCompressionFormat=%d eColorFormat=%d",
+        CODEC_LOGI("portIndex: %ld, index: %ld, eCompressionFormat=%d eColorFormat=%d",
              portIndex,
              index, format.eCompressionFormat, format.eColorFormat);
 #endif
@@ -451,7 +465,7 @@
         return UNKNOWN_ERROR;
     }
 
-    LOGI("found a match.");
+    CODEC_LOGI("found a match.");
     status_t err = mOMX->set_parameter(
             mNode, OMX_IndexParamVideoPortFormat,
             &format, sizeof(format));
@@ -461,14 +475,14 @@
 
 void OMXCodec::setVideoInputFormat(
         const char *mime, OMX_U32 width, OMX_U32 height) {
-    LOGI("setVideoInputFormat width=%ld, height=%ld", width, height);
+    CODEC_LOGI("setVideoInputFormat width=%ld, height=%ld", width, height);
 
     OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
-    if (!strcasecmp("video/avc", mime)) {
+    if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
         compressionFormat = OMX_VIDEO_CodingAVC;
-    } else if (!strcasecmp("video/mp4v-es", mime)) {
+    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
         compressionFormat = OMX_VIDEO_CodingMPEG4;
-    } else if (!strcasecmp("video/3gpp", mime)) {
+    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
         compressionFormat = OMX_VIDEO_CodingH263;
     } else {
         LOGE("Not a supported video mime type: %s", mime);
@@ -521,7 +535,7 @@
     CHECK_EQ(err, OK);
 
     def.nBufferSize = (width * height * 2); // (width * height * 3) / 2;
-    LOGI("Setting nBufferSize = %ld", def.nBufferSize);
+    CODEC_LOGI("Setting nBufferSize = %ld", def.nBufferSize);
 
     CHECK_EQ(def.eDomain, OMX_PortDomainVideo);
 
@@ -537,14 +551,14 @@
 
 void OMXCodec::setVideoOutputFormat(
         const char *mime, OMX_U32 width, OMX_U32 height) {
-    LOGI("setVideoOutputFormat width=%ld, height=%ld", width, height);
+    CODEC_LOGI("setVideoOutputFormat width=%ld, height=%ld", width, height);
 
     OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
-    if (!strcasecmp("video/avc", mime)) {
+    if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
         compressionFormat = OMX_VIDEO_CodingAVC;
-    } else if (!strcasecmp("video/mp4v-es", mime)) {
+    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
         compressionFormat = OMX_VIDEO_CodingMPEG4;
-    } else if (!strcasecmp("video/3gpp", mime)) {
+    } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
         compressionFormat = OMX_VIDEO_CodingH263;
     } else {
         LOGE("Not a supported video mime type: %s", mime);
@@ -663,7 +677,10 @@
     setComponentRole();
 }
 
-void OMXCodec::setComponentRole() {
+// static
+void OMXCodec::setComponentRole(
+        const sp<IOMX> &omx, IOMX::node_id node, bool isEncoder,
+        const char *mime) {
     struct MimeToRole {
         const char *mime;
         const char *decoderRole;
@@ -671,12 +688,20 @@
     };
 
     static const MimeToRole kMimeToRole[] = {
-        { "audio/mpeg", "audio_decoder.mp3", "audio_encoder.mp3" },
-        { "audio/3gpp", "audio_decoder.amrnb", "audio_encoder.amrnb" },
-        { "audio/mp4a-latm", "audio_decoder.aac", "audio_encoder.aac" },
-        { "video/avc",  "video_decoder.avc", "video_encoder.avc" },
-        { "video/mp4v-es", "video_decoder.mpeg4", "video_encoder.mpeg4" },
-        { "video/3gpp", "video_decoder.h263", "video_encoder.h263" },
+        { MEDIA_MIMETYPE_AUDIO_MPEG,
+            "audio_decoder.mp3", "audio_encoder.mp3" },
+        { MEDIA_MIMETYPE_AUDIO_AMR_NB,
+            "audio_decoder.amrnb", "audio_encoder.amrnb" },
+        { MEDIA_MIMETYPE_AUDIO_AMR_WB,
+            "audio_decoder.amrwb", "audio_encoder.amrwb" },
+        { MEDIA_MIMETYPE_AUDIO_AAC,
+            "audio_decoder.aac", "audio_encoder.aac" },
+        { MEDIA_MIMETYPE_VIDEO_AVC,
+            "video_decoder.avc", "video_encoder.avc" },
+        { MEDIA_MIMETYPE_VIDEO_MPEG4,
+            "video_decoder.mpeg4", "video_encoder.mpeg4" },
+        { MEDIA_MIMETYPE_VIDEO_H263,
+            "video_decoder.h263", "video_encoder.h263" },
     };
 
     static const size_t kNumMimeToRole =
@@ -684,7 +709,7 @@
 
     size_t i;
     for (i = 0; i < kNumMimeToRole; ++i) {
-        if (!strcasecmp(mMIME, kMimeToRole[i].mime)) {
+        if (!strcasecmp(mime, kMimeToRole[i].mime)) {
             break;
         }
     }
@@ -694,12 +719,10 @@
     }
 
     const char *role =
-        mIsEncoder ? kMimeToRole[i].encoderRole
-                   : kMimeToRole[i].decoderRole;
+        isEncoder ? kMimeToRole[i].encoderRole
+                  : kMimeToRole[i].decoderRole;
 
     if (role != NULL) {
-        CODEC_LOGV("Setting component role '%s'.", role);
-
         OMX_PARAM_COMPONENTROLETYPE roleParams;
         InitOMXParams(&roleParams);
 
@@ -708,8 +731,8 @@
 
         roleParams.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0';
 
-        status_t err = mOMX->set_parameter(
-                mNode, OMX_IndexParamStandardComponentRole,
+        status_t err = omx->set_parameter(
+                node, OMX_IndexParamStandardComponentRole,
                 &roleParams, sizeof(roleParams));
 
         if (err != OK) {
@@ -718,6 +741,10 @@
     }
 }
 
+void OMXCodec::setComponentRole() {
+    setComponentRole(mOMX, mNode, mIsEncoder, mMIME);
+}
+
 OMXCodec::~OMXCodec() {
     CHECK(mState == LOADED || mState == ERROR);
 
@@ -1351,7 +1378,7 @@
 
         size_t size = specific->mSize;
 
-        if (!strcasecmp("video/avc", mMIME)
+        if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mMIME)
                 && !(mQuirks & kWantsNALFragments)) {
             static const uint8_t kNALStartCode[4] =
                     { 0x00, 0x00, 0x00, 0x01 };
@@ -1548,6 +1575,37 @@
     }
 }
 
+void OMXCodec::setAMRWBFormat() {
+    if (!mIsEncoder) {
+        OMX_AUDIO_PARAM_AMRTYPE def;
+        InitOMXParams(&def);
+        def.nPortIndex = kPortIndexInput;
+
+        status_t err =
+            mOMX->get_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
+
+        CHECK_EQ(err, OK);
+
+        def.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF;
+        def.eAMRBandMode = OMX_AUDIO_AMRBandModeWB0;
+
+        err = mOMX->set_parameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def));
+        CHECK_EQ(err, OK);
+    }
+
+    ////////////////////////
+
+    if (mIsEncoder) {
+        sp<MetaData> format = mSource->getFormat();
+        int32_t sampleRate;
+        int32_t numChannels;
+        CHECK(format->findInt32(kKeySampleRate, &sampleRate));
+        CHECK(format->findInt32(kKeyChannelCount, &numChannels));
+
+        setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
+    }
+}
+
 void OMXCodec::setAACFormat(int32_t numChannels, int32_t sampleRate) {
     if (mIsEncoder) {
         setRawAudioFormat(kPortIndexInput, sampleRate, numChannels);
@@ -1621,6 +1679,15 @@
             break;
         }
 
+        case OMX_COLOR_Format16bitARGB4444:
+        case OMX_COLOR_Format16bitARGB1555:
+        case OMX_COLOR_Format16bitRGB565:
+        case OMX_COLOR_Format16bitBGR565:
+        {
+            def.nBufferSize = width * height * 2;
+            break;
+        }
+
         default:
             CHECK(!"Should not be here. Unknown color format.");
             break;
@@ -2020,6 +2087,55 @@
     }
 }
 
+static const char *amrBandModeString(OMX_AUDIO_AMRBANDMODETYPE type) {
+    static const char *kNames[] = {
+        "OMX_AUDIO_AMRBandModeUnused",
+        "OMX_AUDIO_AMRBandModeNB0",
+        "OMX_AUDIO_AMRBandModeNB1",
+        "OMX_AUDIO_AMRBandModeNB2",
+        "OMX_AUDIO_AMRBandModeNB3",
+        "OMX_AUDIO_AMRBandModeNB4",
+        "OMX_AUDIO_AMRBandModeNB5",
+        "OMX_AUDIO_AMRBandModeNB6",
+        "OMX_AUDIO_AMRBandModeNB7",
+        "OMX_AUDIO_AMRBandModeWB0",
+        "OMX_AUDIO_AMRBandModeWB1",
+        "OMX_AUDIO_AMRBandModeWB2",
+        "OMX_AUDIO_AMRBandModeWB3",
+        "OMX_AUDIO_AMRBandModeWB4",
+        "OMX_AUDIO_AMRBandModeWB5",
+        "OMX_AUDIO_AMRBandModeWB6",
+        "OMX_AUDIO_AMRBandModeWB7",
+        "OMX_AUDIO_AMRBandModeWB8",
+    };
+
+    size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
+
+    if (type < 0 || (size_t)type >= numNames) {
+        return "UNKNOWN";
+    } else {
+        return kNames[type];
+    }
+}
+
+static const char *amrFrameFormatString(OMX_AUDIO_AMRFRAMEFORMATTYPE type) {
+    static const char *kNames[] = {
+        "OMX_AUDIO_AMRFrameFormatConformance",
+        "OMX_AUDIO_AMRFrameFormatIF1",
+        "OMX_AUDIO_AMRFrameFormatIF2",
+        "OMX_AUDIO_AMRFrameFormatFSF",
+        "OMX_AUDIO_AMRFrameFormatRTPPayload",
+        "OMX_AUDIO_AMRFrameFormatITU",
+    };
+
+    size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
+
+    if (type < 0 || (size_t)type >= numNames) {
+        return "UNKNOWN";
+    } else {
+        return kNames[type];
+    }
+}
 
 void OMXCodec::dumpPortStatus(OMX_U32 portIndex) {
     OMX_PARAM_PORTDEFINITIONTYPE def;
@@ -2106,6 +2222,20 @@
                         ? "signed" : "unsigned");
 
                 printf("  ePCMMode = %s\n", audioPCMModeString(params.ePCMMode));
+            } else if (audioDef->eEncoding == OMX_AUDIO_CodingAMR) {
+                OMX_AUDIO_PARAM_AMRTYPE amr;
+                InitOMXParams(&amr);
+                amr.nPortIndex = portIndex;
+
+                err = mOMX->get_parameter(
+                        mNode, OMX_IndexParamAudioAmr, &amr, sizeof(amr));
+                CHECK_EQ(err, OK);
+
+                printf("  nChannels = %ld\n", amr.nChannels);
+                printf("  eAMRBandMode = %s\n",
+                        amrBandModeString(amr.eAMRBandMode));
+                printf("  eAMRFrameFormat = %s\n",
+                        amrFrameFormatString(amr.eAMRFrameFormat));
             }
 
             break;
@@ -2139,7 +2269,7 @@
             OMX_IMAGE_PORTDEFINITIONTYPE *imageDef = &def.format.image;
             CHECK_EQ(imageDef->eCompressionFormat, OMX_IMAGE_CodingUnused);
 
-            mOutputFormat->setCString(kKeyMIMEType, "image/raw");
+            mOutputFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
             mOutputFormat->setInt32(kKeyColorFormat, imageDef->eColorFormat);
             mOutputFormat->setInt32(kKeyWidth, imageDef->nFrameWidth);
             mOutputFormat->setInt32(kKeyHeight, imageDef->nFrameHeight);
@@ -2172,7 +2302,8 @@
                          "the input stream contains.");
                 }
 
-                mOutputFormat->setCString(kKeyMIMEType, "audio/raw");
+                mOutputFormat->setCString(
+                        kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
 
                 // Use the codec-advertised number of channels, as some
                 // codecs appear to output stereo even if the input data is
@@ -2182,9 +2313,33 @@
                 // The codec-reported sampleRate is not reliable...
                 mOutputFormat->setInt32(kKeySampleRate, sampleRate);
             } else if (audio_def->eEncoding == OMX_AUDIO_CodingAMR) {
-                mOutputFormat->setCString(kKeyMIMEType, "audio/3gpp");
+                OMX_AUDIO_PARAM_AMRTYPE amr;
+                InitOMXParams(&amr);
+                amr.nPortIndex = kPortIndexOutput;
+
+                err = mOMX->get_parameter(
+                        mNode, OMX_IndexParamAudioAmr, &amr, sizeof(amr));
+                CHECK_EQ(err, OK);
+
+                CHECK_EQ(amr.nChannels, 1);
+                mOutputFormat->setInt32(kKeyChannelCount, 1);
+
+                if (amr.eAMRBandMode >= OMX_AUDIO_AMRBandModeNB0
+                    && amr.eAMRBandMode <= OMX_AUDIO_AMRBandModeNB7) {
+                    mOutputFormat->setCString(
+                            kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_NB);
+                    mOutputFormat->setInt32(kKeySampleRate, 8000);
+                } else if (amr.eAMRBandMode >= OMX_AUDIO_AMRBandModeWB0
+                            && amr.eAMRBandMode <= OMX_AUDIO_AMRBandModeWB8) {
+                    mOutputFormat->setCString(
+                            kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AMR_WB);
+                    mOutputFormat->setInt32(kKeySampleRate, 16000);
+                } else {
+                    CHECK(!"Unknown AMR band mode.");
+                }
             } else if (audio_def->eEncoding == OMX_AUDIO_CodingAAC) {
-                mOutputFormat->setCString(kKeyMIMEType, "audio/mp4a-latm");
+                mOutputFormat->setCString(
+                        kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
             } else {
                 CHECK(!"Should not be here. Unknown audio encoding.");
             }
@@ -2196,13 +2351,17 @@
             OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video;
 
             if (video_def->eCompressionFormat == OMX_VIDEO_CodingUnused) {
-                mOutputFormat->setCString(kKeyMIMEType, "video/raw");
+                mOutputFormat->setCString(
+                        kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW);
             } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingMPEG4) {
-                mOutputFormat->setCString(kKeyMIMEType, "video/mp4v-es");
+                mOutputFormat->setCString(
+                        kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
             } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingH263) {
-                mOutputFormat->setCString(kKeyMIMEType, "video/3gpp");
+                mOutputFormat->setCString(
+                        kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_H263);
             } else if (video_def->eCompressionFormat == OMX_VIDEO_CodingAVC) {
-                mOutputFormat->setCString(kKeyMIMEType, "video/avc");
+                mOutputFormat->setCString(
+                        kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
             } else {
                 CHECK(!"Unknown compression format.");
             }
@@ -2230,4 +2389,67 @@
     }
 }
 
+////////////////////////////////////////////////////////////////////////////////
+
+status_t QueryCodecs(
+        const sp<IOMX> &omx,
+        const char *mime, bool queryDecoders,
+        Vector<CodecCapabilities> *results) {
+    results->clear();
+
+    for (int index = 0;; ++index) {
+        const char *componentName;
+
+        if (!queryDecoders) {
+            componentName = GetCodec(
+                    kEncoderInfo, sizeof(kEncoderInfo) / sizeof(kEncoderInfo[0]),
+                    mime, index);
+        } else {
+            componentName = GetCodec(
+                    kDecoderInfo, sizeof(kDecoderInfo) / sizeof(kDecoderInfo[0]),
+                    mime, index);
+        }
+
+        if (!componentName) {
+            return OK;
+        }
+
+        IOMX::node_id node;
+        status_t err = omx->allocate_node(componentName, &node);
+
+        if (err != OK) {
+            continue;
+        }
+
+        OMXCodec::setComponentRole(omx, node, queryDecoders, mime);
+
+        results->push();
+        CodecCapabilities *caps = &results->editItemAt(results->size() - 1);
+        caps->mComponentName = componentName;
+
+        OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
+        InitOMXParams(&param);
+
+        param.nPortIndex = queryDecoders ? 0 : 1;
+
+        for (param.nProfileIndex = 0;; ++param.nProfileIndex) {
+            err = omx->get_parameter(
+                    node, OMX_IndexParamVideoProfileLevelQuerySupported,
+                    &param, sizeof(param));
+
+            if (err != OK) {
+                break;
+            }
+
+            CodecProfileLevel profileLevel;
+            profileLevel.mProfile = param.eProfile;
+            profileLevel.mLevel = param.eLevel;
+
+            caps->mProfileLevels.push(profileLevel);
+        }
+
+        CHECK_EQ(omx->free_node(node), OK);
+    }
+}
+
 }  // namespace android
diff --git a/media/libstagefright/ShoutcastSource.cpp b/media/libstagefright/ShoutcastSource.cpp
index 4375f38..8e8f4fa 100644
--- a/media/libstagefright/ShoutcastSource.cpp
+++ b/media/libstagefright/ShoutcastSource.cpp
@@ -20,6 +20,7 @@
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
 #include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/ShoutcastSource.h>
 #include <media/stagefright/string.h>
@@ -77,7 +78,7 @@
 
 sp<MetaData> ShoutcastSource::getFormat() {
     sp<MetaData> meta = new MetaData;
-    meta->setCString(kKeyMIMEType, "audio/mpeg");
+    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
     meta->setInt32(kKeySampleRate, 44100);
     meta->setInt32(kKeyChannelCount, 2);  // XXX
 
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
index 45a5e53..a86ef8f9 100755
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
@@ -415,7 +415,7 @@
           null, null, "231180", "1", null},
       {"/sdcard/media_api/metaDataTestMedias/M4A/Jaws Of Life_ver1.m4a", "1/8", "Suspended Animation",
           "John Petrucci", null, null, "20070510T125223.000Z", 
-          "13", "Jaws Of Life", "2005", "19815424", "1", "m4a composer"},
+          "13", "Jaws Of Life", "2005", "449329", "1", "m4a composer"},
       {"/sdcard/media_api/metaDataTestMedias/M4V/sample_iPod.m4v", null, null, 
           null, null, null, "20051220T202015.000Z", 
           null, null, null, "85500", "2", null},
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaPlayerStressTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaPlayerStressTest.java
index 5e213d7..3667fae 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaPlayerStressTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaPlayerStressTest.java
@@ -97,6 +97,7 @@
         int video_duration = MediaNames.VIDEO_H263_AAC_DURATION;
         int random_play_time = 0;
         int random_seek_time = 0;
+        int random_no_of_seek = 0;
 
         mSurfaceHolder = MediaFrameworkTest.mSurfaceView.getHolder();
         try {
@@ -106,8 +107,13 @@
                 mp.setDisplay(MediaFrameworkTest.mSurfaceView.getHolder());
                 mp.prepare();
                 mp.start();
+                random_no_of_seek = generator.nextInt(10);
+                // make sure the seek at least run once.
+                if (random_no_of_seek == 0) {
+                    random_no_of_seek = 1;
+                }
                 // Random seek and play
-                for (int j = 0; j < generator.nextInt(10); j++) {
+                for (int j = 0; j < random_no_of_seek; j++) {
                     random_play_time =
                         generator.nextInt(video_duration / 2);
                     Log.v(TAG, "Play time = " + random_play_time);
diff --git a/opengl/libagl/texture.cpp b/opengl/libagl/texture.cpp
index 4d3c2f4..90e6d29 100644
--- a/opengl/libagl/texture.cpp
+++ b/opengl/libagl/texture.cpp
@@ -118,10 +118,10 @@
 
 /*
  * If the active textures are EGLImage, they need to be locked before
- * they can be used. 
- * 
+ * they can be used.
+ *
  * FIXME: code below is far from being optimal
- * 
+ *
  */
 
 void ogles_lock_textures(ogles_context_t* c)
@@ -409,6 +409,49 @@
     return 0;
 }
 
+static size_t dataSizePalette4(int numLevels, int width, int height, int format)
+{
+    int indexBits = 8;
+    int entrySize = 0;
+    switch (format) {
+    case GL_PALETTE4_RGB8_OES:
+        indexBits = 4;
+        /* FALLTHROUGH */
+    case GL_PALETTE8_RGB8_OES:
+        entrySize = 3;
+        break;
+
+    case GL_PALETTE4_RGBA8_OES:
+        indexBits = 4;
+        /* FALLTHROUGH */
+    case GL_PALETTE8_RGBA8_OES:
+        entrySize = 4;
+        break;
+
+    case GL_PALETTE4_R5_G6_B5_OES:
+    case GL_PALETTE4_RGBA4_OES:
+    case GL_PALETTE4_RGB5_A1_OES:
+        indexBits = 4;
+        /* FALLTHROUGH */
+    case GL_PALETTE8_R5_G6_B5_OES:
+    case GL_PALETTE8_RGBA4_OES:
+    case GL_PALETTE8_RGB5_A1_OES:
+        entrySize = 2;
+        break;
+    }
+
+    size_t size = (1 << indexBits) * entrySize; // palette size
+
+    for (int i=0 ; i< numLevels ; i++) {
+        int w = (width  >> i) ? : 1;
+        int h = (height >> i) ? : 1;
+        int levelSize = h * ((w * indexBits) / 8) ? : 1;
+        size += levelSize;
+    }
+
+    return size;
+}
+
 static void decodePalette4(const GLvoid *data, int level, int width, int height,
                            void *surface, int stride, int format)
 
@@ -443,6 +486,7 @@
     }
 
     const int paletteSize = (1 << indexBits) * entrySize;
+
     uint8_t const* pixels = (uint8_t *)data + paletteSize;
     for (int i=0 ; i<level ; i++) {
         int w = (width  >> i) ? : 1;
@@ -652,7 +696,7 @@
         ogles_context_t* c)
 {
     ogles_lock_textures(c);
-    
+
     const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
     y = gglIntToFixed(cbSurface.height) - (y + h);
     w >>= FIXED_BITS;
@@ -799,7 +843,7 @@
             c->rasterizer.procs.disable(c, GGL_AA);
             c->rasterizer.procs.shadeModel(c, GL_FLAT);
             c->rasterizer.procs.recti(c, x, y, x+w, y+h);
-            
+
             ogles_unlock_textures(c);
 
             return;
@@ -1091,6 +1135,12 @@
     GGLSurface* surface;
     // all mipmap levels are specified at once.
     const int numLevels = level<0 ? -level : 1;
+
+    if (dataSizePalette4(numLevels, width, height, format) > imageSize) {
+        ogles_error(c, GL_INVALID_VALUE);
+        return;
+    }
+
     for (int i=0 ; i<numLevels ; i++) {
         int lod_w = (width  >> i) ? : 1;
         int lod_h = (height >> i) ? : 1;
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 8f4061e..2524a30 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -25,6 +25,8 @@
 import android.content.res.Resources;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteDoneException;
+import android.database.sqlite.SQLiteException;
 import android.database.sqlite.SQLiteOpenHelper;
 import android.database.sqlite.SQLiteStatement;
 import android.media.AudioManager;
@@ -64,6 +66,11 @@
 
     private static final String TAG = "SettingsProvider";
     private static final String DATABASE_NAME = "settings.db";
+
+    // Please, please please. If you update the database version, check to make sure the
+    // database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
+    // is properly propagated through your change.  Not doing so will result in a loss of user
+    // settings.
     private static final int DATABASE_VERSION = 39;
 
     private Context mContext;
@@ -397,6 +404,7 @@
             } finally {
                 db.endTransaction();
             }
+            upgradeVersion = 35;
         }
             // due to a botched merge from donut to eclair, the initialization of ASSISTED_GPS_ENABLED
             // was accidentally done out of order here.
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 56a279a..8cfd956 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -16,33 +16,31 @@
 
 package com.android.providers.settings;
 
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
+import java.io.EOFException;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
 import java.io.IOException;
-import java.io.EOFException;
 import java.util.Arrays;
-import java.util.HashMap;
 import java.util.zip.CRC32;
 
 import android.backup.BackupDataInput;
 import android.backup.BackupDataOutput;
 import android.backup.BackupHelperAgent;
-import android.bluetooth.BluetoothAdapter;
-import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Context;
 import android.database.Cursor;
-import android.media.AudioManager;
 import android.net.Uri;
 import android.net.wifi.WifiManager;
 import android.os.FileUtils;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
-import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Log;
@@ -52,6 +50,7 @@
  * List of settings that are backed up are stored in the Settings.java file
  */
 public class SettingsBackupAgent extends BackupHelperAgent {
+    private static final boolean DEBUG = true;
 
     private static final String KEY_SYSTEM = "system";
     private static final String KEY_SECURE = "secure";
@@ -72,7 +71,6 @@
 
     private static final String TAG = "SettingsBackupAgent";
 
-    private static final int COLUMN_ID = 0;
     private static final int COLUMN_NAME = 1;
     private static final int COLUMN_VALUE = 2;
 
@@ -83,12 +81,12 @@
     };
 
     private static final String FILE_WIFI_SUPPLICANT = "/data/misc/wifi/wpa_supplicant.conf";
+    private static final String FILE_WIFI_SUPPLICANT_TEMPLATE =
+            "/system/etc/wifi/wpa_supplicant.conf";
 
     // the key to store the WIFI data under, should be sorted as last, so restore happens last.
     // use very late unicode character to quasi-guarantee last sort position.
-    private static final String KEY_WIFI_SUPPLICANT = "\uffeeWIFI";
-
-    private static final String FILE_BT_ROOT = "/data/misc/hcid/";
+    private static final String KEY_WIFI_SUPPLICANT = "\uffedWIFI";
 
     private SettingsHelper mSettingsHelper;
 
@@ -105,7 +103,7 @@
         byte[] secureSettingsData = getSecureSettings();
         byte[] syncProviders = mSettingsHelper.getSyncProviders();
         byte[] locale = mSettingsHelper.getLocaleData();
-        byte[] wifiData = getFileData(FILE_WIFI_SUPPLICANT);
+        byte[] wifiData = getWifiSupplicant(FILE_WIFI_SUPPLICANT);
 
         long[] stateChecksums = readOldChecksums(oldState);
 
@@ -127,9 +125,6 @@
     public void onRestore(BackupDataInput data, int appVersionCode,
             ParcelFileDescriptor newState) throws IOException {
 
-
-        enableBluetooth(false);
-
         while (data.readNextHeader()) {
             final String key = data.getKey();
             final int size = data.getDataSize();
@@ -140,7 +135,7 @@
                 restoreSettings(data, Settings.Secure.CONTENT_URI);
             } else if (KEY_WIFI_SUPPLICANT.equals(key)) {
                 int retainedWifiState = enableWifi(false);
-                restoreFile(FILE_WIFI_SUPPLICANT, data);
+                restoreWifiSupplicant(FILE_WIFI_SUPPLICANT, data);
                 FileUtils.setPermissions(FILE_WIFI_SUPPLICANT,
                         FileUtils.S_IRUSR | FileUtils.S_IWUSR |
                         FileUtils.S_IRGRP | FileUtils.S_IWGRP,
@@ -248,6 +243,13 @@
             pos += length;
             if (!TextUtils.isEmpty(settingName) && !TextUtils.isEmpty(settingValue)) {
                 //Log.i(TAG, "Restore " + settingName + " = " + settingValue);
+
+                // TODO: versioning rather than just an ad hoc blacklist to handle
+                // older varieties of backed-up data
+                if (invalidSavedSetting(contentUri, settingName, settingValue)) {
+                    continue;
+                }
+
                 if (mSettingsHelper.restoreValue(settingName, settingValue)) {
                     cv.clear();
                     cv.put(Settings.NameValueTable.NAME, settingName);
@@ -258,6 +260,22 @@
         }
     }
 
+    private boolean invalidSavedSetting(Uri contentUri, String settingName, String settingValue) {
+        // Even if these settings were stored, don't use them on restore
+        if (contentUri.equals(Settings.Secure.CONTENT_URI)) {
+            if (settingName.equals(Settings.Secure.PREFERRED_NETWORK_MODE)
+                    || settingName.equals(Settings.Secure.PREFERRED_TTY_MODE)
+                    || settingName.equals(Settings.Secure.CDMA_CELL_BROADCAST_SMS)
+                    || settingName.equals(Settings.Secure.PREFERRED_CDMA_SUBSCRIPTION)
+                    || settingName.equals(Settings.Secure.ENHANCED_VOICE_PRIVACY_ENABLED)) {
+                if (DEBUG) Log.v(TAG, "Ignoring restore datum: " + settingName);
+                return true;
+            }
+        }
+
+        return false;
+    }
+
     private String[] copyAndSort(String[] keys) {
         String[] sortedKeys = new String[keys.length];
         System.arraycopy(keys, 0, sortedKeys, 0, keys.length);
@@ -319,19 +337,27 @@
         return result;
     }
 
-    private byte[] getFileData(String filename) {
+    private byte[] getWifiSupplicant(String filename) {
         try {
             File file = new File(filename);
             if (file.exists()) {
-                byte[] bytes = new byte[(int) file.length()];
-                FileInputStream fis = new FileInputStream(file);
-                int offset = 0;
-                int got = 0;
-                do {
-                    got = fis.read(bytes, offset, bytes.length - offset);
-                    if (got > 0) offset += got;
-                } while (offset < bytes.length && got > 0);
-                return bytes;
+                BufferedReader br = new BufferedReader(new FileReader(file));
+                StringBuffer relevantLines = new StringBuffer();
+                boolean started = false;
+                String line;
+                while ((line = br.readLine()) != null) {
+                    if (!started && line.startsWith("network")) {
+                        started = true;
+                    }
+                    if (started) {
+                        relevantLines.append(line).append("\n");
+                    }
+                }
+                if (relevantLines.length() > 0) {
+                    return relevantLines.toString().getBytes();
+                } else {
+                    return EMPTY_DATA;
+                }
             } else {
                 return EMPTY_DATA;
             }
@@ -341,18 +367,39 @@
         }
     }
 
-    private void restoreFile(String filename, BackupDataInput data) {
+    private void restoreWifiSupplicant(String filename, BackupDataInput data) {
         byte[] bytes = new byte[data.getDataSize()];
         if (bytes.length <= 0) return;
         try {
             data.readEntityData(bytes, 0, bytes.length);
-            FileOutputStream fos = new FileOutputStream(filename);
+            File supplicantFile = new File(FILE_WIFI_SUPPLICANT);
+            if (supplicantFile.exists()) supplicantFile.delete();
+            copyWifiSupplicantTemplate();
+
+            FileOutputStream fos = new FileOutputStream(filename, true);
+            fos.write("\n".getBytes());
             fos.write(bytes);
         } catch (IOException ioe) {
             Log.w(TAG, "Couldn't restore " + filename);
         }
     }
 
+    private void copyWifiSupplicantTemplate() {
+        try {
+            BufferedReader br = new BufferedReader(new FileReader(FILE_WIFI_SUPPLICANT_TEMPLATE));
+            BufferedWriter bw = new BufferedWriter(new FileWriter(FILE_WIFI_SUPPLICANT));
+            char[] temp = new char[1024];
+            int size;
+            while ((size = br.read(temp)) > 0) {
+                bw.write(temp, 0, size);
+            }
+            bw.close();
+            br.close();
+        } catch (IOException ioe) {
+            Log.w(TAG, "Couldn't copy wpa_supplicant file");
+        }
+    }
+
     /**
      * Write an int in BigEndian into the byte array.
      * @param out byte array
@@ -391,15 +438,4 @@
         }
         return WifiManager.WIFI_STATE_UNKNOWN;
     }
-
-    private void enableBluetooth(boolean enable) {
-        BluetoothAdapter bt = (BluetoothAdapter) getSystemService(Context.BLUETOOTH_SERVICE);
-        if (bt != null) {
-            if (!enable) {
-                bt.disable();
-            } else {
-                bt.enable();
-            }
-        }
-    }
 }
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index e26dd13..408a4d2 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -640,20 +640,14 @@
             return false;
         }
         NetworkStateTracker tracker = mNetTrackers[networkType];
-        /*
-         * If there's only one connected network, and it's the one requested,
-         * then we don't have to do anything - the requested route already
-         * exists. If it's not the requested network, then it's not possible
-         * to establish the requested route. Finally, if there is more than
-         * one connected network, then we must insert an entry in the routing
-         * table.
-         */
-        if (getNumConnectedNetworks() > 1) {
-            return tracker.requestRouteToHost(hostAddress);
-        } else {
-            return (mNetAttributes[networkType].isDefault() &&
-                    tracker.getNetworkInfo().isConnected());
+
+        if (!tracker.getNetworkInfo().isConnected() || tracker.isTeardownRequested()) {
+            if (DBG) {
+                Log.d(TAG, "requestRouteToHost on down network (" + networkType + " - dropped");
+            }
+            return false;
         }
+        return tracker.requestRouteToHost(hostAddress);
     }
 
     /**
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 3d4bcc5..f85d931 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -296,7 +296,7 @@
         setMediaStorageNotification(
                 com.android.internal.R.string.ext_media_nomedia_notification_title,
                 com.android.internal.R.string.ext_media_nomedia_notification_message,
-                com.android.internal.R.drawable.stat_sys_no_sim,
+                com.android.internal.R.drawable.stat_notify_sdcard_usb,
                 true, false, null);
         handlePossibleExplicitUnmountBroadcast(path);
 
@@ -353,7 +353,7 @@
 
         setMediaStorageNotification(com.android.internal.R.string.ext_media_nofs_notification_title,
                                     com.android.internal.R.string.ext_media_nofs_notification_message,
-                                    com.android.internal.R.drawable.stat_sys_no_sim,
+                                    com.android.internal.R.drawable.stat_notify_sdcard_usb,
                                     true, false, pi);
         updateUsbMassStorageNotification(false, false);
         intent = new Intent(Intent.ACTION_MEDIA_NOFS, 
@@ -421,7 +421,7 @@
 
         setMediaStorageNotification(com.android.internal.R.string.ext_media_unmountable_notification_title,
                                     com.android.internal.R.string.ext_media_unmountable_notification_message,
-                                    com.android.internal.R.drawable.stat_sys_no_sim,
+                                    com.android.internal.R.drawable.stat_notify_sdcard_usb,
                                     true, false, pi); 
         updateUsbMassStorageNotification(false, false);
 
diff --git a/services/java/com/android/server/PackageManagerBackupAgent.java b/services/java/com/android/server/PackageManagerBackupAgent.java
index 786f423..772ddeb 100644
--- a/services/java/com/android/server/PackageManagerBackupAgent.java
+++ b/services/java/com/android/server/PackageManagerBackupAgent.java
@@ -327,6 +327,13 @@
         try {
             int num = in.readInt();
             Log.v(TAG, " ... unflatten read " + num);
+
+            // Sensical?
+            if (num > 20) {
+                Log.e(TAG, "Suspiciously large sig count in restore data; aborting");
+                throw new IllegalStateException("Bad restore state");
+            }
+
             sigs = new Signature[num];
             for (int i = 0; i < num; i++) {
                 int len = in.readInt();
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 2dc747e..53ff78e 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -374,13 +374,6 @@
         }
         setWifiEnabledState(eventualWifiState, uid);
 
-        /*
-         * Initialize the number of allowed radio channels if Wi-Fi is being turned on.
-         */
-        if (enable) {
-            mWifiStateTracker.setNumAllowedChannels();
-        }
-
         return true;
     }
 
@@ -1434,10 +1427,10 @@
                     return;
                 }
                 mPluggedType = pluggedType;
-            } else if (action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) {
+            } else if (action.equals(BluetoothA2dp.ACTION_SINK_STATE_CHANGED)) {
                 boolean isBluetoothPlaying =
                         intent.getIntExtra(
-                                BluetoothA2dp.SINK_STATE,
+                                BluetoothA2dp.EXTRA_SINK_STATE,
                                 BluetoothA2dp.STATE_DISCONNECTED) == BluetoothA2dp.STATE_PLAYING;
                 mWifiStateTracker.setBluetoothScanMode(isBluetoothPlaying);
             } else {
@@ -1556,7 +1549,7 @@
         intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
         intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
         intentFilter.addAction(ACTION_DEVICE_IDLE);
-        intentFilter.addAction(BluetoothA2dp.SINK_STATE_CHANGED_ACTION);
+        intentFilter.addAction(BluetoothA2dp.ACTION_SINK_STATE_CHANGED);
         mContext.registerReceiver(mReceiver, intentFilter);
     }
     
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index c8ff6cb..b0e4038 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -8022,6 +8022,19 @@
             }
         }
 
+        WindowState findMainWindow() {
+            int j = windows.size();
+            while (j > 0) {
+                j--;
+                WindowState win = windows.get(j);
+                if (win.mAttrs.type == WindowManager.LayoutParams.TYPE_BASE_APPLICATION
+                        || win.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING) {
+                    return win;
+                }
+            }
+            return null;
+        }
+        
         void dump(PrintWriter pw, String prefix) {
             super.dump(pw, prefix);
             if (appToken != null) {
@@ -8088,71 +8101,6 @@
         }
     }
 
-    public static WindowManager.LayoutParams findAnimations(
-            ArrayList<AppWindowToken> order,
-            ArrayList<AppWindowToken> openingTokenList1,
-            ArrayList<AppWindowToken> closingTokenList2) {
-        // We need to figure out which animation to use...
-
-        // First, check if there is a compatible window in opening/closing
-        // apps, and use it if exists.
-        WindowManager.LayoutParams animParams = null;
-        int animSrc = 0;
-        animParams = findCompatibleWindowParams(openingTokenList1);
-        if (animParams == null) {
-            animParams = findCompatibleWindowParams(closingTokenList2);
-        }
-        if (animParams != null) {
-            return animParams;
-        }
-        
-        //Log.i(TAG, "Looking for animations...");
-        for (int i=order.size()-1; i>=0; i--) {
-            AppWindowToken wtoken = order.get(i);
-            //Log.i(TAG, "Token " + wtoken + " with " + wtoken.windows.size() + " windows");
-            if (openingTokenList1.contains(wtoken) || closingTokenList2.contains(wtoken)) {
-                int j = wtoken.windows.size();
-                while (j > 0) {
-                    j--;
-                    WindowState win = wtoken.windows.get(j);
-                    //Log.i(TAG, "Window " + win + ": type=" + win.mAttrs.type);
-                    if (win.mAttrs.type == WindowManager.LayoutParams.TYPE_BASE_APPLICATION
-                            || win.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING) {
-                        //Log.i(TAG, "Found base or application window, done!");
-                        if (wtoken.appFullscreen) {
-                            return win.mAttrs;
-                        }
-                        if (animSrc < 2) {
-                            animParams = win.mAttrs;
-                            animSrc = 2;
-                        }
-                    } else if (animSrc < 1 && win.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION) {
-                        //Log.i(TAG, "Found normal window, we may use this...");
-                        animParams = win.mAttrs;
-                        animSrc = 1;
-                    }
-                }
-            }
-        }
-
-        return animParams;
-    }
-
-    private static LayoutParams findCompatibleWindowParams(ArrayList<AppWindowToken> tokenList) {
-        for (int appCount = tokenList.size() - 1; appCount >= 0; appCount--) {
-            AppWindowToken wtoken = tokenList.get(appCount);
-            // Just checking one window is sufficient as all windows have the compatible flag 
-            // if the application is in compatibility mode.
-            if (wtoken.windows.size() > 0) {
-                WindowManager.LayoutParams params = wtoken.windows.get(0).mAttrs;
-                if ((params.flags & FLAG_COMPATIBLE_WINDOW) != 0) {
-                    return params;
-                }
-            }
-        }
-        return null;
-    }
-
     // -------------------------------------------------------------
     // DummyAnimation
     // -------------------------------------------------------------
@@ -9043,35 +8991,56 @@
                         adjustWallpaperWindowsLocked();
                         wallpaperMayChange = false;
                         
+                        // The top-most window will supply the layout params,
+                        // and we will determine it below.
+                        LayoutParams animLp = null;
+                        int bestAnimLayer = -1;
+                        
                         if (DEBUG_APP_TRANSITIONS) Log.v(TAG,
                                 "New wallpaper target=" + mWallpaperTarget
                                 + ", lower target=" + mLowerWallpaperTarget
                                 + ", upper target=" + mUpperWallpaperTarget);
                         int foundWallpapers = 0;
-                        if (mLowerWallpaperTarget != null) {
-                            // Need to determine if both the closing and
-                            // opening app token sets are wallpaper targets,
-                            // in which case special animations are needed
-                            // (since the wallpaper needs to stay static
-                            // behind them).
-                            NN = mClosingApps.size();
-                            for (i=0; i<NN; i++) {
-                                AppWindowToken wtoken = mClosingApps.get(i);
-                                if (mLowerWallpaperTarget.mAppToken == wtoken) {
-                                    foundWallpapers |= 1;
-                                }
-                                if (mUpperWallpaperTarget.mAppToken == wtoken) {
-                                    foundWallpapers |= 1;
+                        // Do a first pass through the tokens for two
+                        // things:
+                        // (1) Determine if both the closing and opening
+                        // app token sets are wallpaper targets, in which
+                        // case special animations are needed
+                        // (since the wallpaper needs to stay static
+                        // behind them).
+                        // (2) Find the layout params of the top-most
+                        // application window in the tokens, which is
+                        // what will control the animation theme.
+                        final int NC = mClosingApps.size();
+                        NN = NC + mOpeningApps.size();
+                        for (i=0; i<NN; i++) {
+                            AppWindowToken wtoken;
+                            int mode;
+                            if (i < NC) {
+                                wtoken = mClosingApps.get(i);
+                                mode = 1;
+                            } else {
+                                wtoken = mOpeningApps.get(i-NC);
+                                mode = 2;
+                            }
+                            if (mLowerWallpaperTarget != null) {
+                                if (mLowerWallpaperTarget.mAppToken == wtoken
+                                        || mUpperWallpaperTarget.mAppToken == wtoken) {
+                                    foundWallpapers |= mode;
                                 }
                             }
-                            NN = mOpeningApps.size();
-                            for (i=0; i<NN; i++) {
-                                AppWindowToken wtoken = mOpeningApps.get(i);
-                                if (mLowerWallpaperTarget.mAppToken == wtoken) {
-                                    foundWallpapers |= 2;
-                                }
-                                if (mUpperWallpaperTarget.mAppToken == wtoken) {
-                                    foundWallpapers |= 2;
+                            if (wtoken.appFullscreen) {
+                                WindowState ws = wtoken.findMainWindow();
+                                if (ws != null) {
+                                    // If this is a compatibility mode
+                                    // window, we will always use its anim.
+                                    if ((ws.mAttrs.flags&FLAG_COMPATIBLE_WINDOW) != 0) {
+                                        animLp = ws.mAttrs;
+                                        bestAnimLayer = Integer.MAX_VALUE;
+                                    } else if (ws.mLayer > bestAnimLayer) {
+                                        animLp = ws.mAttrs;
+                                        bestAnimLayer = ws.mLayer;
+                                    }
                                 }
                             }
                         }
@@ -9107,10 +9076,6 @@
                                     "New transit into wallpaper: " + transit);
                         }
                         
-                        // We need to figure out which animation to use...
-                        WindowManager.LayoutParams lp = findAnimations(mAppTokens,
-                                mOpeningApps, mClosingApps);
-
                         NN = mOpeningApps.size();
                         for (i=0; i<NN; i++) {
                             AppWindowToken wtoken = mOpeningApps.get(i);
@@ -9119,7 +9084,7 @@
                             wtoken.reportedVisible = false;
                             wtoken.inPendingTransaction = false;
                             wtoken.animation = null;
-                            setTokenVisibilityLocked(wtoken, lp, true, transit, false);
+                            setTokenVisibilityLocked(wtoken, animLp, true, transit, false);
                             wtoken.updateReportedVisibilityLocked();
                             wtoken.waitingToShow = false;
                             wtoken.showAllWindowsLocked();
@@ -9131,7 +9096,7 @@
                                     "Now closing app" + wtoken);
                             wtoken.inPendingTransaction = false;
                             wtoken.animation = null;
-                            setTokenVisibilityLocked(wtoken, lp, false, transit, false);
+                            setTokenVisibilityLocked(wtoken, animLp, false, transit, false);
                             wtoken.updateReportedVisibilityLocked();
                             wtoken.waitingToHide = false;
                             // Force the allDrawn flag, because we want to start
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 0b86fc0..66ef557 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -33,6 +33,7 @@
 import android.app.ApplicationErrorReport;
 import android.app.Dialog;
 import android.app.IActivityController;
+import android.app.IActivityManager;
 import android.app.IActivityWatcher;
 import android.app.IApplicationThread;
 import android.app.IInstrumentationWatcher;
@@ -3612,6 +3613,29 @@
         }
     }
 
+    public int startActivityPendingIntent(IApplicationThread caller,
+            PendingIntent intent, Intent fillInIntent, String resolvedType,
+            IBinder resultTo, String resultWho, int requestCode,
+            int flagsMask, int flagsValues) {
+        // Refuse possible leaked file descriptors
+        if (fillInIntent != null && fillInIntent.hasFileDescriptors()) {
+            throw new IllegalArgumentException("File descriptors passed in Intent");
+        }
+        
+        IIntentSender sender = intent.getTarget();
+        if (!(sender instanceof PendingIntentRecord)) {
+            throw new IllegalArgumentException("Bad PendingIntent object");
+        }
+        
+        PendingIntentRecord pir = (PendingIntentRecord)sender;
+        if (pir.key.type != IActivityManager.INTENT_SENDER_ACTIVITY) {
+            return START_NOT_ACTIVITY;
+        }
+        
+        return pir.sendInner(0, fillInIntent, resolvedType,
+                null, resultTo, resultWho, requestCode, flagsMask, flagsValues);
+    }
+    
     public boolean startNextMatchingActivity(IBinder callingActivity,
             Intent intent) {
         // Refuse possible leaked file descriptors
@@ -12918,15 +12942,6 @@
         }
 
         if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
-            // If this process has active services running in it, we would
-            // like to avoid killing it unless it would prevent the current
-            // application from running.  By default we put the process in
-            // with the rest of the background processes; as we scan through
-            // its services we may bump it up from there.
-            if (adj > hiddenAdj) {
-                adj = hiddenAdj;
-                app.adjType = "bg-services";
-            }
             final long now = SystemClock.uptimeMillis();
             // This process is more important if the top activity is
             // bound to the service.
@@ -12994,17 +13009,19 @@
                     }
                 }
             }
+            
+            // Finally, f this process has active services running in it, we
+            // would like to avoid killing it unless it would prevent the current
+            // application from running.  By default we put the process in
+            // with the rest of the background processes; as we scan through
+            // its services we may bump it up from there.
+            if (adj > hiddenAdj) {
+                adj = hiddenAdj;
+                app.adjType = "bg-services";
+            }
         }
 
         if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
-            // If this process has published any content providers, then
-            // its adjustment makes it at least as important as any of the
-            // processes using those providers, and no less important than
-            // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
-            if (adj > CONTENT_PROVIDER_ADJ) {
-                adj = CONTENT_PROVIDER_ADJ;
-                app.adjType = "pub-providers";
-            }
             Iterator jt = app.pubProviders.values().iterator();
             while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
                 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
@@ -13048,6 +13065,15 @@
                     }
                 }
             }
+            
+            // Finally, if this process has published any content providers,
+            // then its adjustment makes it at least as important as any of the
+            // processes using those providers, and no less important than
+            // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
+            if (adj > CONTENT_PROVIDER_ADJ) {
+                adj = CONTENT_PROVIDER_ADJ;
+                app.adjType = "pub-providers";
+            }
         }
 
         app.curRawAdj = adj;
diff --git a/services/java/com/android/server/am/PendingIntentRecord.java b/services/java/com/android/server/am/PendingIntentRecord.java
index fa2a100..d994362 100644
--- a/services/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/java/com/android/server/am/PendingIntentRecord.java
@@ -22,6 +22,7 @@
 import android.app.PendingIntent;
 import android.content.Intent;
 import android.os.Binder;
+import android.os.IBinder;
 import android.os.RemoteException;
 import android.util.Log;
 
@@ -172,6 +173,14 @@
 
     public int send(int code, Intent intent, String resolvedType,
             IIntentReceiver finishedReceiver) {
+        return sendInner(code, intent, resolvedType, finishedReceiver,
+                null, null, 0, 0, 0);
+    }
+    
+    int sendInner(int code, Intent intent, String resolvedType,
+            IIntentReceiver finishedReceiver,
+            IBinder resultTo, String resultWho, int requestCode,
+            int flagsMask, int flagsValues) {
         synchronized(owner) {
             if (!canceled) {
                 sent = true;
@@ -189,6 +198,8 @@
                 } else {
                     resolvedType = key.requestResolvedType;
                 }
+                flagsValues &= flagsMask;
+                finalIntent.setFlags((finalIntent.getFlags()&~flagsMask) | flagsValues);
                 
                 final long origId = Binder.clearCallingIdentity();
                 
@@ -198,7 +209,7 @@
                         try {
                             owner.startActivityInPackage(uid,
                                     finalIntent, resolvedType,
-                                    null, null, 0, false);
+                                    resultTo, resultWho, requestCode, false);
                         } catch (RuntimeException e) {
                             Log.w(ActivityManagerService.TAG,
                                     "Unable to send startActivity intent", e);
@@ -246,7 +257,7 @@
                 return 0;
             }
         }
-        return -1;
+        return IActivityManager.START_CANCELED;
     }
     
     protected void finalize() throws Throwable {
diff --git a/services/java/com/android/server/status/StatusBarPolicy.java b/services/java/com/android/server/status/StatusBarPolicy.java
index 10680dd..da64e54 100644
--- a/services/java/com/android/server/status/StatusBarPolicy.java
+++ b/services/java/com/android/server/status/StatusBarPolicy.java
@@ -19,9 +19,7 @@
 import android.app.AlertDialog;
 import android.bluetooth.BluetoothA2dp;
 import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothError;
 import android.bluetooth.BluetoothHeadset;
-import android.bluetooth.BluetoothIntent;
 import android.bluetooth.BluetoothPbap;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -362,9 +360,9 @@
                     || action.equals(Intent.ACTION_POWER_CONNECTED)) {
                 onBatteryOkay(intent);
             }
-            else if (action.equals(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION) ||
-                    action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION) ||
-                    action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION) ||
+            else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED) ||
+                    action.equals(BluetoothHeadset.ACTION_STATE_CHANGED) ||
+                    action.equals(BluetoothA2dp.ACTION_SINK_STATE_CHANGED) ||
                     action.equals(BluetoothPbap.PBAP_STATE_CHANGED_ACTION)) {
                 updateBluetooth(intent);
             }
@@ -507,9 +505,9 @@
         filter.addAction(Intent.ACTION_SYNC_STATE_CHANGED);
         filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
         filter.addAction(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
-        filter.addAction(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION);
-        filter.addAction(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION);
-        filter.addAction(BluetoothA2dp.SINK_STATE_CHANGED_ACTION);
+        filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
+        filter.addAction(BluetoothHeadset.ACTION_STATE_CHANGED);
+        filter.addAction(BluetoothA2dp.ACTION_SINK_STATE_CHANGED);
         filter.addAction(BluetoothPbap.PBAP_STATE_CHANGED_ACTION);
         filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
         filter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
@@ -1072,15 +1070,14 @@
         int iconId = com.android.internal.R.drawable.stat_sys_data_bluetooth;
 
         String action = intent.getAction();
-        if (action.equals(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION)) {
-            int state = intent.getIntExtra(BluetoothIntent.BLUETOOTH_STATE,
-                                           BluetoothError.ERROR);
-            mBluetoothEnabled = state == BluetoothAdapter.BLUETOOTH_STATE_ON;
-        } else if (action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION)) {
-            mBluetoothHeadsetState = intent.getIntExtra(BluetoothIntent.HEADSET_STATE,
+        if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
+            int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
+            mBluetoothEnabled = state == BluetoothAdapter.STATE_ON;
+        } else if (action.equals(BluetoothHeadset.ACTION_STATE_CHANGED)) {
+            mBluetoothHeadsetState = intent.getIntExtra(BluetoothHeadset.EXTRA_STATE,
                     BluetoothHeadset.STATE_ERROR);
-        } else if (action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) {
-            mBluetoothA2dpState = intent.getIntExtra(BluetoothA2dp.SINK_STATE,
+        } else if (action.equals(BluetoothA2dp.ACTION_SINK_STATE_CHANGED)) {
+            mBluetoothA2dpState = intent.getIntExtra(BluetoothA2dp.EXTRA_SINK_STATE,
                     BluetoothA2dp.STATE_DISCONNECTED);
         } else if (action.equals(BluetoothPbap.PBAP_STATE_CHANGED_ACTION)) {
             mBluetoothPbapState = intent.getIntExtra(BluetoothPbap.PBAP_STATE,
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index a744486..8914aceac 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -159,7 +159,8 @@
 
     /**
      * Returns the software version number for the device, for example,
-     * the IMEI/SV for GSM phones.
+     * the IMEI/SV for GSM phones. Return null if the software version is
+     * not available.
      *
      * <p>Requires Permission:
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
@@ -168,13 +169,15 @@
         try {
             return getSubscriberInfo().getDeviceSvn();
         } catch (RemoteException ex) {
+            return null;
+        } catch (NullPointerException ex) {
+            return null;
         }
-        return null;
     }
 
     /**
-     * Returns the unique device ID, for example, the IMEI for GSM and the MEID for CDMA
-     * phones.
+     * Returns the unique device ID, for example, the IMEI for GSM and the MEID
+     * for CDMA phones. Return null if device ID is not available.
      *
      * <p>Requires Permission:
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
@@ -183,12 +186,15 @@
         try {
             return getSubscriberInfo().getDeviceId();
         } catch (RemoteException ex) {
+            return null;
+        } catch (NullPointerException ex) {
+            return null;
         }
-        return null;
     }
 
     /**
      * Returns the current location of the device.
+     * Return null if current location is not available.
      *
      * <p>Requires Permission:
      * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or
@@ -199,8 +205,10 @@
             Bundle bundle = getITelephony().getCellLocation();
             return CellLocation.newFromBundle(bundle);
         } catch (RemoteException ex) {
+            return null;
+        } catch (NullPointerException ex) {
+            return null;
         }
-        return null;
     }
 
     /**
@@ -216,6 +224,7 @@
         try {
             getITelephony().enableLocationUpdates();
         } catch (RemoteException ex) {
+        } catch (NullPointerException ex) {
         }
     }
 
@@ -232,6 +241,7 @@
         try {
             getITelephony().disableLocationUpdates();
         } catch (RemoteException ex) {
+        } catch (NullPointerException ex) {
         }
     }
 
@@ -247,9 +257,10 @@
        try {
            return getITelephony().getNeighboringCellInfo();
        } catch (RemoteException ex) {
+           return null;
+       } catch (NullPointerException ex) {
+           return null;
        }
-       return null;
-
     }
 
     /**
@@ -289,7 +300,11 @@
                 // This can happen when the ITelephony interface is not up yet.
                 return getPhoneTypeFromProperty();
             }
-        } catch(RemoteException ex){
+        } catch (RemoteException ex) {
+            // This shouldn't happen in the normal case, as a backup we
+            // read from the system property.
+            return getPhoneTypeFromProperty();
+        } catch (NullPointerException ex) {
             // This shouldn't happen in the normal case, as a backup we
             // read from the system property.
             return getPhoneTypeFromProperty();
@@ -418,9 +433,12 @@
                 // This can happen when the ITelephony interface is not up yet.
                 return NETWORK_TYPE_UNKNOWN;
             }
-        } catch(RemoteException ex){
+        } catch(RemoteException ex) {
             // This shouldn't happen in the normal case
             return NETWORK_TYPE_UNKNOWN;
+        } catch (NullPointerException ex) {
+            // This could happen before phone restarts due to crashing
+            return NETWORK_TYPE_UNKNOWN;
         }
     }
 
@@ -489,6 +507,9 @@
         } catch (RemoteException ex) {
             // Assume no ICC card if remote exception which shouldn't happen
             return false;
+        } catch (NullPointerException ex) {
+            // This could happen before phone restarts due to crashing
+            return false;
         }
     }
 
@@ -556,7 +577,8 @@
     }
 
     /**
-     * Returns the serial number of the SIM, if applicable.
+     * Returns the serial number of the SIM, if applicable. Return null if it is
+     * unavailable.
      * <p>
      * Requires Permission:
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
@@ -565,8 +587,11 @@
         try {
             return getSubscriberInfo().getIccSerialNumber();
         } catch (RemoteException ex) {
+            return null;
+        } catch (NullPointerException ex) {
+            // This could happen before phone restarts due to crashing
+            return null;
         }
-        return null;
     }
 
     //
@@ -577,6 +602,7 @@
 
     /**
      * Returns the unique subscriber ID, for example, the IMSI for a GSM phone.
+     * Return null if it is unavailable.
      * <p>
      * Requires Permission:
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
@@ -585,13 +611,16 @@
         try {
             return getSubscriberInfo().getSubscriberId();
         } catch (RemoteException ex) {
+            return null;
+        } catch (NullPointerException ex) {
+            // This could happen before phone restarts due to crashing
+            return null;
         }
-        return null;
     }
 
     /**
      * Returns the phone number string for line 1, for example, the MSISDN
-     * for a GSM phone.
+     * for a GSM phone. Return null if it is unavailable.
      * <p>
      * Requires Permission:
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
@@ -600,12 +629,16 @@
         try {
             return getSubscriberInfo().getLine1Number();
         } catch (RemoteException ex) {
+            return null;
+        } catch (NullPointerException ex) {
+            // This could happen before phone restarts due to crashing
+            return null;
         }
-        return null;
     }
 
     /**
      * Returns the alphabetic identifier associated with the line 1 number.
+     * Return null if it is unavailable.
      * <p>
      * Requires Permission:
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
@@ -616,12 +649,15 @@
         try {
             return getSubscriberInfo().getLine1AlphaTag();
         } catch (RemoteException ex) {
+            return null;
+        } catch (NullPointerException ex) {
+            // This could happen before phone restarts due to crashing
+            return null;
         }
-        return null;
     }
 
     /**
-     * Returns the voice mail number.
+     * Returns the voice mail number. Return null if it is unavailable.
      * <p>
      * Requires Permission:
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
@@ -630,12 +666,15 @@
         try {
             return getSubscriberInfo().getVoiceMailNumber();
         } catch (RemoteException ex) {
+            return null;
+        } catch (NullPointerException ex) {
+            // This could happen before phone restarts due to crashing
+            return null;
         }
-        return null;
     }
 
     /**
-     * Returns the voice mail count.
+     * Returns the voice mail count. Return 0 if unavailable.
      * <p>
      * Requires Permission:
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
@@ -645,8 +684,11 @@
         try {
             return getITelephony().getVoiceMessageCount();
         } catch (RemoteException ex) {
+            return 0;
+        } catch (NullPointerException ex) {
+            // This could happen before phone restarts due to crashing
+            return 0;
         }
-        return 0;
     }
 
     /**
@@ -660,8 +702,11 @@
         try {
             return getSubscriberInfo().getVoiceMailAlphaTag();
         } catch (RemoteException ex) {
+            return null;
+        } catch (NullPointerException ex) {
+            // This could happen before phone restarts due to crashing
+            return null;
         }
-        return null;
     }
 
     private IPhoneSubInfo getSubscriberInfo() {
@@ -759,6 +804,8 @@
         } catch (RemoteException ex) {
             // the phone process is restarting.
             return DATA_DISCONNECTED;
+        } catch (NullPointerException ex) {
+            return DATA_DISCONNECTED;
         }
     }
 
@@ -802,6 +849,8 @@
             mRegistry.listen(pkgForDebug, listener.callback, events, notifyNow);
         } catch (RemoteException ex) {
             // system process dead
+        } catch (NullPointerException ex) {
+            // system process dead
         }
     }
 
@@ -816,6 +865,8 @@
         } catch (RemoteException ex) {
             // the phone process is restarting.
             return -1;
+        } catch (NullPointerException ex) {
+            return -1;
         }
     }
 
@@ -832,6 +883,8 @@
         } catch (RemoteException ex) {
             // the phone process is restarting.
             return -1;
+        } catch (NullPointerException ex) {
+            return -1;
         }
     }
 
@@ -846,6 +899,8 @@
         } catch (RemoteException ex) {
             // the phone process is restarting.
             return null;
+        } catch (NullPointerException ex) {
+            return null;
         }
     }
 }
diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java
index bda2d22..e1bd1db 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfo.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfo.java
@@ -250,7 +250,7 @@
             }
         }
 
-        Uri contactUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, number);
+        Uri contactUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
 
         CallerInfo info = getCallerInfo(context, contactUri);
 
diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
index ef456f0..3d4f78c 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
@@ -303,7 +303,7 @@
     public static CallerInfoAsyncQuery startQuery(int token, Context context, String number,
             OnQueryCompleteListener listener, Object cookie) {
         //contruct the URI object and start Query.
-        Uri contactRef = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, number);
+        Uri contactRef = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
 
         CallerInfoAsyncQuery c = new CallerInfoAsyncQuery();
         c.allocate(context, contactRef);
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index ece708a..8d2785a 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -100,7 +100,6 @@
     public static final int EVENT_CLEAN_UP_CONNECTION = 34;
     protected static final int EVENT_CDMA_OTA_PROVISION = 35;
     protected static final int EVENT_RESTART_RADIO = 36;
-    private static final int EVENT_ENABLE_APN_REQUEST = 37;
 
     /***** Constants *****/
 
@@ -126,6 +125,10 @@
         + "5000,10000,20000,40000,80000:5000,160000:5000,"
         + "320000:5000,640000:5000,1280000:5000,1800000:5000";
 
+    /** Retry configuration for secondary networks: 4 tries in 20 sec */
+    protected static final String SECONDARY_DATA_RETRY_CONFIG =
+            "max_retries=3; 5000, 5000, 5000";
+
     /** Slow poll when attempting connection recovery. */
     protected static final int POLL_NETSTAT_SLOW_MILLIS = 5000;
     /** Default ping deadline, in seconds. */
@@ -171,7 +174,7 @@
     protected boolean netStatPollEnabled = false;
 
     /** Manage the behavior of data retry after failure */
-    protected final RetryManager mRetryMgr = new RetryManager();
+    protected RetryManager mRetryMgr = new RetryManager();
 
     // wifi connection status will be updated by sticky intent
     protected boolean mIsWifiConnected = false;
@@ -266,33 +269,8 @@
     public void handleMessage (Message msg) {
         switch (msg.what) {
 
-            case EVENT_ENABLE_APN_REQUEST:
-                int apnId = msg.arg1;
-                synchronized (this) {
-                    if (DBG) {
-                        Log.d(LOG_TAG, "got EVENT_ENABLE_APN_REQUEST with apnType = " + apnId +
-                                " and enable = " + msg.arg2);
-                        Log.d(LOG_TAG, "dataEnabled[apnId] = " + dataEnabled[apnId] +
-                                ", enabledCount = " + enabledCount);
-                    }
-                    if (msg.arg2 == APN_ENABLED) {
-                        // enable
-                        if (!dataEnabled[apnId]) {
-                            dataEnabled[apnId] = true;
-                            enabledCount++;
-                        }
-                        onTrySetupData(null);
-                    } else {
-                        // disable
-                        if (dataEnabled[apnId]) {
-                            dataEnabled[apnId] = false;
-                            enabledCount--;
-                            if (enabledCount == 0) {
-                                onCleanUpConnection(true, Phone.REASON_DATA_DISABLED);
-                            }
-                        }
-                    }
-                }
+            case EVENT_ENABLE_NEW_APN:
+                onEnableApn(msg.arg1, msg.arg2);
                 break;
 
             case EVENT_TRY_SETUP_DATA:
@@ -392,6 +370,24 @@
         }
     }
 
+    protected String apnIdToType(int id) {
+        switch (id) {
+        case APN_DEFAULT_ID:
+            return Phone.APN_TYPE_DEFAULT;
+        case APN_MMS_ID:
+            return Phone.APN_TYPE_MMS;
+        case APN_SUPL_ID:
+            return Phone.APN_TYPE_SUPL;
+        case APN_DUN_ID:
+            return Phone.APN_TYPE_DUN;
+        case APN_HIPRI_ID:
+            return Phone.APN_TYPE_HIPRI;
+        default:
+            Log.e(LOG_TAG, "Unknown id (" + id + ") in apnIdToType");
+            return Phone.APN_TYPE_DEFAULT;
+        }
+    }
+
     protected abstract boolean isApnTypeActive(String type);
 
     protected abstract boolean isApnTypeAvailable(String type);
@@ -449,8 +445,6 @@
         }
 
         setEnabled(id, true);
-        mRequestedApnType = type;
-        sendMessage(obtainMessage(EVENT_ENABLE_NEW_APN));
         return Phone.APN_REQUEST_STARTED;
     }
 
@@ -471,7 +465,6 @@
         if (isEnabled(id)) {
             setEnabled(id, false);
             if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
-                mRequestedApnType = Phone.APN_TYPE_DEFAULT;
                 if (dataEnabled[APN_DEFAULT_ID]) {
                     return Phone.APN_ALREADY_ACTIVE;
                 } else {
@@ -485,16 +478,56 @@
         }
     }
 
-    protected void setEnabled(int id, boolean enable) {
+    private void setEnabled(int id, boolean enable) {
         if (DBG) Log.d(LOG_TAG, "setEnabled(" + id + ", " + enable + ") with old state = " +
                 dataEnabled[id] + " and enabledCount = " + enabledCount);
 
-        Message msg = obtainMessage(EVENT_ENABLE_APN_REQUEST);
+        Message msg = obtainMessage(EVENT_ENABLE_NEW_APN);
         msg.arg1 = id;
         msg.arg2 = (enable ? APN_ENABLED : APN_DISABLED);
         sendMessage(msg);
     }
 
+    protected synchronized void onEnableApn(int apnId, int enabled) {
+        if (DBG) {
+            Log.d(LOG_TAG, "got EVENT_APN_ENABLE_REQUEST with apnType = " + apnId +
+                    " and enable = " + enabled);
+            Log.d(LOG_TAG, "dataEnabled[apnId] = " + dataEnabled[apnId] +
+                    ", enabledCount = " + enabledCount);
+        }
+        if (enabled == APN_ENABLED) {
+            if (!dataEnabled[apnId]) {
+                mRequestedApnType = apnIdToType(apnId);
+                onEnableNewApn();
+
+                dataEnabled[apnId] = true;
+                enabledCount++;
+            }
+            onTrySetupData(null);
+        } else {
+            // disable
+            if (dataEnabled[apnId]) {
+                dataEnabled[apnId] = false;
+                enabledCount--;
+                if (enabledCount == 0) {
+                    onCleanUpConnection(true, Phone.REASON_DATA_DISABLED);
+                } else if (dataEnabled[APN_DEFAULT_ID] == true) {
+                    mRequestedApnType = Phone.APN_TYPE_DEFAULT;
+                    onEnableNewApn();
+                }
+            }
+        }
+    }
+
+    /**
+     * Called when we switch APNs.
+     *
+     * mRequestedApnType is set prior to call
+     * To be overridden.
+     */
+    protected void onEnableNewApn() {
+    }
+
     /**
      * Prevent mobile data connections from being established,
      * or once again allow mobile data connections. If the state
diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java
index e818175..f32837f 100644
--- a/telephony/java/com/android/internal/telephony/Phone.java
+++ b/telephony/java/com/android/internal/telephony/Phone.java
@@ -154,6 +154,7 @@
     static final String REASON_CDMA_DATA_DETACHED = "cdmaDataDetached";
     static final String REASON_APN_CHANGED = "apnChanged";
     static final String REASON_APN_SWITCHED = "apnSwitched";
+    static final String REASON_APN_FAILED = "apnFailed";
     static final String REASON_RESTORE_DEFAULT_APN = "restoreDefaultApn";
     static final String REASON_RADIO_TURNED_OFF = "radioTurnedOff";
     static final String REASON_PDP_RESET = "pdpReset";
@@ -1189,17 +1190,9 @@
     List<DataConnection> getCurrentDataConnectionList ();
 
     /**
-     * Udpate LAC and CID in service state for currnet GSM netowrk registration
-     *
-     * If get different LAC and/or CID, notifyServiceState will be sent
-     *
-     * @param
-     * <strong>On failure</strong>,
-     * (((AsyncResult)response.obj).result) == null and
-     * (((AsyncResult)response.obj).exception) being an instance of
-     * com.android.internal.telephony.gsm.CommandException
+     * Update the ServiceState CellLocation for current network registration.
      */
-    void updateServiceLocation(Message response);
+    void updateServiceLocation();
 
     /**
      * Enable location update notifications.
diff --git a/telephony/java/com/android/internal/telephony/PhoneProxy.java b/telephony/java/com/android/internal/telephony/PhoneProxy.java
index 8683278..711a48c 100644
--- a/telephony/java/com/android/internal/telephony/PhoneProxy.java
+++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java
@@ -566,8 +566,8 @@
         return mActivePhone.getCurrentDataConnectionList();
     }
 
-    public void updateServiceLocation(Message response) {
-        mActivePhone.updateServiceLocation(response);
+    public void updateServiceLocation() {
+        mActivePhone.updateServiceLocation();
     }
 
     public void enableLocationUpdates() {
diff --git a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
index cc13450..6892998 100644
--- a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -226,12 +226,43 @@
         setPowerStateToDesired();
     }
 
-    public void enableLocationUpdates() {
+    /**
+     * These two flags manage the behavior of the cell lock -- the
+     * lock should be held if either flag is true.  The intention is
+     * to allow temporary aquisition of the lock to get a single
+     * update.  Such a lock grab and release can thus be made to not
+     * interfere with more permanent lock holds -- in other words, the
+     * lock will only be released if both flags are false, and so
+     * releases by temporary users will only affect the lock state if
+     * there is no continuous user.
+     */
+    private boolean mWantContinuousLocationUpdates;
+    private boolean mWantSingleLocationUpdate;
+
+    public void enableSingleLocationUpdate() {
+        if (mWantSingleLocationUpdate || mWantContinuousLocationUpdates) return;
+        mWantSingleLocationUpdate = true;
         cm.setLocationUpdates(true, obtainMessage(EVENT_LOCATION_UPDATES_ENABLED));
     }
 
+    public void enableLocationUpdates() {
+        if (mWantSingleLocationUpdate || mWantContinuousLocationUpdates) return;
+        mWantContinuousLocationUpdates = true;
+        cm.setLocationUpdates(true, obtainMessage(EVENT_LOCATION_UPDATES_ENABLED));
+    }
+
+    protected void disableSingleLocationUpdate() {
+        mWantSingleLocationUpdate = false;
+        if (!mWantSingleLocationUpdate && !mWantContinuousLocationUpdates) {
+            cm.setLocationUpdates(false, null);
+        }
+    }
+
     public void disableLocationUpdates() {
-        cm.setLocationUpdates(false, null);
+        mWantContinuousLocationUpdates = false;
+        if (!mWantSingleLocationUpdate && !mWantContinuousLocationUpdates) {
+            cm.setLocationUpdates(false, null);
+        }
     }
 
     public abstract void handleMessage(Message msg);
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index ff06bc0..dfc4889 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -500,8 +500,8 @@
         Log.e(LOG_TAG, "method setCallWaiting is NOT supported in CDMA!");
     }
 
-    public void updateServiceLocation(Message response) {
-        mSST.getLacAndCid(response);
+    public void updateServiceLocation() {
+        mSST.enableSingleLocationUpdate();
     }
 
     public void setDataRoamingEnabled(boolean enable) {
@@ -661,6 +661,10 @@
         mSST.enableLocationUpdates();
     }
 
+    public void disableLocationUpdates() {
+        mSST.disableLocationUpdates();
+    }
+
     /**
      * @deprecated
      */
@@ -741,10 +745,6 @@
         }
     }
 
-    public void disableLocationUpdates() {
-        mSST.disableLocationUpdates();
-    }
-
     public boolean getIccRecordsLoaded() {
         return mRuimRecords.getRecordsLoaded();
     }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
index bf42257..623d985 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
@@ -21,6 +21,7 @@
 import android.app.PendingIntent;
 import android.app.PendingIntent.CanceledException;
 import android.content.ContentValues;
+import android.content.Intent;
 import android.content.SharedPreferences;
 import android.database.Cursor;
 import android.database.SQLException;
@@ -73,6 +74,23 @@
         Log.d(TAG, "handleStatusReport is a special GSM function, should never be called in CDMA!");
     }
 
+    private void handleCdmaStatusReport(SmsMessage sms) {
+        for (int i = 0, count = deliveryPendingList.size(); i < count; i++) {
+            SmsTracker tracker = deliveryPendingList.get(i);
+            if (tracker.mMessageRef == sms.messageRef) {
+                // Found it.  Remove from list and broadcast.
+                deliveryPendingList.remove(i);
+                PendingIntent intent = tracker.mDeliveryIntent;
+                Intent fillIn = new Intent();
+                fillIn.putExtra("pdu", sms.getPdu());
+                try {
+                    intent.send(mContext, Activity.RESULT_OK, fillIn);
+                } catch (CanceledException ex) {}
+                break;  // Only expect to see one tracker matching this message.
+            }
+        }
+    }
+
     /** {@inheritDoc} */
     protected int dispatchMessage(SmsMessageBase smsb) {
 
@@ -105,6 +123,11 @@
             editor.commit();
             ((CDMAPhone) mPhone).updateMessageWaitingIndicator(voicemailCount);
             handled = true;
+        } else if (((SmsEnvelope.TELESERVICE_WMT == teleService) ||
+                (SmsEnvelope.TELESERVICE_WEMT == teleService)) &&
+                sms.isStatusReportMessage()) {
+            handleCdmaStatusReport(sms);
+            handled = true;
         } else if ((sms.getUserData() == null)) {
             if (Config.LOGD) {
                 Log.d(TAG, "Received SMS without user data");
@@ -354,8 +377,12 @@
             uData.payloadStr = parts.get(i);
             uData.userDataHeader = smsHeader;
 
+            /* By setting the statusReportRequested bit only for the
+             * last message fragment, this will result in only one
+             * callback to the sender when that last fragment delivery
+             * has been acknowledged. */
             SmsMessage.SubmitPdu submitPdu = SmsMessage.getSubmitPdu(destAddr,
-                    uData, deliveryIntent != null);
+                    uData, (deliveryIntent != null) && (i == (msgCount - 1)));
 
             sendSubmitPdu(submitPdu, sentIntent, deliveryIntent);
         }
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index 46e360b..9ac78eb 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -279,12 +279,6 @@
         cdmaForSubscriptionInfoReadyRegistrants.remove(h);
     }
 
-    public void
-    getLacAndCid(Message onComplete) {
-        cm.getRegistrationState(obtainMessage(
-                EVENT_GET_LOC_DONE_CDMA, onComplete));
-    }
-
     @Override
     public void handleMessage (Message msg) {
         AsyncResult ar;
@@ -377,22 +371,14 @@
                     }
                 }
 
-                // Only update if cell location really changed.
-                if (cellLoc.getBaseStationId() != baseStationData[0]
-                        || cellLoc.getBaseStationLatitude() != baseStationData[1]
-                        || cellLoc.getBaseStationLongitude() != baseStationData[2]) {
-                    cellLoc.setCellLocationData(baseStationData[0],
-                                                baseStationData[1],
-                                                baseStationData[2]);
-                   phone.notifyLocationChanged();
-                }
+                cellLoc.setCellLocationData(baseStationData[0],
+                        baseStationData[1], baseStationData[2]);
+                phone.notifyLocationChanged();
             }
 
-            if (ar.userObj != null) {
-                AsyncResult.forMessage(((Message) ar.userObj)).exception
-                = ar.exception;
-                ((Message) ar.userObj).sendToTarget();
-            }
+            // Release any temporary cell lock, which could have been
+            // aquired to allow a single-shot location update.
+            disableSingleLocationUpdate();
             break;
 
         case EVENT_POLL_STATE_REGISTRATION_CDMA:
@@ -487,7 +473,7 @@
             ar = (AsyncResult) msg.obj;
 
             if (ar.exception == null) {
-                getLacAndCid(null);
+                cm.getRegistrationState(obtainMessage(EVENT_GET_LOC_DONE_CDMA, null));
             }
             break;
 
diff --git a/telephony/java/com/android/internal/telephony/cdma/EriManager.java b/telephony/java/com/android/internal/telephony/cdma/EriManager.java
index 6c1384c..44c6173 100644
--- a/telephony/java/com/android/internal/telephony/cdma/EriManager.java
+++ b/telephony/java/com/android/internal/telephony/cdma/EriManager.java
@@ -19,12 +19,19 @@
 import android.content.res.XmlResourceParser;
 import android.os.Message;
 import android.util.Log;
+import android.util.Xml;
 
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneBase;
 
 import com.android.internal.util.XmlUtils;
 
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
 import java.util.HashMap;
 
 /**
@@ -76,7 +83,8 @@
         }
     }
 
-    static final String LOG_TAG = "CDMA";
+    private static final String LOG_TAG = "CDMA";
+    private static final boolean DBG = true;
 
     public static final int ERI_FROM_XML          = 0;
     public static final int ERI_FROM_FILE_SYSTEM  = 1;
@@ -143,8 +151,30 @@
      *
      */
     private void loadEriFileFromXml() {
+        XmlPullParser parser = null;
+        FileInputStream stream = null;
         Resources r = mContext.getResources();
-        XmlResourceParser parser = r.getXml(com.android.internal.R.xml.eri);
+
+        try {
+            if (DBG) Log.d(LOG_TAG, "loadEriFileFromXml: check for alternate file");
+            stream = new FileInputStream(
+                            r.getString(com.android.internal.R.string.alternate_eri_file));
+            parser = Xml.newPullParser();
+            parser.setInput(stream, null);
+            if (DBG) Log.d(LOG_TAG, "loadEriFileFromXml: opened alternate file");
+        } catch (FileNotFoundException e) {
+            if (DBG) Log.d(LOG_TAG, "loadEriFileFromXml: no alternate file");
+            parser = null;
+        } catch (XmlPullParserException e) {
+            if (DBG) Log.d(LOG_TAG, "loadEriFileFromXml: no parser for alternate file");
+            parser = null;
+        }
+
+        if (parser == null) {
+            if (DBG) Log.d(LOG_TAG, "loadEriFileFromXml: open normal file");
+            parser = r.getXml(com.android.internal.R.xml.eri);
+        }
+
         try {
             XmlUtils.beginDocument(parser, "EriFile");
             mEriFile.mVersionNumber = Integer.parseInt(
@@ -187,12 +217,22 @@
                 }
             }
 
+            if (DBG) Log.d(LOG_TAG, "loadEriFileFromXml: eri parsing successful, file loaded");
             isEriFileLoaded = true;
 
         } catch (Exception e) {
             Log.e(LOG_TAG, "Got exception while loading ERI file.", e);
         } finally {
-            parser.close();
+            if (parser instanceof XmlResourceParser) {
+                ((XmlResourceParser)parser).close();
+            }
+            try {
+                if (stream != null) {
+                    stream.close();
+                }
+            } catch (IOException e) {
+                // Ignore
+            }
         }
     }
 
@@ -345,16 +385,16 @@
         default:
             if (!isEriFileLoaded) {
                 // ERI file NOT loaded
-                Log.d(LOG_TAG, "ERI File not loaded");
+                if (DBG) Log.d(LOG_TAG, "ERI File not loaded");
                 if(defRoamInd > 2) {
-                    Log.d(LOG_TAG, "ERI defRoamInd > 2 ...flashing");
+                    if (DBG) Log.d(LOG_TAG, "ERI defRoamInd > 2 ...flashing");
                     ret = new EriDisplayInformation(
                             EriInfo.ROAMING_INDICATOR_FLASH,
                             EriInfo.ROAMING_ICON_MODE_FLASH,
                             mContext.getText(com.android.internal
                                                             .R.string.roamingText2).toString());
                 } else {
-                    Log.d(LOG_TAG, "ERI defRoamInd <= 2");
+                    if (DBG) Log.d(LOG_TAG, "ERI defRoamInd <= 2");
                     switch (defRoamInd) {
                     case EriInfo.ROAMING_INDICATOR_ON:
                         ret = new EriDisplayInformation(
@@ -386,12 +426,14 @@
                 }
             } else {
                 // ERI file loaded
-                Log.d(LOG_TAG, "ERI File loaded");
+                if (DBG) Log.d(LOG_TAG, "ERI File loaded");
                 EriInfo eriInfo = getEriInfo(roamInd);
                 EriInfo defEriInfo = getEriInfo(defRoamInd);
                 if (eriInfo == null) {
-                    Log.d(LOG_TAG, "ERI roamInd " + roamInd
+                    if (DBG) {
+                        Log.d(LOG_TAG, "ERI roamInd " + roamInd
                             + " not found in ERI file ...using defRoamInd " + defRoamInd);
+                    }
                     if(defEriInfo == null) {
                         Log.e(LOG_TAG, "ERI defRoamInd " + defRoamInd
                                 + " not found in ERI file ...on");
@@ -402,14 +444,16 @@
                                                              .R.string.roamingText0).toString());
 
                     } else {
-                        Log.d(LOG_TAG, "ERI defRoamInd " + defRoamInd + " found in ERI file");
+                        if (DBG) {
+                            Log.d(LOG_TAG, "ERI defRoamInd " + defRoamInd + " found in ERI file");
+                        }
                         ret = new EriDisplayInformation(
                                 defEriInfo.mIconIndex,
                                 defEriInfo.mIconMode,
                                 defEriInfo.mEriText);
                     }
                 } else {
-                    Log.d(LOG_TAG, "ERI roamInd " + roamInd + " found in ERI file");
+                    if (DBG) Log.d(LOG_TAG, "ERI roamInd " + roamInd + " found in ERI file");
                     ret = new EriDisplayInformation(
                             eriInfo.mIconIndex,
                             eriInfo.mIconMode,
@@ -418,7 +462,7 @@
             }
             break;
         }
-        Log.d(LOG_TAG, "Displaying ERI " + ret.toString());
+        if (DBG) Log.d(LOG_TAG, "Displaying ERI " + ret.toString());
         return ret;
     }
 
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
index d17468c..165d583 100755
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -424,12 +424,9 @@
         return (status << 16);
     }
 
-    /**
-     *  Note: This function is a GSM specific functionality which is not supported in CDMA mode.
-     */
+    /** Return true iff the bearer data message type is DELIVERY_ACK. */
     public boolean isStatusReportMessage() {
-        Log.w(LOG_TAG, "isStatusReportMessage: is not supported in CDMA mode.");
-        return false;
+        return (mBearerData.messageType == BearerData.MESSAGE_TYPE_DELIVERY_ACK);
     }
 
     /**
@@ -548,17 +545,6 @@
             messageBody = mBearerData.userData.payloadStr;
         }
 
-        // TP-Message-Type-Indicator (See 3GPP2 C.S0015-B, v2, 4.5.1)
-        switch (mBearerData.messageType) {
-        case BearerData.MESSAGE_TYPE_USER_ACK:
-        case BearerData.MESSAGE_TYPE_READ_ACK:
-        case BearerData.MESSAGE_TYPE_DELIVER:
-        case BearerData.MESSAGE_TYPE_DELIVERY_ACK:
-            break;
-        default:
-            throw new RuntimeException("Unsupported message type: " + mBearerData.messageType);
-        }
-
         if (originatingAddress != null) {
             originatingAddress.address = new String(originatingAddress.origBytes);
             if (Config.LOGV) Log.v(LOG_TAG, "SMS originating address: "
@@ -571,11 +557,26 @@
 
         if (Config.LOGD) Log.d(LOG_TAG, "SMS SC timestamp: " + scTimeMillis);
 
-        // TODO(Teleca): do we really want this test to occur only for DELIVERY_ACKs?
-        if ((mBearerData.messageType == BearerData.MESSAGE_TYPE_DELIVERY_ACK) &&
-                (mBearerData.errorClass != BearerData.ERROR_UNDEFINED)) {
-            status = mBearerData.errorClass << 8;
-            status |= mBearerData.messageStatus;
+        // Message Type (See 3GPP2 C.S0015-B, v2, 4.5.1)
+        if (mBearerData.messageType == BearerData.MESSAGE_TYPE_DELIVERY_ACK) {
+            // The BearerData MsgStatus subparameter should only be
+            // included for DELIVERY_ACK messages.  If it occurred for
+            // other messages, it would be unclear what the status
+            // being reported refers to.  The MsgStatus subparameter
+            // is primarily useful to indicate error conditions -- a
+            // message without this subparameter is assumed to
+            // indicate successful delivery (status == 0).
+            if (! mBearerData.messageStatusSet) {
+                Log.d(LOG_TAG, "DELIVERY_ACK message without msgStatus (" +
+                        (userData == null ? "also missing" : "does have") +
+                        " userData).");
+                status = 0;
+            } else {
+                status = mBearerData.errorClass << 8;
+                status |= mBearerData.messageStatus;
+            }
+        } else if (mBearerData.messageType != BearerData.MESSAGE_TYPE_DELIVER) {
+            throw new RuntimeException("Unsupported message type: " + mBearerData.messageType);
         }
 
         if (messageBody != null) {
diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
index ac7331e..2fc2e13 100755
--- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
@@ -1099,8 +1099,8 @@
         return mDataConnection.getAllDataConnections();
     }
 
-    public void updateServiceLocation(Message response) {
-        mSST.getLacAndCid(response);
+    public void updateServiceLocation() {
+        mSST.enableSingleLocationUpdate();
     }
 
     public void enableLocationUpdates() {
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 0215ab2..b063e0a 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -150,6 +150,11 @@
     static final String APN_ID = "apn_id";
     private boolean canSetPreferApn = false;
 
+    // for tracking retrys on the default APN
+    private RetryManager mDefaultRetryManager;
+    // for tracking retrys on a secondary APN
+    private RetryManager mSecondaryRetryManager;
+
     BroadcastReceiver mIntentReceiver = new BroadcastReceiver ()
     {
         @Override
@@ -253,6 +258,19 @@
                 mRetryMgr.configure(20, 2000, 1000);
             }
         }
+
+        mDefaultRetryManager = mRetryMgr;
+        mSecondaryRetryManager = new RetryManager();
+
+        if (!mSecondaryRetryManager.configure(SystemProperties.get(
+                "ro.gsm.2nd_data_retry_config"))) {
+            if (!mSecondaryRetryManager.configure(SECONDARY_DATA_RETRY_CONFIG)) {
+                // Should never happen, log an error and default to a simple sequence.
+                Log.e(LOG_TAG, "Could note configure using SECONDARY_DATA_RETRY_CONFIG="
+                        + SECONDARY_DATA_RETRY_CONFIG);
+                mSecondaryRetryManager.configure("max_retries=3, 333, 333, 333");
+            }
+        }
     }
 
     public void dispose() {
@@ -1019,6 +1037,12 @@
     private void reconnectAfterFail(FailCause lastFailCauseCode, String reason) {
         if (state == State.FAILED) {
             if (!mRetryMgr.isRetryNeeded()) {
+                if (!mRequestedApnType.equals(Phone.APN_TYPE_DEFAULT)) {
+                    // if no more retries on a secondary APN attempt, tell the world and revert.
+                    phone.notifyDataConnection(Phone.REASON_APN_FAILED);
+                    onEnableApn(apnTypeToId(mRequestedApnType), APN_DISABLED);
+                    return;
+                }
                 if (mReregisterOnReconnectFailure) {
                     // We've re-registerd once now just retry forever.
                     mRetryMgr.retryForeverUsingLastTimeout();
@@ -1069,7 +1093,16 @@
         sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA, Phone.REASON_SIM_LOADED));
     }
 
+    @Override
     protected void onEnableNewApn() {
+        // change our retry manager to use the appropriate numbers for the new APN
+        if (mRequestedApnType.equals(Phone.APN_TYPE_DEFAULT)) {
+            mRetryMgr = mDefaultRetryManager;
+        } else {
+            mRetryMgr = mSecondaryRetryManager;
+        }
+        mRetryMgr.resetRetryCount();
+
         // TODO:  To support simultaneous PDP contexts, this should really only call
         // cleanUpConnection if it needs to free up a PdpConnection.
         cleanUpConnection(true, Phone.REASON_APN_SWITCHED);
@@ -1189,6 +1222,10 @@
             // No try for permanent failure
             if (cause.isPermanentFail()) {
                 notifyNoData(cause);
+                if (!mRequestedApnType.equals(Phone.APN_TYPE_DEFAULT)) {
+                    phone.notifyDataConnection(Phone.REASON_APN_FAILED);
+                    onEnableApn(apnTypeToId(mRequestedApnType), APN_DISABLED);
+                }
                 return;
             }
 
@@ -1381,9 +1418,7 @@
 
     private void startDelayedRetry(PdpConnection.FailCause cause, String reason) {
         notifyNoData(cause);
-        if (mRequestedApnType == Phone.APN_TYPE_DEFAULT) {
-            reconnectAfterFail(cause, reason);
-        }
+        reconnectAfterFail(cause, reason);
     }
 
     private void setPreferredApn(int pos) {
@@ -1442,10 +1477,6 @@
                 onRecordsLoaded();
                 break;
 
-            case EVENT_ENABLE_NEW_APN:
-                onEnableNewApn();
-                break;
-
             case EVENT_GPRS_DETACHED:
                 onGprsDetached();
                 break;
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
index 65463e5..003899b 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
@@ -314,11 +314,6 @@
         return mDataRoaming;
     }
 
-    public void getLacAndCid(Message onComplete) {
-        cm.getRegistrationState(obtainMessage(
-                        EVENT_GET_LOC_DONE, onComplete));
-    }
-
     public void handleMessage (Message msg) {
         AsyncResult ar;
         int[] ints;
@@ -391,19 +386,13 @@
                             Log.w(LOG_TAG, "error parsing location: " + ex);
                         }
                     }
-
-                    // only update if lac or cid changed
-                    if (cellLoc.getCid() != cid || cellLoc.getLac() != lac) {
-                        cellLoc.setLacAndCid(lac, cid);
-                        phone.notifyLocationChanged();
-                    }
+                    cellLoc.setLacAndCid(lac, cid);
+                    phone.notifyLocationChanged();
                 }
 
-                if (ar.userObj != null) {
-                    AsyncResult.forMessage(((Message) ar.userObj)).exception
-                            = ar.exception;
-                    ((Message) ar.userObj).sendToTarget();
-                }
+                // Release any temporary cell lock, which could have been
+                // aquired to allow a single-shot location update.
+                disableSingleLocationUpdate();
                 break;
 
             case EVENT_POLL_STATE_REGISTRATION:
@@ -451,7 +440,7 @@
                 ar = (AsyncResult) msg.obj;
 
                 if (ar.exception == null) {
-                    getLacAndCid(null);
+                    cm.getRegistrationState(obtainMessage(EVENT_GET_LOC_DONE, null));
                 }
                 break;
 
diff --git a/test-runner/android/test/AndroidTestRunner.java b/test-runner/android/test/AndroidTestRunner.java
index 358b7e9..0f1599a 100644
--- a/test-runner/android/test/AndroidTestRunner.java
+++ b/test-runner/android/test/AndroidTestRunner.java
@@ -18,6 +18,8 @@
 
 import android.app.Instrumentation;
 import android.content.Context;
+import android.os.PerformanceCollector.PerformanceResultsWriter;
+
 import com.google.android.collect.Lists;
 import junit.framework.Test;
 import junit.framework.TestCase;
@@ -39,6 +41,7 @@
 
     private List<TestListener> mTestListeners = Lists.newArrayList();
     private Instrumentation mInstrumentation;
+    private PerformanceResultsWriter mPerfWriter;
 
     @SuppressWarnings("unchecked")
     public void setTestClassName(String testClassName, String testMethodName) {
@@ -162,6 +165,7 @@
         for (TestCase testCase : mTestCases) {
             setContextIfAndroidTestCase(testCase, mContext, testContext);
             setInstrumentationIfInstrumentationTestCase(testCase, mInstrumentation);
+            setPerformanceWriterIfPerformanceTestCase(testCase, mPerfWriter);
             testCase.run(mTestResult);
         }
     }
@@ -184,6 +188,13 @@
         }
     }
 
+    private void setPerformanceWriterIfPerformanceTestCase(
+            Test test, PerformanceResultsWriter writer) {
+        if (PerformanceTestBase.class.isAssignableFrom(test.getClass())) {
+            ((PerformanceTestBase) test).setPerformanceResultsWriter(writer);
+        }
+    }
+
     public void setInstrumentation(Instrumentation instrumentation) {
         mInstrumentation = instrumentation;
     }
@@ -197,6 +208,13 @@
         setInstrumentation(instrumentation);
     }
 
+    /**
+     * {@hide} Pending approval for public API.
+     */
+    public void setPerformanceResultsWriter(PerformanceResultsWriter writer) {
+        mPerfWriter = writer;
+    }
+
     @Override
     protected Class loadSuiteClass(String suiteClassName) throws ClassNotFoundException {
         return mContext.getClassLoader().loadClass(suiteClassName);
diff --git a/test-runner/android/test/InstrumentationTestRunner.java b/test-runner/android/test/InstrumentationTestRunner.java
index 23f0ed4..b9978d6 100644
--- a/test-runner/android/test/InstrumentationTestRunner.java
+++ b/test-runner/android/test/InstrumentationTestRunner.java
@@ -17,17 +17,31 @@
 package android.test;
 
 import static android.test.suitebuilder.TestPredicates.REJECT_PERFORMANCE;
+
+import com.android.internal.util.Predicate;
+
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.os.Bundle;
 import android.os.Debug;
 import android.os.Looper;
+import android.os.Parcelable;
+import android.os.PerformanceCollector;
+import android.os.Process;
+import android.os.SystemClock;
+import android.os.PerformanceCollector.PerformanceResultsWriter;
 import android.test.suitebuilder.TestMethod;
 import android.test.suitebuilder.TestPredicates;
 import android.test.suitebuilder.TestSuiteBuilder;
 import android.util.Log;
 
-import com.android.internal.util.Predicate;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.PrintStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
 
 import junit.framework.AssertionFailedError;
 import junit.framework.Test;
@@ -38,22 +52,13 @@
 import junit.runner.BaseTestRunner;
 import junit.textui.ResultPrinter;
 
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.PrintStream;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.List;
-
-
 /**
  * An {@link Instrumentation} that runs various types of {@link junit.framework.TestCase}s against
  * an Android package (application). Typical usage:
  * <ol>
  * <li>Write {@link junit.framework.TestCase}s that perform unit, functional, or performance tests
  * against the classes in your package.  Typically these are subclassed from:
- *   <ul><li>{@link android.test.ActivityInstrumentationTestCase}</li>
+ *   <ul><li>{@link android.test.ActivityInstrumentationTestCase2}</li>
  *   <li>{@link android.test.ActivityUnitTestCase}</li>
  *   <li>{@link android.test.AndroidTestCase}</li>
  *   <li>{@link android.test.ApplicationTestCase}</li>
@@ -111,13 +116,13 @@
  * <p/>
  * <b>To run in 'log only' mode</b>
  * -e log true
- * This option will load and iterate through all test classes and methods, but will bypass actual 
- * test execution. Useful for quickly obtaining info on the tests to be executed by an 
+ * This option will load and iterate through all test classes and methods, but will bypass actual
+ * test execution. Useful for quickly obtaining info on the tests to be executed by an
  * instrumentation command.
  * <p/>
  * <b>To generate EMMA code coverage:</b>
  * -e coverage true
- * Note: this requires an emma instrumented build. By default, the code coverage results file 
+ * Note: this requires an emma instrumented build. By default, the code coverage results file
  * will be saved in a /data/<app>/coverage.ec file, unless overridden by coverageFile flag (see
  * below)
  * <p/>
@@ -129,11 +134,10 @@
 
 /* (not JavaDoc)
  * Although not necessary in most case, another way to use this class is to extend it and have the
- * derived class return
- * the desired test suite from the {@link #getTestSuite()} method. The test suite returned from this
- * method will be used if no target class is defined in the meta-data or command line argument
- * parameters. If a derived class is used it needs to be added as an instrumentation to the
- * AndroidManifest.xml and the command to run it would look like:
+ * derived class return the desired test suite from the {@link #getTestSuite()} method. The test
+ * suite returned from this method will be used if no target class is defined in the meta-data or
+ * command line argument parameters. If a derived class is used it needs to be added as an
+ * instrumentation to the AndroidManifest.xml and the command to run it would look like:
  * <p/>
  * adb shell am instrument -w com.android.foo/<i>com.android.FooInstrumentationTestRunner</i>
  * <p/>
@@ -155,66 +159,65 @@
     public static final String ARGUMENT_DELAY_MSEC = "delay_msec";
 
     private static final String SMALL_SUITE = "small";
-    private static final String MEDIUM_SUITE = "medium";  
+    private static final String MEDIUM_SUITE = "medium";
     private static final String LARGE_SUITE = "large";
-    
+
     private static final String ARGUMENT_LOG_ONLY = "log";
 
-   
     /**
-     * This constant defines the maximum allowed runtime (in ms) for a test included in the "small" suite. 
-     * It is used to make an educated guess at what suite an unlabeled test belongs.
+     * This constant defines the maximum allowed runtime (in ms) for a test included in the "small"
+     * suite. It is used to make an educated guess at what suite an unlabeled test belongs.
      */
     private static final float SMALL_SUITE_MAX_RUNTIME = 100;
-    
+
     /**
-     * This constant defines the maximum allowed runtime (in ms) for a test included in the "medium" suite. 
-     * It is used to make an educated guess at what suite an unlabeled test belongs.
+     * This constant defines the maximum allowed runtime (in ms) for a test included in the
+     * "medium" suite. It is used to make an educated guess at what suite an unlabeled test belongs.
      */
     private static final float MEDIUM_SUITE_MAX_RUNTIME = 1000;
-    
+
     /**
-     * The following keys are used in the status bundle to provide structured reports to 
-     * an IInstrumentationWatcher. 
+     * The following keys are used in the status bundle to provide structured reports to
+     * an IInstrumentationWatcher.
      */
 
     /**
-     * This value, if stored with key {@link android.app.Instrumentation#REPORT_KEY_IDENTIFIER}, 
+     * This value, if stored with key {@link android.app.Instrumentation#REPORT_KEY_IDENTIFIER},
      * identifies InstrumentationTestRunner as the source of the report.  This is sent with all
      * status messages.
      */
     public static final String REPORT_VALUE_ID = "InstrumentationTestRunner";
     /**
-     * If included in the status or final bundle sent to an IInstrumentationWatcher, this key 
+     * If included in the status or final bundle sent to an IInstrumentationWatcher, this key
      * identifies the total number of tests that are being run.  This is sent with all status
      * messages.
      */
     public static final String REPORT_KEY_NUM_TOTAL = "numtests";
     /**
-     * If included in the status or final bundle sent to an IInstrumentationWatcher, this key 
+     * If included in the status or final bundle sent to an IInstrumentationWatcher, this key
      * identifies the sequence number of the current test.  This is sent with any status message
      * describing a specific test being started or completed.
      */
     public static final String REPORT_KEY_NUM_CURRENT = "current";
     /**
-     * If included in the status or final bundle sent to an IInstrumentationWatcher, this key 
+     * If included in the status or final bundle sent to an IInstrumentationWatcher, this key
      * identifies the name of the current test class.  This is sent with any status message
      * describing a specific test being started or completed.
      */
     public static final String REPORT_KEY_NAME_CLASS = "class";
     /**
-     * If included in the status or final bundle sent to an IInstrumentationWatcher, this key 
+     * If included in the status or final bundle sent to an IInstrumentationWatcher, this key
      * identifies the name of the current test.  This is sent with any status message
      * describing a specific test being started or completed.
      */
     public static final String REPORT_KEY_NAME_TEST = "test";
     /**
-     * If included in the status or final bundle sent to an IInstrumentationWatcher, this key 
+     * If included in the status or final bundle sent to an IInstrumentationWatcher, this key
      * reports the run time in seconds of the current test.
      */
     private static final String REPORT_KEY_RUN_TIME = "runtime";
     /**
-     * If included in the status or final bundle sent to an IInstrumentationWatcher, this key 
+     * If included in the status or final bundle sent to an IInstrumentationWatcher, this key
      * reports the guessed suite assignment for the current test.
      */
     private static final String REPORT_KEY_SUITE_ASSIGNMENT = "suiteassignment";
@@ -224,6 +227,19 @@
      */
     private static final String REPORT_KEY_COVERAGE_PATH = "coverageFilePath";
     /**
+     * If included in the status or final bundle sent to an IInstrumentationWatcher, this key
+     * reports the cpu time in milliseconds of the current test.
+     */
+    private static final String REPORT_KEY_PERF_CPU_TIME =
+        "performance." + PerformanceCollector.METRIC_KEY_CPU_TIME;
+    /**
+     * If included in the status or final bundle sent to an IInstrumentationWatcher, this key
+     * reports the run time in milliseconds of the current test.
+     */
+    private static final String REPORT_KEY_PERF_EXECUTION_TIME =
+        "performance." + PerformanceCollector.METRIC_KEY_EXECUTION_TIME;
+
+    /**
      * The test is starting.
      */
     public static final int REPORT_VALUE_RESULT_START = 1;
@@ -240,15 +256,15 @@
      */
     public static final int REPORT_VALUE_RESULT_FAILURE = -2;
     /**
-     * If included in the status bundle sent to an IInstrumentationWatcher, this key 
-     * identifies a stack trace describing an error or failure.  This is sent with any status 
+     * If included in the status bundle sent to an IInstrumentationWatcher, this key
+     * identifies a stack trace describing an error or failure.  This is sent with any status
      * message describing a specific test being completed.
      */
     public static final String REPORT_KEY_STACK = "stack";
 
     // Default file name for code coverage
     private static final String DEFAULT_COVERAGE_FILE_NAME = "coverage.ec";
-    
+
     private static final String LOG_TAG = "InstrumentationTestRunner";
 
     private final Bundle mResults = new Bundle();
@@ -316,7 +332,7 @@
                 if (testSuite != null) {
                     testSuiteBuilder.addTestSuite(testSuite);
                 } else {
-                    // no package or class bundle arguments were supplied, and no test suite 
+                    // no package or class bundle arguments were supplied, and no test suite
                     // provided so add all tests in application
                     testSuiteBuilder.includePackages("");
                 }
@@ -324,7 +340,7 @@
         } else {
             parseTestClasses(testClassesArg, testSuiteBuilder);
         }
-        
+
         testSuiteBuilder.addRequirements(getBuilderRequirements());
 
         mTestRunner = getAndroidTestRunner();
@@ -336,8 +352,10 @@
         if (mSuiteAssignmentMode) {
             mTestRunner.addTestListener(new SuiteAssignmentPrinter());
         } else {
+            WatcherResultPrinter resultPrinter = new WatcherResultPrinter(mTestCount);
             mTestRunner.addTestListener(new TestPrinter("TestRunner", false));
-            mTestRunner.addTestListener(new WatcherResultPrinter(mTestCount));
+            mTestRunner.addTestListener(resultPrinter);
+            mTestRunner.setPerformanceResultsWriter(resultPrinter);
         }
         start();
     }
@@ -347,7 +365,8 @@
     }
 
     /**
-     * Parses and loads the specified set of test classes 
+     * Parses and loads the specified set of test classes
+     *
      * @param testClassArg - comma-separated list of test classes and methods
      * @param testSuiteBuilder - builder to add tests to
      */
@@ -360,8 +379,9 @@
 
     /**
      * Parse and load the given test class and, optionally, method
-     * @param testClassName - full package name of test class and optionally method to add. Expected
-     *   format: com.android.TestClass#testMethod
+     *
+     * @param testClassName - full package name of test class and optionally method to add.
+     *        Expected format: com.android.TestClass#testMethod
      * @param testSuiteBuilder - builder to add tests to
      */
     private void parseTestClass(String testClassName, TestSuiteBuilder testSuiteBuilder) {
@@ -372,8 +392,7 @@
             testMethodName = testClassName.substring(methodSeparatorIndex + 1);
             testClassName = testClassName.substring(0, methodSeparatorIndex);
         }
-        testSuiteBuilder.addTestClassByName(testClassName, testMethodName, 
-                getTargetContext());
+        testSuiteBuilder.addTestClassByName(testClassName, testMethodName, getTargetContext());
     }
 
     protected AndroidTestRunner getAndroidTestRunner() {
@@ -384,12 +403,12 @@
         String tagString = arguments.getString(tag);
         return tagString != null && Boolean.parseBoolean(tagString);
     }
-    
+
     /*
      * Returns the size predicate object, corresponding to the "size" argument value.
      */
     private Predicate<TestMethod> getSizePredicateFromArg(String sizeArg) {
-     
+
         if (SMALL_SUITE.equals(sizeArg)) {
             return TestPredicates.SELECT_SMALL;
         } else if (MEDIUM_SUITE.equals(sizeArg)) {
@@ -400,11 +419,11 @@
             return null;
         }
     }
-  
+
     @Override
     public void onStart() {
         Looper.prepare();
-        
+
         if (mJustCount) {
             mResults.putString(Instrumentation.REPORT_KEY_IDENTIFIER, REPORT_VALUE_ID);
             mResults.putInt(REPORT_KEY_NUM_TOTAL, mTestCount);
@@ -413,30 +432,30 @@
             if (mDebug) {
                 Debug.waitForDebugger();
             }
-    
+
             ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
             PrintStream writer = new PrintStream(byteArrayOutputStream);
             try {
                 StringResultPrinter resultPrinter = new StringResultPrinter(writer);
-    
+
                 mTestRunner.addTestListener(resultPrinter);
-                
+
                 long startTime = System.currentTimeMillis();
                 mTestRunner.runTest();
                 long runTime = System.currentTimeMillis() - startTime;
-    
+
                 resultPrinter.print(mTestRunner.getTestResult(), runTime);
             } finally {
-                mResults.putString(Instrumentation.REPORT_KEY_STREAMRESULT, 
-                        String.format("\nTest results for %s=%s", 
-                        mTestRunner.getTestClassName(), 
+                mResults.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
+                        String.format("\nTest results for %s=%s",
+                        mTestRunner.getTestClassName(),
                         byteArrayOutputStream.toString()));
 
                 if (mCoverage) {
                     generateCoverageReport();
                 }
                 writer.close();
-                
+
                 finish(Activity.RESULT_OK, mResults);
             }
         }
@@ -459,7 +478,7 @@
     public ClassLoader getLoader() {
         return null;
     }
-    
+
     private void generateCoverageReport() {
         // use reflection to call emma dump coverage method, to avoid
         // always statically compiling against emma jar
@@ -467,9 +486,9 @@
         java.io.File coverageFile = new java.io.File(coverageFilePath);
         try {
             Class emmaRTClass = Class.forName("com.vladium.emma.rt.RT");
-            Method dumpCoverageMethod = emmaRTClass.getMethod("dumpCoverageData", 
+            Method dumpCoverageMethod = emmaRTClass.getMethod("dumpCoverageData",
                     coverageFile.getClass(), boolean.class, boolean.class);
-            
+
             dumpCoverageMethod.invoke(null, coverageFile, false, false);
             // output path to generated coverage file so it can be parsed by a test harness if
             // needed
@@ -495,15 +514,14 @@
     private String getCoverageFilePath() {
         if (mCoverageFilePath == null) {
             return getTargetContext().getFilesDir().getAbsolutePath() + File.separator +
-                    DEFAULT_COVERAGE_FILE_NAME;
-         }
-        else {
+                   DEFAULT_COVERAGE_FILE_NAME;
+        } else {
             return mCoverageFilePath;
         }
     }
 
     private void reportEmmaError(Exception e) {
-        reportEmmaError("", e); 
+        reportEmmaError("", e);
     }
 
     private void reportEmmaError(String hint, Exception e) {
@@ -524,30 +542,29 @@
             printFooter(result);
         }
     }
-    
+
     /**
-     * This class sends status reports back to the IInstrumentationWatcher about 
+     * This class sends status reports back to the IInstrumentationWatcher about
      * which suite each test belongs.
      */
-    private class SuiteAssignmentPrinter implements TestListener
-    {
-        
+    private class SuiteAssignmentPrinter implements TestListener {
+
         private Bundle mTestResult;
         private long mStartTime;
         private long mEndTime;
         private boolean mTimingValid;
-        
+
         public SuiteAssignmentPrinter() {
         }
-        
+
         /**
          * send a status for the start of a each test, so long tests can be seen as "running"
          */
         public void startTest(Test test) {
             mTimingValid = true;
-            mStartTime = System.currentTimeMillis(); 
+            mStartTime = System.currentTimeMillis();
         }
-        
+
         /**
          * @see junit.framework.TestListener#addError(Test, Throwable)
          */
@@ -576,7 +593,7 @@
                 runTime = -1;
             } else {
                 runTime = mEndTime - mStartTime;
-                if (runTime < SMALL_SUITE_MAX_RUNTIME 
+                if (runTime < SMALL_SUITE_MAX_RUNTIME
                         && !InstrumentationTestCase.class.isAssignableFrom(test.getClass())) {
                     assignmentSuite = SMALL_SUITE;
                 } else if (runTime < MEDIUM_SUITE_MAX_RUNTIME) {
@@ -588,8 +605,8 @@
             // Clear mStartTime so that we can verify that it gets set next time.
             mStartTime = -1;
 
-            mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT, 
-                    test.getClass().getName() + "#" + ((TestCase) test).getName() 
+            mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
+                    test.getClass().getName() + "#" + ((TestCase) test).getName()
                     + "\nin " + assignmentSuite + " suite\nrunTime: "
                     + String.valueOf(runTime) + "\n");
             mTestResult.putFloat(REPORT_KEY_RUN_TIME, runTime);
@@ -598,36 +615,40 @@
             sendStatus(0, mTestResult);
         }
     }
-    
+
     /**
      * This class sends status reports back to the IInstrumentationWatcher
      */
-    private class WatcherResultPrinter implements TestListener
-    {
+    private class WatcherResultPrinter implements TestListener, PerformanceResultsWriter {
         private final Bundle mResultTemplate;
         Bundle mTestResult;
         int mTestNum = 0;
         int mTestResultCode = 0;
         String mTestClass = null;
-        
+        boolean mIsTimedTest = false;
+        long mCpuTime = 0;
+        long mExecTime = 0;
+
         public WatcherResultPrinter(int numTests) {
             mResultTemplate = new Bundle();
             mResultTemplate.putString(Instrumentation.REPORT_KEY_IDENTIFIER, REPORT_VALUE_ID);
             mResultTemplate.putInt(REPORT_KEY_NUM_TOTAL, numTests);
         }
-        
+
         /**
-         * send a status for the start of a each test, so long tests can be seen as "running"
+         * send a status for the start of a each test, so long tests can be seen
+         * as "running"
          */
         public void startTest(Test test) {
             String testClass = test.getClass().getName();
+            String testName = ((TestCase)test).getName();
             mTestResult = new Bundle(mResultTemplate);
             mTestResult.putString(REPORT_KEY_NAME_CLASS, testClass);
-            mTestResult.putString(REPORT_KEY_NAME_TEST, ((TestCase) test).getName());
+            mTestResult.putString(REPORT_KEY_NAME_TEST, testName);
             mTestResult.putInt(REPORT_KEY_NUM_CURRENT, ++mTestNum);
             // pretty printing
             if (testClass != null && !testClass.equals(mTestClass)) {
-                mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT, 
+                mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
                         String.format("\n%s:", testClass));
                 mTestClass = testClass;
             } else {
@@ -635,9 +656,9 @@
             }
 
             // The delay_msec parameter is normally used to provide buffers of idle time
-            // for power measurement purposes.  To make sure there is a delay before and after
+            // for power measurement purposes. To make sure there is a delay before and after
             // every test in a suite, we delay *after* every test (see endTest below) and also
-            // delay *before* the first test.  So, delay test1 delay test2 delay.
+            // delay *before* the first test. So, delay test1 delay test2 delay.
 
             try {
                 if (mTestNum == 1) Thread.sleep(mDelayMsec);
@@ -647,8 +668,25 @@
 
             sendStatus(REPORT_VALUE_RESULT_START, mTestResult);
             mTestResultCode = 0;
+
+            mIsTimedTest = false;
+            try {
+                // Look for TimedTest annotation on both test class and test
+                // method
+                mIsTimedTest = test.getClass().isAnnotationPresent(TimedTest.class) ||
+                    test.getClass().getMethod(testName).isAnnotationPresent(TimedTest.class);
+            } catch (SecurityException e) {
+                throw new IllegalStateException(e);
+            } catch (NoSuchMethodException e) {
+                throw new IllegalStateException(e);
+            }
+
+            if (mIsTimedTest) {
+                mExecTime = SystemClock.uptimeMillis();
+                mCpuTime = Process.getElapsedCpuTime();
+            }
         }
-        
+
         /**
          * @see junit.framework.TestListener#addError(Test, Throwable)
          */
@@ -656,9 +694,9 @@
             mTestResult.putString(REPORT_KEY_STACK, BaseTestRunner.getFilteredTrace(t));
             mTestResultCode = REPORT_VALUE_RESULT_ERROR;
             // pretty printing
-            mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT, 
-                    String.format("\nError in %s:\n%s", 
-                            ((TestCase) test).getName(), BaseTestRunner.getFilteredTrace(t)));
+            mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
+                String.format("\nError in %s:\n%s",
+                    ((TestCase)test).getName(), BaseTestRunner.getFilteredTrace(t)));
         }
 
         /**
@@ -668,28 +706,68 @@
             mTestResult.putString(REPORT_KEY_STACK, BaseTestRunner.getFilteredTrace(t));
             mTestResultCode = REPORT_VALUE_RESULT_FAILURE;
             // pretty printing
-            mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT, 
-                    String.format("\nFailure in %s:\n%s", 
-                            ((TestCase) test).getName(), BaseTestRunner.getFilteredTrace(t)));
+            mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
+                String.format("\nFailure in %s:\n%s",
+                    ((TestCase)test).getName(), BaseTestRunner.getFilteredTrace(t)));
         }
 
         /**
          * @see junit.framework.TestListener#endTest(Test)
          */
         public void endTest(Test test) {
+            if (mIsTimedTest) {
+                mCpuTime = Process.getElapsedCpuTime() - mCpuTime;
+                mExecTime = SystemClock.uptimeMillis() - mExecTime;
+                mTestResult.putLong(REPORT_KEY_PERF_CPU_TIME, mCpuTime);
+                mTestResult.putLong(REPORT_KEY_PERF_EXECUTION_TIME, mExecTime);
+            }
+
             if (mTestResultCode == 0) {
                 mTestResult.putString(Instrumentation.REPORT_KEY_STREAMRESULT, ".");
             }
             sendStatus(mTestResultCode, mTestResult);
 
-            try {  // Sleep after every test, if specified
+            try { // Sleep after every test, if specified
                 Thread.sleep(mDelayMsec);
             } catch (InterruptedException e) {
                 throw new IllegalStateException(e);
             }
         }
 
+        public void writeBeginSnapshot(String label) {
+            // Do nothing
+        }
+
+        public void writeEndSnapshot(Bundle results) {
+            // Copy all snapshot data fields as type long into mResults, which
+            // is outputted via Instrumentation.finish
+            for (String key : results.keySet()) {
+                mResults.putLong(key, results.getLong(key));
+            }
+        }
+
+        public void writeStartTiming(String label) {
+            // Do nothing
+        }
+
+        public void writeStopTiming(Bundle results) {
+            // Copy results into mTestResult by flattening list of iterations,
+            // which is outputted via WatcherResultPrinter.endTest
+            int i = 0;
+            for (Parcelable p :
+                    results.getParcelableArrayList(PerformanceCollector.METRIC_KEY_ITERATIONS)) {
+                Bundle iteration = (Bundle)p;
+                String index = "performance.iteration" + i + ".";
+                mTestResult.putString(index + PerformanceCollector.METRIC_KEY_LABEL,
+                        iteration.getString(PerformanceCollector.METRIC_KEY_LABEL));
+                mTestResult.putLong(index + PerformanceCollector.METRIC_KEY_CPU_TIME,
+                        iteration.getLong(PerformanceCollector.METRIC_KEY_CPU_TIME));
+                mTestResult.putLong(index + PerformanceCollector.METRIC_KEY_EXECUTION_TIME,
+                        iteration.getLong(PerformanceCollector.METRIC_KEY_EXECUTION_TIME));
+                i++;
+            }
+        }
+
         // TODO report the end of the cycle
-        // TODO report runtime for each test
     }
 }
diff --git a/test-runner/android/test/PerformanceTestBase.java b/test-runner/android/test/PerformanceTestBase.java
index 93ac90c..572a9b8 100644
--- a/test-runner/android/test/PerformanceTestBase.java
+++ b/test-runner/android/test/PerformanceTestBase.java
@@ -16,13 +16,95 @@
 
 package android.test;
 
-import android.test.PerformanceTestCase;
-import junit.framework.TestCase;
+import android.os.Bundle;
+import android.os.PerformanceCollector;
+import android.os.PerformanceCollector.PerformanceResultsWriter;
+
+import java.lang.reflect.Method;
 
 /**
- * {@hide} Not needed for SDK.
+ * Provides hooks and wrappers to automatically and manually collect and report
+ * performance data in tests.
+ *
+ * {@hide} Pending approval for public API.
  */
-public abstract class PerformanceTestBase extends TestCase implements PerformanceTestCase {
+public class PerformanceTestBase extends InstrumentationTestCase implements PerformanceTestCase {
+
+    private static PerformanceCollector sPerfCollector = new PerformanceCollector();
+    private static int sNumTestMethods = 0;
+    private static int sNumTestMethodsLeft = 0;
+
+    // Count number of tests, used to emulate beforeClass and afterClass from JUnit4
+    public PerformanceTestBase() {
+        if (sNumTestMethods == 0) {
+            Method methods[] = getClass().getMethods();
+            for (Method m : methods) {
+                if (m.getName().startsWith("test")) {
+                    sNumTestMethods ++;
+                    sNumTestMethodsLeft ++;
+                }
+            }
+        }
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        // @beforeClass
+        // Will skew timing measured by TestRunner, but not by PerformanceCollector
+        if (sNumTestMethodsLeft == sNumTestMethods) {
+            sPerfCollector.beginSnapshot(this.getClass().getName());
+        }
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        // @afterClass
+        // Will skew timing measured by TestRunner, but not by PerformanceCollector
+        if (--sNumTestMethodsLeft == 0) {
+            sPerfCollector.endSnapshot();
+        }
+        super.tearDown();
+    }
+
+    public void setPerformanceResultsWriter(PerformanceResultsWriter writer) {
+        sPerfCollector.setPerformanceResultsWriter(writer);
+    }
+
+    /**
+     * @see PerformanceCollector#beginSnapshot(String)
+     */
+    protected void beginSnapshot(String label) {
+        sPerfCollector.beginSnapshot(label);
+    }
+
+    /**
+     * @see PerformanceCollector#endSnapshot()
+     */
+    protected Bundle endSnapshot() {
+        return sPerfCollector.endSnapshot();
+    }
+
+    /**
+     * @see PerformanceCollector#startTiming(String)
+     */
+    protected void startTiming(String label) {
+        sPerfCollector.startTiming(label);
+    }
+
+    /**
+     * @see PerformanceCollector#addIteration(String)
+     */
+    protected Bundle addIteration(String label) {
+        return sPerfCollector.addIteration(label);
+    }
+
+    /**
+     * @see PerformanceCollector#stopTiming(String)
+     */
+    protected Bundle stopTiming(String label) {
+        return sPerfCollector.stopTiming(label);
+    }
 
     public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
         return 0;
@@ -31,12 +113,4 @@
     public boolean isPerformanceOnly() {
         return true;
     }
-
-    /*
-     * Temporary hack to get some things working again.
-     */
-    public void testRun() {
-        throw new RuntimeException("test implementation not provided");
-    }
 }
-
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/PerformanceCollectorTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/PerformanceCollectorTest.java
new file mode 100644
index 0000000..1a0c2d1
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/PerformanceCollectorTest.java
@@ -0,0 +1,441 @@
+/*
+ * 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.unit_tests.os;
+
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.os.PerformanceCollector;
+import android.os.PerformanceCollector.PerformanceResultsWriter;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Random;
+
+import junit.framework.TestCase;
+
+public class PerformanceCollectorTest extends TestCase {
+
+    private PerformanceCollector mPerfCollector;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mPerfCollector = new PerformanceCollector();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        mPerfCollector = null;
+    }
+
+    public void testBeginSnapshotNoWriter() throws Exception {
+        mPerfCollector.beginSnapshot("testBeginSnapshotNoWriter");
+
+        assertTrue((Long)readPrivateField("mSnapshotCpuTime", mPerfCollector) > 0);
+        assertTrue((Long)readPrivateField("mSnapshotExecTime", mPerfCollector) > 0);
+        Bundle snapshot = (Bundle)readPrivateField("mPerfSnapshot", mPerfCollector);
+        assertNotNull(snapshot);
+        assertEquals(2, snapshot.size());
+    }
+
+    @LargeTest
+    public void testEndSnapshotNoWriter() throws Exception {
+        mPerfCollector.beginSnapshot("testEndSnapshotNoWriter");
+        sleepForRandomLongPeriod();
+        Bundle snapshot = mPerfCollector.endSnapshot();
+
+        verifySnapshotBundle(snapshot);
+    }
+
+    public void testStartTimingNoWriter() throws Exception {
+        mPerfCollector.startTiming("testStartTimingNoWriter");
+
+        assertTrue((Long)readPrivateField("mCpuTime", mPerfCollector) > 0);
+        assertTrue((Long)readPrivateField("mExecTime", mPerfCollector) > 0);
+        Bundle measurement = (Bundle)readPrivateField("mPerfMeasurement", mPerfCollector);
+        assertNotNull(measurement);
+        verifyTimingBundle(measurement, new ArrayList<String>());
+    }
+
+    public void testAddIterationNoWriter() throws Exception {
+        mPerfCollector.startTiming("testAddIterationNoWriter");
+        sleepForRandomTinyPeriod();
+        Bundle iteration = mPerfCollector.addIteration("timing1");
+
+        verifyIterationBundle(iteration, "timing1");
+    }
+
+    public void testStopTimingNoWriter() throws Exception {
+        mPerfCollector.startTiming("testStopTimingNoWriter");
+        sleepForRandomTinyPeriod();
+        mPerfCollector.addIteration("timing2");
+        sleepForRandomTinyPeriod();
+        mPerfCollector.addIteration("timing3");
+        sleepForRandomShortPeriod();
+        Bundle timing = mPerfCollector.stopTiming("timing4");
+
+        ArrayList<String> labels = new ArrayList<String>();
+        labels.add("timing2");
+        labels.add("timing3");
+        labels.add("timing4");
+        verifyTimingBundle(timing, labels);
+    }
+
+    public void testBeginSnapshot() throws Exception {
+        MockPerformanceResultsWriter writer = new MockPerformanceResultsWriter();
+        mPerfCollector.setPerformanceResultsWriter(writer);
+        mPerfCollector.beginSnapshot("testBeginSnapshot");
+
+        assertEquals("testBeginSnapshot", writer.snapshotLabel);
+        assertTrue((Long)readPrivateField("mSnapshotCpuTime", mPerfCollector) > 0);
+        assertTrue((Long)readPrivateField("mSnapshotExecTime", mPerfCollector) > 0);
+        Bundle snapshot = (Bundle)readPrivateField("mPerfSnapshot", mPerfCollector);
+        assertNotNull(snapshot);
+        assertEquals(2, snapshot.size());
+    }
+
+    @LargeTest
+    public void testEndSnapshot() throws Exception {
+        MockPerformanceResultsWriter writer = new MockPerformanceResultsWriter();
+        mPerfCollector.setPerformanceResultsWriter(writer);
+        mPerfCollector.beginSnapshot("testEndSnapshot");
+        sleepForRandomLongPeriod();
+        Bundle snapshot1 = mPerfCollector.endSnapshot();
+        Bundle snapshot2 = writer.snapshotResults;
+
+        assertTrue(snapshot1.equals(snapshot2));
+        verifySnapshotBundle(snapshot1);
+    }
+
+    public void testStartTiming() throws Exception {
+        MockPerformanceResultsWriter writer = new MockPerformanceResultsWriter();
+        mPerfCollector.setPerformanceResultsWriter(writer);
+        mPerfCollector.startTiming("testStartTiming");
+
+        assertEquals("testStartTiming", writer.timingLabel);
+        assertTrue((Long)readPrivateField("mCpuTime", mPerfCollector) > 0);
+        assertTrue((Long)readPrivateField("mExecTime", mPerfCollector) > 0);
+        Bundle measurement = (Bundle)readPrivateField("mPerfMeasurement", mPerfCollector);
+        assertNotNull(measurement);
+        verifyTimingBundle(measurement, new ArrayList<String>());
+    }
+
+    public void testAddIteration() throws Exception {
+        mPerfCollector.startTiming("testAddIteration");
+        sleepForRandomTinyPeriod();
+        Bundle iteration = mPerfCollector.addIteration("timing5");
+
+        verifyIterationBundle(iteration, "timing5");
+    }
+
+    public void testStopTiming() throws Exception {
+        mPerfCollector.startTiming("testStopTiming");
+        sleepForRandomTinyPeriod();
+        mPerfCollector.addIteration("timing6");
+        sleepForRandomTinyPeriod();
+        mPerfCollector.addIteration("timing7");
+        sleepForRandomShortPeriod();
+        Bundle timing = mPerfCollector.stopTiming("timing8");
+
+        ArrayList<String> labels = new ArrayList<String>();
+        labels.add("timing6");
+        labels.add("timing7");
+        labels.add("timing8");
+        verifyTimingBundle(timing, labels);
+    }
+
+    @LargeTest
+    public void testSimpleSequence() throws Exception {
+        MockPerformanceResultsWriter writer = new MockPerformanceResultsWriter();
+        mPerfCollector.setPerformanceResultsWriter(writer);
+        mPerfCollector.beginSnapshot("testSimpleSequence");
+        mPerfCollector.startTiming("testSimpleSequenceTiming");
+        sleepForRandomTinyPeriod();
+        mPerfCollector.addIteration("iteration1");
+        sleepForRandomTinyPeriod();
+        mPerfCollector.addIteration("iteration2");
+        sleepForRandomTinyPeriod();
+        mPerfCollector.addIteration("iteration3");
+        sleepForRandomTinyPeriod();
+        mPerfCollector.addIteration("iteration4");
+        sleepForRandomShortPeriod();
+        Bundle timing = mPerfCollector.stopTiming("iteration5");
+        sleepForRandomLongPeriod();
+        Bundle snapshot1 = mPerfCollector.endSnapshot();
+        Bundle snapshot2 = writer.snapshotResults;
+
+        assertTrue(snapshot1.equals(snapshot2));
+        verifySnapshotBundle(snapshot1);
+
+        ArrayList<String> labels = new ArrayList<String>();
+        labels.add("iteration1");
+        labels.add("iteration2");
+        labels.add("iteration3");
+        labels.add("iteration4");
+        labels.add("iteration5");
+        verifyTimingBundle(timing, labels);
+    }
+
+    @LargeTest
+    public void testLongSequence() throws Exception {
+        MockPerformanceResultsWriter writer = new MockPerformanceResultsWriter();
+        mPerfCollector.setPerformanceResultsWriter(writer);
+        mPerfCollector.beginSnapshot("testLongSequence");
+        mPerfCollector.startTiming("testLongSequenceTiming1");
+        sleepForRandomTinyPeriod();
+        mPerfCollector.addIteration("iteration1");
+        sleepForRandomTinyPeriod();
+        mPerfCollector.addIteration("iteration2");
+        sleepForRandomShortPeriod();
+        Bundle timing1 = mPerfCollector.stopTiming("iteration3");
+        sleepForRandomLongPeriod();
+
+        mPerfCollector.startTiming("testLongSequenceTiming2");
+        sleepForRandomTinyPeriod();
+        mPerfCollector.addIteration("iteration4");
+        sleepForRandomTinyPeriod();
+        mPerfCollector.addIteration("iteration5");
+        sleepForRandomShortPeriod();
+        Bundle timing2 = mPerfCollector.stopTiming("iteration6");
+        sleepForRandomLongPeriod();
+
+        mPerfCollector.startTiming("testLongSequenceTiming3");
+        sleepForRandomTinyPeriod();
+        mPerfCollector.addIteration("iteration7");
+        sleepForRandomTinyPeriod();
+        mPerfCollector.addIteration("iteration8");
+        sleepForRandomShortPeriod();
+        Bundle timing3 = mPerfCollector.stopTiming("iteration9");
+        sleepForRandomLongPeriod();
+
+        mPerfCollector.startTiming("testLongSequenceTiming4");
+        sleepForRandomTinyPeriod();
+        mPerfCollector.addIteration("iteration10");
+        sleepForRandomTinyPeriod();
+        mPerfCollector.addIteration("iteration11");
+        sleepForRandomShortPeriod();
+        Bundle timing4 = mPerfCollector.stopTiming("iteration12");
+        sleepForRandomLongPeriod();
+
+        mPerfCollector.startTiming("testLongSequenceTiming5");
+        sleepForRandomTinyPeriod();
+        mPerfCollector.addIteration("iteration13");
+        sleepForRandomTinyPeriod();
+        mPerfCollector.addIteration("iteration14");
+        sleepForRandomShortPeriod();
+        Bundle timing5 = mPerfCollector.stopTiming("iteration15");
+        sleepForRandomLongPeriod();
+        Bundle snapshot1 = mPerfCollector.endSnapshot();
+        Bundle snapshot2 = writer.snapshotResults;
+
+        assertTrue(snapshot1.equals(snapshot2));
+        verifySnapshotBundle(snapshot1);
+
+        ArrayList<String> labels1 = new ArrayList<String>();
+        labels1.add("iteration1");
+        labels1.add("iteration2");
+        labels1.add("iteration3");
+        verifyTimingBundle(timing1, labels1);
+        ArrayList<String> labels2 = new ArrayList<String>();
+        labels2.add("iteration4");
+        labels2.add("iteration5");
+        labels2.add("iteration6");
+        verifyTimingBundle(timing2, labels2);
+        ArrayList<String> labels3 = new ArrayList<String>();
+        labels3.add("iteration7");
+        labels3.add("iteration8");
+        labels3.add("iteration9");
+        verifyTimingBundle(timing3, labels3);
+        ArrayList<String> labels4 = new ArrayList<String>();
+        labels4.add("iteration10");
+        labels4.add("iteration11");
+        labels4.add("iteration12");
+        verifyTimingBundle(timing4, labels4);
+        ArrayList<String> labels5 = new ArrayList<String>();
+        labels5.add("iteration13");
+        labels5.add("iteration14");
+        labels5.add("iteration15");
+        verifyTimingBundle(timing5, labels5);
+    }
+
+    /*
+     * Verify that snapshotting and timing do not interfere w/ each other,
+     * by staggering calls to snapshot and timing functions.
+     */
+    @LargeTest
+    public void testOutOfOrderSequence() {
+        MockPerformanceResultsWriter writer = new MockPerformanceResultsWriter();
+        mPerfCollector.setPerformanceResultsWriter(writer);
+        mPerfCollector.startTiming("testOutOfOrderSequenceTiming");
+        sleepForRandomShortPeriod();
+        mPerfCollector.beginSnapshot("testOutOfOrderSequenceSnapshot");
+        sleepForRandomShortPeriod();
+        Bundle timing1 = mPerfCollector.stopTiming("timing1");
+        sleepForRandomShortPeriod();
+        Bundle snapshot1 = mPerfCollector.endSnapshot();
+
+        Bundle timing2 = writer.timingResults;
+        Bundle snapshot2 = writer.snapshotResults;
+
+        assertTrue(snapshot1.equals(snapshot2));
+        verifySnapshotBundle(snapshot1);
+
+        assertTrue(timing1.equals(timing2));
+        ArrayList<String> labels = new ArrayList<String>();
+        labels.add("timing1");
+        verifyTimingBundle(timing1, labels);
+    }
+
+    private void sleepForRandomPeriod(int minDuration, int maxDuration) {
+        Random random = new Random();
+        int period = minDuration + random.nextInt(maxDuration - minDuration);
+        int slept = 0;
+        // Generate random positive amount of work, so cpu time is measurable in
+        // milliseconds
+        while (slept < period) {
+            int step = random.nextInt(minDuration/5);
+            try {
+                Thread.sleep(step);
+            } catch (InterruptedException e ) {
+                // eat the exception
+            }
+            slept += step;
+        }
+    }
+
+    private void sleepForRandomTinyPeriod() {
+        sleepForRandomPeriod(25, 50);
+    }
+
+    private void sleepForRandomShortPeriod() {
+        sleepForRandomPeriod(100, 250);
+    }
+
+    private void sleepForRandomLongPeriod() {
+        sleepForRandomPeriod(500, 1000);
+    }
+
+    private void verifySnapshotBundle(Bundle snapshot) {
+        assertTrue("At least 26 metrics collected", 26 <= snapshot.size());
+
+        assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_CPU_TIME));
+        assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_CPU_TIME) > 0);
+        assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_EXECUTION_TIME));
+        assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_EXECUTION_TIME) > 0);
+
+        assertTrue(snapshot.containsKey(
+                PerformanceCollector.METRIC_KEY_PRE_RECEIVED_TRANSACTIONS));
+        assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_PRE_SENT_TRANSACTIONS));
+        assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_RECEIVED_TRANSACTIONS));
+        assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_SENT_TRANSACTIONS));
+        assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_GC_INVOCATION_COUNT));
+
+        assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_JAVA_ALLOCATED));
+        assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_JAVA_ALLOCATED) > 0);
+        assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_JAVA_FREE));
+        assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_JAVA_FREE) > 0);
+        assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_JAVA_PRIVATE_DIRTY));
+        assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_JAVA_PRIVATE_DIRTY) > 0);
+        assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_JAVA_PSS));
+        assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_JAVA_PSS) > 0);
+        assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_JAVA_SHARED_DIRTY));
+        assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_JAVA_SHARED_DIRTY) > 0);
+        assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_JAVA_SIZE));
+        assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_JAVA_SIZE) > 0);
+        assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_NATIVE_ALLOCATED));
+        assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_NATIVE_ALLOCATED) > 0);
+        assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_NATIVE_FREE));
+        assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_NATIVE_FREE) > 0);
+        assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_NATIVE_PRIVATE_DIRTY));
+        assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_NATIVE_PRIVATE_DIRTY) > 0);
+        assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_NATIVE_PSS));
+        assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_NATIVE_PSS) > 0);
+        assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_NATIVE_SHARED_DIRTY));
+        assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_NATIVE_SHARED_DIRTY) > 0);
+        assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_NATIVE_SIZE));
+        assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_NATIVE_SIZE) > 0);
+        assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_GLOBAL_ALLOC_COUNT));
+        assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_GLOBAL_ALLOC_COUNT) > 0);
+        assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_GLOBAL_ALLOC_SIZE));
+        assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_GLOBAL_ALLOC_SIZE) > 0);
+        assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_GLOBAL_FREED_COUNT));
+        assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_GLOBAL_FREED_COUNT) > 0);
+        assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_GLOBAL_FREED_SIZE));
+        assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_GLOBAL_FREED_SIZE) > 0);
+        assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_OTHER_PRIVATE_DIRTY));
+        assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_OTHER_PRIVATE_DIRTY) > 0);
+        assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_OTHER_PSS));
+        assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_OTHER_PSS) > 0);
+        assertTrue(snapshot.containsKey(PerformanceCollector.METRIC_KEY_OTHER_SHARED_DIRTY));
+        assertTrue(snapshot.getLong(PerformanceCollector.METRIC_KEY_OTHER_SHARED_DIRTY) > 0);
+    }
+
+    private void verifyIterationBundle(Bundle iteration, String label) {
+        assertEquals(3, iteration.size());
+        assertTrue(iteration.containsKey(PerformanceCollector.METRIC_KEY_LABEL));
+        assertEquals(label, iteration.getString(PerformanceCollector.METRIC_KEY_LABEL));
+        assertTrue(iteration.containsKey(PerformanceCollector.METRIC_KEY_CPU_TIME));
+        assertTrue(iteration.getLong(PerformanceCollector.METRIC_KEY_CPU_TIME) > 0);
+        assertTrue(iteration.containsKey(PerformanceCollector.METRIC_KEY_EXECUTION_TIME));
+        assertTrue(iteration.getLong(PerformanceCollector.METRIC_KEY_EXECUTION_TIME) > 0);
+    }
+
+    private void verifyTimingBundle(Bundle timing, ArrayList<String> labels) {
+        assertEquals(1, timing.size());
+        assertTrue(timing.containsKey(PerformanceCollector.METRIC_KEY_ITERATIONS));
+        ArrayList<Parcelable> iterations = timing.getParcelableArrayList(
+                PerformanceCollector.METRIC_KEY_ITERATIONS);
+        assertNotNull(iterations);
+        assertEquals(labels.size(), iterations.size());
+        for (int i = 0; i < labels.size(); i ++) {
+            Bundle iteration = (Bundle)iterations.get(i);
+            verifyIterationBundle(iteration, labels.get(i));
+        }
+    }
+
+    private Object readPrivateField(String fieldName, Object object) throws Exception {
+        Field f = object.getClass().getDeclaredField(fieldName);
+        f.setAccessible(true);
+        return f.get(object);
+    }
+
+    private class MockPerformanceResultsWriter implements PerformanceResultsWriter {
+
+        public String snapshotLabel;
+        public Bundle snapshotResults = new Bundle();
+        public String timingLabel;
+        public Bundle timingResults = new Bundle();
+
+        public void writeBeginSnapshot(String label) {
+            snapshotLabel = label;
+        }
+
+        public void writeEndSnapshot(Bundle results) {
+            snapshotResults = results;
+        }
+
+        public void writeStartTiming(String label) {
+            timingLabel = label;
+        }
+
+        public void writeStopTiming(Bundle results) {
+            timingResults = results;
+        }
+    }
+}
diff --git a/tests/CoreTests/android/webkit/CookieTest.java b/tests/CoreTests/android/webkit/CookieTest.java
index ea4422f..5c5a6a8 100644
--- a/tests/CoreTests/android/webkit/CookieTest.java
+++ b/tests/CoreTests/android/webkit/CookieTest.java
@@ -188,6 +188,6 @@
 
         mCookieManager.setCookie(url, "a=d");
         cookie = mCookieManager.getCookie(url + "/wee");
-        assertTrue(cookie.equals("a=b; a=c; a=d"));
+        assertTrue(cookie.equals("a=b; a=d"));
     }
 }
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index fa24a98..9a11404 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -784,6 +784,9 @@
                     mBluetoothA2dp = new BluetoothA2dp(mContext);
                 }
                 checkIsBluetoothPlaying();
+
+                // initialize this after the supplicant is alive
+                setNumAllowedChannels();
                 break;
 
             case EVENT_SUPPLICANT_DISCONNECT: