Merge change 24903 into eclair

* changes:
  Fix some LayoutBridge javadoc.
diff --git a/api/current.xml b/api/current.xml
index fa9ab93..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,30 @@
  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"
@@ -25490,6 +25629,17 @@
  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"
@@ -25536,6 +25686,17 @@
  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"
@@ -25588,11 +25749,55 @@
 <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.intent.action.SCAN_MODE_CHANGED&quot;"
+ value="&quot;android.bluetooth.adapter.action.SCAN_MODE_CHANGED&quot;"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -25603,7 +25808,7 @@
  type="java.lang.String"
  transient="false"
  volatile="false"
- value="&quot;android.bluetooth.intent.action.STATE_CHANGED&quot;"
+ value="&quot;android.bluetooth.adapter.action.STATE_CHANGED&quot;"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -25614,7 +25819,18 @@
  type="int"
  transient="false"
  volatile="false"
- value="-1"
+ 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"
@@ -25625,7 +25841,7 @@
  type="java.lang.String"
  transient="false"
  volatile="false"
- value="&quot;android.bluetooth.intent.extra.PREVIOUS_SCAN_MODE&quot;"
+ value="&quot;android.bluetooth.adapter.extra.PREVIOUS_SCAN_MODE&quot;"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -25636,7 +25852,7 @@
  type="java.lang.String"
  transient="false"
  volatile="false"
- value="&quot;android.bluetooth.intent.extra.PREVIOUS_STATE&quot;"
+ value="&quot;android.bluetooth.adapter.extra.PREVIOUS_STATE&quot;"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -25647,7 +25863,7 @@
  type="java.lang.String"
  transient="false"
  volatile="false"
- value="&quot;android.bluetooth.intent.extra.SCAN_MODE&quot;"
+ value="&quot;android.bluetooth.adapter.extra.SCAN_MODE&quot;"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -25658,7 +25874,7 @@
  type="java.lang.String"
  transient="false"
  volatile="false"
- value="&quot;android.bluetooth.intent.extra.STATE&quot;"
+ value="&quot;android.bluetooth.adapter.extra.STATE&quot;"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -25669,7 +25885,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="51"
+ value="21"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -25680,7 +25896,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="53"
+ value="23"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -25691,7 +25907,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="50"
+ value="20"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -25702,7 +25918,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="40"
+ value="10"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -25713,7 +25929,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="42"
+ value="12"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -25724,7 +25940,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="43"
+ value="13"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -25735,7 +25951,900 @@
  type="int"
  transient="false"
  volatile="false"
- value="41"
+ 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"
@@ -25753,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"
@@ -25790,6 +26921,28 @@
  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"
@@ -25801,6 +26954,17 @@
  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"
@@ -25816,11 +26980,187 @@
 <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="-1"
+ 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"
diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp
index 3c2dc2b..f425f6b 100644
--- a/camera/libcameraservice/CameraService.cpp
+++ b/camera/libcameraservice/CameraService.cpp
@@ -1101,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 4751580..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/amr-wb" : "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);
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/SearchDialog.java b/core/java/android/app/SearchDialog.java
index f474f06..75e4669 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -1137,6 +1137,11 @@
         String action = mGlobalSearchMode ? Intent.ACTION_WEB_SEARCH : Intent.ACTION_SEARCH;
         Intent intent = createIntent(action, null, null, query, null,
                 actionKey, actionMsg);
+        // Allow GlobalSearch to log and create shortcut for searches launched by
+        // the search button, enter key or an action key.
+        if (mGlobalSearchMode) {
+            mSuggestionsAdapter.reportSearch(query);
+        }
         launchIntent(intent);
     }
     
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 7e6efec..3a14f6f 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
@@ -1350,6 +1350,14 @@
          * When the threshold received in {@link #POST_REFRESH_RECEIVE_DISPLAY_NOTIFY} is displayed.
          */
         public final static int THRESH_HIT = 3;
+
+        /**
+         * When a search is started without using a suggestion.
+         */
+        public final static int SEARCH = 4;
+        public final static String SEARCH_SEND_MAX_DISPLAY_POS
+                = "DialogCursorProtocol.SEARCH.sendDisplayPosition";
+        public final static String SEARCH_SEND_QUERY = "DialogCursorProtocol.SEARCH.query";
     }
 
     /**
@@ -2060,4 +2068,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/app/SuggestionsAdapter.java b/core/java/android/app/SuggestionsAdapter.java
index 90f8c50..8730288 100644
--- a/core/java/android/app/SuggestionsAdapter.java
+++ b/core/java/android/app/SuggestionsAdapter.java
@@ -290,7 +290,7 @@
      */
     void callCursorOnClick(Cursor cursor, int position) {
         if (!mGlobalSearchMode) return;
-        final Bundle request = new Bundle(1);
+        final Bundle request = new Bundle(3);
         request.putInt(DialogCursorProtocol.METHOD, DialogCursorProtocol.CLICK);
         request.putInt(DialogCursorProtocol.CLICK_SEND_POSITION, position);
         request.putInt(DialogCursorProtocol.CLICK_SEND_MAX_DISPLAY_POS, mMaxDisplayed);
@@ -301,6 +301,23 @@
     }
 
     /**
+     * Tell the cursor that a search was started without using a suggestion.
+     *
+     * @param query The search query.
+     */
+    void reportSearch(String query) {
+        if (!mGlobalSearchMode) return;
+        Cursor cursor = getCursor();
+        if (cursor == null) return;
+        final Bundle request = new Bundle(3);
+        request.putInt(DialogCursorProtocol.METHOD, DialogCursorProtocol.SEARCH);
+        request.putString(DialogCursorProtocol.SEARCH_SEND_QUERY, query);
+        request.putInt(DialogCursorProtocol.SEARCH_SEND_MAX_DISPLAY_POS, mMaxDisplayed);
+        // the response is always empty
+        cursor.respond(request);
+    }
+
+    /**
      * Tags the view with cached child view look-ups.
      */
     @Override
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index 060f20e..2e9612a 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -51,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;
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 18f6995..96a927b 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -36,8 +36,6 @@
  *
  * <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";
@@ -49,20 +47,20 @@
      * <p><code>Intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
      * BluetoothAdapter.ERROR)</code>
      */
-    public static final int ERROR = -1;
+    public static final int ERROR = Integer.MIN_VALUE;
 
     /**
      * Broadcast Action: The state of the local Bluetooth adapter has been
      * changed.
      * <p>For example, Bluetooth has been turned on or off.
-     * <p>Contains the extra fields {@link #EXTRA_STATE} and {@link
+     * <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.intent.action.STATE_CHANGED";
+            "android.bluetooth.adapter.action.STATE_CHANGED";
 
     /**
      * Used as an int extra field in {@link #ACTION_STATE_CHANGED}
@@ -73,7 +71,7 @@
      * {@link #STATE_TURNING_OFF},
      */
     public static final String EXTRA_STATE =
-            "android.bluetooth.intent.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:
@@ -83,39 +81,39 @@
      * {@link #STATE_TURNING_OFF},
      */
     public static final String EXTRA_PREVIOUS_STATE =
-            "android.bluetooth.intent.extra.PREVIOUS_STATE";
+            "android.bluetooth.adapter.extra.PREVIOUS_STATE";
 
     /**
      * Indicates the local Bluetooth adapter is off.
      */
-    public static final int STATE_OFF = 40;
+    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 = 41;
+    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 = 42;
+    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 = 43;
+    public static final int STATE_TURNING_OFF = 13;
 
     /**
      * Broadcast Action: Indicates the Bluetooth scan mode of the local Adapter
      * has changed.
-     * <p>Contains the extra fields {@link #EXTRA_SCAN_MODE} and {@link
+     * <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.intent.action.SCAN_MODE_CHANGED";
+            "android.bluetooth.adapter.action.SCAN_MODE_CHANGED";
 
     /**
      * Used as an int extra field in {@link #ACTION_SCAN_MODE_CHANGED}
@@ -124,7 +122,7 @@
      * {@link #SCAN_MODE_CONNECTABLE},
      * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE},
      */
-    public static final String EXTRA_SCAN_MODE = "android.bluetooth.intent.extra.SCAN_MODE";
+    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:
@@ -133,37 +131,73 @@
      * {@link #SCAN_MODE_CONNECTABLE_DISCOVERABLE},
      */
     public static final String EXTRA_PREVIOUS_SCAN_MODE =
-            "android.bluetooth.intent.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 = 50;
+    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 = 51;
+    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 = 53;
+    public static final int SCAN_MODE_CONNECTABLE_DISCOVERABLE = 23;
 
-    /** 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;
+
+    /**
+     * 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;
 
@@ -182,7 +216,8 @@
      * 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.
      *
@@ -380,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();
@@ -388,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();
@@ -404,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 {
@@ -511,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 1ab4389..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,8 +40,6 @@
  * 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";
@@ -48,37 +48,209 @@
      * 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>
+     * <p><code>Intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
+     * BluetoothDevice.ERROR)</code>
      */
-    public static final int ERROR = -1;
+    public static final int ERROR = Integer.MIN_VALUE;
 
-    /** 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;
+    /**
+     * 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";
 
-    /** 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 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
@@ -94,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;
@@ -107,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 */
 
@@ -135,7 +316,7 @@
             }
         }
 
-        if (!checkBluetoothAddress(address)) {
+        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
             throw new IllegalArgumentException(address + " is not a valid Bluetooth address");
         }
 
@@ -216,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 {
@@ -234,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 {
@@ -245,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 {
@@ -260,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:
-     * BOND_*
-     * ERROR
-     *
-     * @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 BluetoothDevice.ERROR;
+        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;
     }
 
     /**
@@ -305,14 +503,6 @@
     }
 
     /** @hide */
-    public int getBluetoothClass() {
-        try {
-            return sService.getRemoteClass(mAddress);
-        } catch (RemoteException e) {Log.e(TAG, "", e);}
-        return BluetoothDevice.ERROR;
-    }
-
-    /** @hide */
      public String[] getUuids() {
         try {
             return sService.getRemoteUuids(mAddress);
@@ -433,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/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 8de19f5..0000000
--- a/core/java/android/bluetooth/BluetoothIntent.java
+++ /dev/null
@@ -1,154 +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;
-
-/**
- * Bluetooth API constants.
- *
- * TODO: Deprecate this class
- * @hide
- */
-public interface BluetoothIntent {
-    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 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";
-
-    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-    public static final String NAME_CHANGED_ACTION  =
-        "android.bluetooth.intent.action.NAME_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/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/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/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 a24e0d21..9c687e2 100644
--- a/core/java/android/server/BluetoothA2dpService.java
+++ b/core/java/android/server/BluetoothA2dpService.java
@@ -25,7 +25,6 @@
 import android.bluetooth.BluetoothA2dp;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothIntent;
 import android.bluetooth.BluetoothUuid;
 import android.bluetooth.IBluetoothA2dp;
 import android.content.BroadcastReceiver;
@@ -79,7 +78,7 @@
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
             BluetoothDevice device =
-                    intent.getParcelableExtra(BluetoothIntent.DEVICE);
+                    intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
             if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
                 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
                                                BluetoothAdapter.ERROR);
@@ -91,19 +90,19 @@
                     onBluetoothDisable();
                     break;
                 }
-            } else if (action.equals(BluetoothIntent.BOND_STATE_CHANGED_ACTION)) {
-                int bondState = intent.getIntExtra(BluetoothIntent.BOND_STATE,
+            } 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,8 +133,8 @@
         mAdapter = (BluetoothAdapter) context.getSystemService(Context.BLUETOOTH_SERVICE);
 
         mIntentFilter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
-        mIntentFilter.addAction(BluetoothIntent.BOND_STATE_CHANGED_ACTION);
-        mIntentFilter.addAction(BluetoothIntent.REMOTE_DEVICE_CONNECTED_ACTION);
+        mIntentFilter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
+        mIntentFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
         mContext.registerReceiver(mReceiver, mIntentFilter);
 
         mAudioDevices = new HashMap<BluetoothDevice, Integer>();
@@ -361,7 +360,7 @@
     public synchronized boolean setSinkPriority(BluetoothDevice device, int priority) {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,
                                                 "Need BLUETOOTH_ADMIN permission");
-        if (!BluetoothDevice.checkBluetoothAddress(device.getAddress())) {
+        if (!BluetoothAdapter.checkBluetoothAddress(device.getAddress())) {
             return false;
         }
         return Settings.Secure.putInt(mContext.getContentResolver(),
@@ -411,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 b5eb9ac..1ed5c49 100644
--- a/core/java/android/server/BluetoothEventLoop.java
+++ b/core/java/android/server/BluetoothEventLoop.java
@@ -17,10 +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.BluetoothIntent;
 import android.bluetooth.BluetoothUuid;
 import android.content.Context;
 import android.content.Intent;
@@ -54,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
@@ -68,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;
@@ -79,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;
             }
         }
     };
@@ -140,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 {
@@ -161,8 +169,19 @@
     }
 
     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);
     }
 
@@ -182,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);
             }
@@ -202,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;
         }
 
@@ -213,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);
@@ -228,6 +247,7 @@
                 addDevice(address, properties);
             }
         }
+        mBluetoothService.getBondState().setBondState(address, BluetoothDevice.BOND_BONDING);
         return;
     }
 
@@ -235,7 +255,7 @@
         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) {
@@ -246,8 +266,8 @@
         }
         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")) {
@@ -274,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]);
@@ -312,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")) {
@@ -350,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")) {
@@ -378,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;
     }
@@ -395,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;
     }
@@ -409,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:
@@ -427,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) {
@@ -464,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 6482c4c..6ce0f5f 100644
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -28,7 +28,6 @@
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothHeadset;
-import android.bluetooth.BluetoothIntent;
 import android.bluetooth.IBluetooth;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
@@ -183,7 +182,7 @@
 
         // 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);
         }
 
@@ -441,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);
@@ -470,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();
         }
@@ -526,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";
@@ -642,9 +641,11 @@
         case BluetoothAdapter.SCAN_MODE_CONNECTABLE:
             pairable = true;
             discoverable = false;
+            break;
         case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE:
             pairable = true;
             discoverable = true;
+            break;
         default:
             Log.w(TAG, "Requested invalid scan mode " + mode);
             return false;
@@ -685,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);
@@ -747,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();
@@ -762,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;
         }
@@ -778,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();
@@ -786,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;
@@ -795,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));
@@ -808,7 +809,7 @@
 
     public synchronized int getBondState(String address) {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
-        if (!BluetoothDevice.checkBluetoothAddress(address)) {
+        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
             return BluetoothDevice.ERROR;
         }
         return mBondState.getBondState(address.toUpperCase());
@@ -898,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;
         }
@@ -915,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;
         }
@@ -939,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;
         }
@@ -961,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");
@@ -982,7 +983,7 @@
      */
     public int getRemoteServiceChannel(String address, String uuid) {
         mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
-        if (!BluetoothDevice.checkBluetoothAddress(address)) {
+        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
             return BluetoothDevice.ERROR;
         }
         return getDeviceServiceChannelNative(getObjectPathFromAddress(address), uuid, 0x0004);
@@ -992,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();
@@ -1017,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();
@@ -1048,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);
@@ -1265,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/vcard/ContactStruct.java b/core/java/android/syncml/pim/vcard/ContactStruct.java
index 687c1b4..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;
@@ -88,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;
@@ -148,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 9823015..a5dd053 100644
--- a/core/java/android/syncml/pim/vcard/VCardComposer.java
+++ b/core/java/android/syncml/pim/vcard/VCardComposer.java
@@ -149,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/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/text/util/Linkify.java b/core/java/android/text/util/Linkify.java
index d61e888..ce25c47 100644
--- a/core/java/android/text/util/Linkify.java
+++ b/core/java/android/text/util/Linkify.java
@@ -208,7 +208,7 @@
 
         if ((mask & WEB_URLS) != 0) {
             gatherLinks(links, text, Regex.WEB_URL_PATTERN,
-                new String[] { "http://", "https://" },
+                new String[] { "http://", "https://", "rtsp://" },
                 sUrlMatchFilter, null);
         }
 
diff --git a/core/java/android/text/util/Regex.java b/core/java/android/text/util/Regex.java
index a349b82..a6844a4 100644
--- a/core/java/android/text/util/Regex.java
+++ b/core/java/android/text/util/Regex.java
@@ -65,7 +65,7 @@
      */
     public static final Pattern WEB_URL_PATTERN
         = Pattern.compile(
-            "((?:(http|https|Http|Https):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)"
+            "((?:(http|https|Http|Https|rtsp|Rtsp):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)"
             + "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_"
             + "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@)?)?"
             + "((?:(?:[a-zA-Z0-9][a-zA-Z0-9\\-]{0,64}\\.)+"   // named host
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 2f17bbc..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/WebView.java b/core/java/android/webkit/WebView.java
index 8446475..c93df74 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2049,12 +2049,9 @@
     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);
+            // to avoid rounding error caused unnecessary scrollbar, use floor
+            return (int) Math.floor(mContentWidth * mActualScale);
         }
     }
 
@@ -2066,18 +2063,8 @@
         if (mDrawHistory) {
             return mHistoryHeight;
         } else {
-            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;
-            }
-            return height;
+            // to avoid rounding error caused unnecessary scrollbar, use floor
+            return (int) Math.floor(mContentHeight * mActualScale);
         }
     }
 
@@ -4582,8 +4569,7 @@
     }
 
     private int computeMaxScrollY() {
-        int maxContentH = contentToViewDimension(mContentHeight)
-                          + getTitleHeight();
+        int maxContentH = computeVerticalScrollRange() + getTitleHeight();
         return Math.max(maxContentH - getHeight(), 0);
     }
 
@@ -5023,8 +5009,8 @@
         int measuredWidth = widthSize;
 
         // Grab the content size from WebViewCore.
-        int contentHeight = Math.round(mContentHeight * mActualScale);
-        int contentWidth = Math.round(mContentWidth * mActualScale);
+        int contentHeight = contentToViewDimension(mContentHeight);
+        int contentWidth = contentToViewDimension(mContentWidth);
 
 //        Log.d(LOGTAG, "------- measure " + heightMode);
 
diff --git a/core/java/android/webkit/WebViewDatabase.java b/core/java/android/webkit/WebViewDatabase.java
index 4e76254..6e10811 100644
--- a/core/java/android/webkit/WebViewDatabase.java
+++ b/core/java/android/webkit/WebViewDatabase.java
@@ -39,7 +39,7 @@
     // log tag
     protected static final String LOGTAG = "webviewdatabase";
 
-    private static final int DATABASE_VERSION = 9;
+    private static final int DATABASE_VERSION = 10;
     // 2 -> 3 Modified Cache table to allow cache of redirects
     // 3 -> 4 Added Oma-Downloads table
     // 4 -> 5 Modified Cache table to support persistent contentLength
@@ -48,6 +48,7 @@
     // 6 -> 7 Change cache localPath from int to String
     // 7 -> 8 Move cache to its own db
     // 8 -> 9 Store both scheme and host when storing passwords
+    // 9 -> 10 Update httpauth table UNIQUE
     private static final int CACHE_DATABASE_VERSION = 3;
     // 1 -> 2 Add expires String
     // 2 -> 3 Add content-disposition
@@ -256,6 +257,20 @@
                     + DATABASE_VERSION + ", which will destroy old data");
         }
         boolean justPasswords = 8 == oldVersion && 9 == DATABASE_VERSION;
+        boolean justAuth = 9 == oldVersion && 10 == DATABASE_VERSION;
+        if (justAuth) {
+            mDatabase.execSQL("DROP TABLE IF EXISTS "
+                    + mTableNames[TABLE_HTTPAUTH_ID]);
+            mDatabase.execSQL("CREATE TABLE " + mTableNames[TABLE_HTTPAUTH_ID]
+                    + " (" + ID_COL + " INTEGER PRIMARY KEY, "
+                    + HTTPAUTH_HOST_COL + " TEXT, " + HTTPAUTH_REALM_COL
+                    + " TEXT, " + HTTPAUTH_USERNAME_COL + " TEXT, "
+                    + HTTPAUTH_PASSWORD_COL + " TEXT," + " UNIQUE ("
+                    + HTTPAUTH_HOST_COL + ", " + HTTPAUTH_REALM_COL
+                    + ") ON CONFLICT REPLACE);");
+            return;
+        }
+
         if (!justPasswords) {
             mDatabase.execSQL("DROP TABLE IF EXISTS "
                     + mTableNames[TABLE_COOKIES_ID]);
@@ -302,8 +317,8 @@
                     + HTTPAUTH_HOST_COL + " TEXT, " + HTTPAUTH_REALM_COL
                     + " TEXT, " + HTTPAUTH_USERNAME_COL + " TEXT, "
                     + HTTPAUTH_PASSWORD_COL + " TEXT," + " UNIQUE ("
-                    + HTTPAUTH_HOST_COL + ", " + HTTPAUTH_REALM_COL + ", "
-                    + HTTPAUTH_USERNAME_COL + ") ON CONFLICT REPLACE);");
+                    + HTTPAUTH_HOST_COL + ", " + HTTPAUTH_REALM_COL
+                    + ") ON CONFLICT REPLACE);");
         }
         // passwords
         mDatabase.execSQL("CREATE TABLE " + mTableNames[TABLE_PASSWORD_ID]
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/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/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/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/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/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/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 7f99553..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();
@@ -206,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 0fc533f..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 *);
 
diff --git a/keystore/java/android/security/Keystore.java b/keystore/java/android/security/Keystore.java
index a706c89..b47ae12 100644
--- a/keystore/java/android/security/Keystore.java
+++ b/keystore/java/android/security/Keystore.java
@@ -60,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;
         }
 
@@ -73,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;
         }
 
@@ -106,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;
         }
@@ -121,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/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index e2b6b51..790a655 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -2014,6 +2014,7 @@
     :   RefBase(),
         mThread(thread),
         mClient(client),
+        mCblk(0),
         mFrameCount(0),
         mState(IDLE),
         mClientTid(-1),
@@ -2162,21 +2163,23 @@
     :   TrackBase(thread, client, sampleRate, format, channelCount, frameCount, 0, sharedBuffer),
     mMute(false), mSharedBuffer(sharedBuffer), mName(-1)
 {
-    sp<ThreadBase> baseThread = thread.promote();
-    if (baseThread != 0) {
-        PlaybackThread *playbackThread = (PlaybackThread *)baseThread.get();
-        mName = playbackThread->getTrackName_l();
+    if (mCblk != NULL) {
+        sp<ThreadBase> baseThread = thread.promote();
+        if (baseThread != 0) {
+            PlaybackThread *playbackThread = (PlaybackThread *)baseThread.get();
+            mName = playbackThread->getTrackName_l();
+        }
+        LOGV("Track constructor name %d, calling thread %d", mName, IPCThreadState::self()->getCallingPid());
+        if (mName < 0) {
+            LOGE("no more track names available");
+        }
+        mVolume[0] = 1.0f;
+        mVolume[1] = 1.0f;
+        mStreamType = streamType;
+        // NOTE: audio_track_cblk_t::frameSize for 8 bit PCM data is based on a sample size of
+        // 16 bit because data is converted to 16 bit before being stored in buffer by AudioTrack
+        mCblk->frameSize = AudioSystem::isLinearPCM(format) ? channelCount * sizeof(int16_t) : sizeof(int8_t);
     }
-    LOGV("Track constructor name %d, calling thread %d", mName, IPCThreadState::self()->getCallingPid());
-    if (mName < 0) {
-        LOGE("no more track names available");
-    }
-    mVolume[0] = 1.0f;
-    mVolume[1] = 1.0f;
-    mStreamType = streamType;
-    // NOTE: audio_track_cblk_t::frameSize for 8 bit PCM data is based on a sample size of
-    // 16 bit because data is converted to 16 bit before being stored in buffer by AudioTrack
-    mCblk->frameSize = AudioSystem::isLinearPCM(format) ? channelCount * sizeof(int16_t) : sizeof(int8_t);
 }
 
 AudioFlinger::PlaybackThread::Track::~Track()
@@ -2390,14 +2393,16 @@
                   channelCount, frameCount, flags, 0),
         mOverflow(false)
 {
-   LOGV("RecordTrack constructor, size %d", (int)mBufferEnd - (int)mBuffer);
-   if (format == AudioSystem::PCM_16_BIT) {
-       mCblk->frameSize = channelCount * sizeof(int16_t);
-   } else if (format == AudioSystem::PCM_8_BIT) {
-       mCblk->frameSize = channelCount * sizeof(int8_t);
-   } else {
-       mCblk->frameSize = sizeof(int8_t);
-   }
+    if (mCblk != NULL) {
+       LOGV("RecordTrack constructor, size %d", (int)mBufferEnd - (int)mBuffer);
+       if (format == AudioSystem::PCM_16_BIT) {
+           mCblk->frameSize = channelCount * sizeof(int16_t);
+       } else if (format == AudioSystem::PCM_8_BIT) {
+           mCblk->frameSize = channelCount * sizeof(int8_t);
+       } else {
+           mCblk->frameSize = sizeof(int8_t);
+       }
+    }
 }
 
 AudioFlinger::RecordThread::RecordTrack::~RecordTrack()
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/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/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/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 665d353..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);
 
     }
@@ -1372,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));
@@ -1395,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;
@@ -1415,8 +1412,6 @@
                         case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
                             device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
                             break;
-                        default:
-                            break;
                         }
                     }
                 }
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index fc39a46..5089157 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -83,6 +83,7 @@
                                 status_t *status)
     {
         Parcel data, reply;
+        sp<IAudioTrack> track;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
         data.writeInt32(pid);
         data.writeInt32(streamType);
@@ -96,12 +97,14 @@
         status_t lStatus = remote()->transact(CREATE_TRACK, data, &reply);
         if (lStatus != NO_ERROR) {
             LOGE("createTrack error: %s", strerror(-lStatus));
+        } else {
+            lStatus = reply.readInt32();
+            track = interface_cast<IAudioTrack>(reply.readStrongBinder());
         }
-        lStatus = reply.readInt32();
         if (status) {
             *status = lStatus;
         }
-        return interface_cast<IAudioTrack>(reply.readStrongBinder());
+        return track;
     }
 
     virtual sp<IAudioRecord> openRecord(
@@ -115,6 +118,7 @@
                                 status_t *status)
     {
         Parcel data, reply;
+        sp<IAudioRecord> record;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
         data.writeInt32(pid);
         data.writeInt32(input);
@@ -123,12 +127,17 @@
         data.writeInt32(channelCount);
         data.writeInt32(frameCount);
         data.writeInt32(flags);
-        remote()->transact(OPEN_RECORD, data, &reply);
-        status_t lStatus = reply.readInt32();
+        status_t lStatus = remote()->transact(OPEN_RECORD, data, &reply);
+        if (lStatus != NO_ERROR) {
+            LOGE("openRecord error: %s", strerror(-lStatus));
+        } else {
+            lStatus = reply.readInt32();
+            record = interface_cast<IAudioRecord>(reply.readStrongBinder());
+        }
         if (status) {
             *status = lStatus;
         }
-        return interface_cast<IAudioRecord>(reply.readStrongBinder());
+        return record;
     }
 
     virtual uint32_t sampleRate(int output) const
diff --git a/media/libmedia/IAudioRecord.cpp b/media/libmedia/IAudioRecord.cpp
index 8fb5d3d..dacf75a 100644
--- a/media/libmedia/IAudioRecord.cpp
+++ b/media/libmedia/IAudioRecord.cpp
@@ -56,9 +56,13 @@
     virtual sp<IMemory> getCblk() const
     {
         Parcel data, reply;
+        sp<IMemory> cblk;
         data.writeInterfaceToken(IAudioRecord::getInterfaceDescriptor());
-        remote()->transact(GET_CBLK, data, &reply);
-        return interface_cast<IMemory>(reply.readStrongBinder());
+        status_t status = remote()->transact(GET_CBLK, data, &reply);
+        if (status == NO_ERROR) {
+            cblk = interface_cast<IMemory>(reply.readStrongBinder());
+        }
+        return cblk;
     }    
 };
 
diff --git a/media/libmedia/IAudioTrack.cpp b/media/libmedia/IAudioTrack.cpp
index 75b861b..7f43347 100644
--- a/media/libmedia/IAudioTrack.cpp
+++ b/media/libmedia/IAudioTrack.cpp
@@ -81,9 +81,13 @@
     virtual sp<IMemory> getCblk() const
     {
         Parcel data, reply;
+        sp<IMemory> cblk;
         data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
-        remote()->transact(GET_CBLK, data, &reply);
-        return interface_cast<IMemory>(reply.readStrongBinder());
+        status_t status = remote()->transact(GET_CBLK, data, &reply);
+        if (status == NO_ERROR) {
+            cblk = interface_cast<IMemory>(reply.readStrongBinder());
+        }
+        return cblk;
     }    
 };
 
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
index 4772aca..8d85ce2 100644
--- a/media/libstagefright/AMRExtractor.cpp
+++ b/media/libstagefright/AMRExtractor.cpp
@@ -22,6 +22,7 @@
 #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>
@@ -66,7 +67,7 @@
     float confidence;
     if (SniffAMR(mDataSource, &mimeType, &confidence)) {
         mInitCheck = OK;
-        mIsWide = (mimeType == "audio/amr-wb");
+        mIsWide = (mimeType == MEDIA_MIMETYPE_AUDIO_AMR_WB);
     }
 }
 
@@ -96,7 +97,10 @@
 // static
 sp<MetaData> AMRExtractor::makeAMRFormat(bool isWide) {
     sp<MetaData> meta = new MetaData;
-    meta->setCString(kKeyMIMEType, isWide ? "audio/amr-wb" : "audio/3gpp");
+    meta->setCString(
+            kKeyMIMEType, isWide ? MEDIA_MIMETYPE_AUDIO_AMR_WB
+                                 : MEDIA_MIMETYPE_AUDIO_AMR_NB);
+
     meta->setInt32(kKeyChannelCount, 1);
     meta->setInt32(kKeySampleRate, isWide ? 16000 : 8000);
 
@@ -221,12 +225,12 @@
     }
 
     if (!memcmp(header, "#!AMR\n", 6)) {
-        *mimeType = "audio/3gpp";
+        *mimeType = MEDIA_MIMETYPE_AUDIO_AMR_NB;
         *confidence = 0.5;
 
         return true;
     } else if (!memcmp(header, "#!AMR-WB\n", 9)) {
-        *mimeType = "audio/amr-wb";
+        *mimeType = MEDIA_MIMETYPE_AUDIO_AMR_WB;
         *confidence = 0.5;
 
         return true;
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index c3a4722..79a32b5 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -2,33 +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/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 433fb18..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,25 +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 "audio/amr-wb";
+            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.");
@@ -499,8 +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))
-                || !strcasecmp("audio/amr-wb", 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;
             }
@@ -746,7 +749,7 @@
     success = mFormat->findInt32(kKeyTimeScale, &mTimescale);
     CHECK(success);
 
-    mIsAVC = !strcasecmp(mime, "video/avc");
+    mIsAVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
 }
 
 MPEG4Source::~MPEG4Source() {
@@ -978,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 d3da889..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>
 
@@ -351,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) {
@@ -528,9 +529,9 @@
             mOwner->writeInt32(1);               // entry count
             if (is_audio) {
                 const char *fourcc = NULL;
-                if (!strcasecmp("audio/3gpp", mime)) {
+                if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) {
                     fourcc = "samr";
-                } else if (!strcasecmp("audio/amr-wb", mime)) {
+                } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
                     fourcc = "sawb";
                 } else {
                     LOGE("Unknown mime type '%s'.", mime);
@@ -555,9 +556,9 @@
                   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);
@@ -590,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
@@ -625,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 8afa8e1..8535f52 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -20,6 +20,7 @@
 
 #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>
@@ -44,12 +45,13 @@
              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, "audio/3gpp")
-            || !strcasecmp(mime, "audio/amr-wb")) {
+    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)
+            || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) {
         return new AMRExtractor(source);
     }
 
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 3ab44b0..d905619 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,42 +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/amr-wb", "OMX.TI.WBAMR.decode" },
-    { "audio/amr-wb", "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/amr-wb", "OMX.TI.WBAMR.encode" },
-    { "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 {
@@ -168,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);
@@ -190,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);
@@ -224,6 +232,16 @@
         quirks |= kRequiresAllocateBufferOnOutputPorts;
     }
 
+    if (!strncmp(componentName, "OMX.TI.", 7)) {
+        // Apparently I must not use OMX_UseBuffer on either input or
+        // output ports on any of the TI components or quote:
+        // "(I) may have unexpected problem (sic) which can be timing related
+        //  and hard to reproduce."
+
+        quirks |= kRequiresAllocateBufferOnInputPorts;
+        quirks |= kRequiresAllocateBufferOnOutputPorts;
+    }
+
     sp<OMXCodec> codec = new OMXCodec(
             omx, node, quirks, createEncoder, mime, componentName,
             source);
@@ -317,13 +335,13 @@
         }
     }
 
-    if (!strcasecmp("audio/3gpp", mime)) {
+    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) {
         codec->setAMRFormat();
     }
-    if (!strcasecmp("audio/amr-wb", mime)) {
+    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
         codec->setAMRWBFormat();
     }
-    if (!strcasecmp("audio/mp4a-latm", mime)) {
+    if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
         int32_t numChannels, sampleRate;
         CHECK(meta->findInt32(kKeyChannelCount, &numChannels));
         CHECK(meta->findInt32(kKeySampleRate, &sampleRate));
@@ -342,7 +360,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;
@@ -424,7 +442,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
@@ -457,7 +475,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));
@@ -467,14 +485,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);
@@ -527,7 +545,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);
 
@@ -543,14 +561,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);
@@ -669,7 +687,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;
@@ -677,13 +698,20 @@
     };
 
     static const MimeToRole kMimeToRole[] = {
-        { "audio/mpeg", "audio_decoder.mp3", "audio_encoder.mp3" },
-        { "audio/3gpp", "audio_decoder.amrnb", "audio_encoder.amrnb" },
-        { "audio/amr-wb", "audio_decoder.amrwb", "audio_encoder.amrwb" },
-        { "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 =
@@ -691,7 +719,7 @@
 
     size_t i;
     for (i = 0; i < kNumMimeToRole; ++i) {
-        if (!strcasecmp(mMIME, kMimeToRole[i].mime)) {
+        if (!strcasecmp(mime, kMimeToRole[i].mime)) {
             break;
         }
     }
@@ -701,12 +729,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);
 
@@ -715,8 +741,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) {
@@ -725,6 +751,10 @@
     }
 }
 
+void OMXCodec::setComponentRole() {
+    setComponentRole(mOMX, mNode, mIsEncoder, mMIME);
+}
+
 OMXCodec::~OMXCodec() {
     CHECK(mState == LOADED || mState == ERROR);
 
@@ -820,8 +850,8 @@
                     mNode, portIndex, mem, &buffer);
         } else if (portIndex == kPortIndexOutput
                 && (mQuirks & kRequiresAllocateBufferOnOutputPorts)) {
-            err = mOMX->allocate_buffer(
-                    mNode, portIndex, def.nBufferSize, &buffer);
+            err = mOMX->allocate_buffer_with_backup(
+                    mNode, portIndex, mem, &buffer);
         } else {
             err = mOMX->use_buffer(mNode, portIndex, mem, &buffer);
         }
@@ -1358,7 +1388,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 };
@@ -2249,7 +2279,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);
@@ -2282,7 +2312,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
@@ -2305,17 +2336,20 @@
 
                 if (amr.eAMRBandMode >= OMX_AUDIO_AMRBandModeNB0
                     && amr.eAMRBandMode <= OMX_AUDIO_AMRBandModeNB7) {
-                    mOutputFormat->setCString(kKeyMIMEType, "audio/3gpp");
+                    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, "audio/amr-wb");
+                    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.");
             }
@@ -2327,13 +2361,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.");
             }
@@ -2361,4 +2399,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/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 f3127f3..da64e54 100644
--- a/services/java/com/android/server/status/StatusBarPolicy.java
+++ b/services/java/com/android/server/status/StatusBarPolicy.java
@@ -20,7 +20,6 @@
 import android.bluetooth.BluetoothA2dp;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothHeadset;
-import android.bluetooth.BluetoothIntent;
 import android.bluetooth.BluetoothPbap;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -362,8 +361,8 @@
                 onBatteryOkay(intent);
             }
             else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED) ||
-                    action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION) ||
-                    action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION) ||
+                    action.equals(BluetoothHeadset.ACTION_STATE_CHANGED) ||
+                    action.equals(BluetoothA2dp.ACTION_SINK_STATE_CHANGED) ||
                     action.equals(BluetoothPbap.PBAP_STATE_CHANGED_ACTION)) {
                 updateBluetooth(intent);
             }
@@ -507,8 +506,8 @@
         filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
         filter.addAction(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
         filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
-        filter.addAction(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION);
-        filter.addAction(BluetoothA2dp.SINK_STATE_CHANGED_ACTION);
+        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);
@@ -1074,11 +1073,11 @@
         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(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION)) {
-            mBluetoothHeadsetState = intent.getIntExtra(BluetoothIntent.HEADSET_STATE,
+        } 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 5203d3f..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";
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/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/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/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/DumpRenderTree/assets/run_page_cycler.py b/tests/DumpRenderTree/assets/run_page_cycler.py
index 2325047..4a68d72 100755
--- a/tests/DumpRenderTree/assets/run_page_cycler.py
+++ b/tests/DumpRenderTree/assets/run_page_cycler.py
@@ -59,8 +59,18 @@
   run_load_test_cmd = run_load_test_cmd_prefix + " -e class com.android.dumprendertree.LoadTestsAutoTest#runPageCyclerTest -e path \"" + path + "\" -e timeout " + timeout_ms + run_load_test_cmd_postfix
 
   (adb_output, adb_error) = subprocess.Popen(run_load_test_cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
-  if adb_output.find('INSTRUMENTATION_FAILED') != -1 or \
-      adb_output.find('Process crashed.') != -1:
+  fail_flag = False
+  for line in adb_output.splitlines():
+    line = line.strip()
+    if line.find('INSTRUMENTATION_CODE') == 0:
+      if not line[22:] == '-1':
+        fail_flag = True
+        break
+    if (line.find('INSTRUMENTATION_FAILED') != -1 or
+        line.find('Process crashed.') != -1):
+      fail_flag = True
+      break
+  if fail_flag:
     logging.error("Error happened : " + adb_output)
     sys.exit(1)
 
@@ -80,7 +90,6 @@
   shell_cmd_str = adb_cmd + " pull " + result_file + " " + results_dir
   adb_output = subprocess.Popen(shell_cmd_str, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
   logging.info(adb_output)
-    
   logging.info("Results are stored under: " + results_dir + "/load_test_result.txt\n")
 
 if '__main__' == __name__:
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: