Merge "New RS types test for checking compilation."
diff --git a/api/current.xml b/api/current.xml
index 4c7df55..ed9ed53 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -1255,6 +1255,17 @@
  visibility="public"
 >
 </field>
+<field name="WRITE_MEDIA_STORAGE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.permission.WRITE_MEDIA_STORAGE&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="WRITE_SECURE_SETTINGS"
  type="java.lang.String"
  transient="false"
@@ -1894,7 +1905,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843549"
+ value="16843550"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -1905,7 +1916,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843548"
+ value="16843549"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -1916,7 +1927,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843550"
+ value="16843551"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -4717,6 +4728,17 @@
  visibility="public"
 >
 </field>
+<field name="homeAsUpIndicator"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843548"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="horizontalDivider"
  type="int"
  transient="false"
@@ -9286,7 +9308,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843552"
+ value="16843553"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -9297,7 +9319,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16843551"
+ value="16843552"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -14253,7 +14275,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16973947"
+ value="16973949"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -14264,7 +14286,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16973948"
+ value="16973950"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -14414,6 +14436,17 @@
  visibility="public"
 >
 </field>
+<field name="Theme_Holo_Extended"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16973943"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="Theme_Holo_Light"
  type="int"
  transient="false"
@@ -14436,6 +14469,17 @@
  visibility="public"
 >
 </field>
+<field name="Theme_Holo_Light_Extended"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16973944"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="Theme_Holo_NoActionBar"
  type="int"
  transient="false"
@@ -14737,7 +14781,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16973946"
+ value="16973948"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -14748,7 +14792,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16973945"
+ value="16973947"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -14902,7 +14946,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16973949"
+ value="16973951"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -14968,7 +15012,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16973943"
+ value="16973945"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -15023,7 +15067,7 @@
  type="int"
  transient="false"
  volatile="false"
- value="16973944"
+ value="16973946"
  static="true"
  final="true"
  deprecated="not deprecated"
@@ -19449,6 +19493,17 @@
  visibility="public"
 >
 </method>
+<method name="getNavigationItemCount"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getNavigationMode"
  return="int"
  abstract="true"
@@ -19460,6 +19515,17 @@
  visibility="public"
 >
 </method>
+<method name="getSelectedNavigationIndex"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getSelectedNavigationItem"
  return="int"
  abstract="true"
@@ -19467,7 +19533,7 @@
  synchronized="false"
  static="false"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </method>
@@ -19493,6 +19559,19 @@
  visibility="public"
 >
 </method>
+<method name="getTabAt"
+ return="android.app.ActionBar.Tab"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="index" type="int">
+</parameter>
+</method>
 <method name="getTitle"
  return="java.lang.CharSequence"
  abstract="true"
@@ -19537,6 +19616,17 @@
  visibility="public"
 >
 </method>
+<method name="removeAllTabs"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="removeTab"
  return="void"
  abstract="true"
@@ -19596,12 +19686,40 @@
  synchronized="false"
  static="false"
  final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
+<parameter name="view" type="android.view.View">
+</parameter>
+</method>
+<method name="setCustomView"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
  deprecated="not deprecated"
  visibility="public"
 >
 <parameter name="view" type="android.view.View">
 </parameter>
 </method>
+<method name="setCustomView"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="view" type="android.view.View">
+</parameter>
+<parameter name="layoutParams" type="android.app.ActionBar.LayoutParams">
+</parameter>
+</method>
 <method name="setDisplayOptions"
  return="void"
  abstract="true"
@@ -19637,7 +19755,7 @@
  synchronized="false"
  static="false"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 <parameter name="adapter" type="android.widget.SpinnerAdapter">
@@ -19652,7 +19770,7 @@
  synchronized="false"
  static="false"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 <parameter name="adapter" type="android.widget.SpinnerAdapter">
@@ -19662,6 +19780,34 @@
 <parameter name="defaultSelectedPosition" type="int">
 </parameter>
 </method>
+<method name="setListNavigationCallbacks"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="adapter" type="android.widget.SpinnerAdapter">
+</parameter>
+<parameter name="callback" type="android.app.ActionBar.NavigationCallback">
+</parameter>
+</method>
+<method name="setNavigationMode"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="mode" type="int">
+</parameter>
+</method>
 <method name="setSelectedNavigationItem"
  return="void"
  abstract="true"
@@ -19682,7 +19828,7 @@
  synchronized="false"
  static="false"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </method>
@@ -19719,7 +19865,7 @@
  synchronized="false"
  static="false"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </method>
@@ -19764,6 +19910,39 @@
  type="int"
  transient="false"
  volatile="false"
+ value="4096"
+ static="true"
+ final="true"
+ deprecated="deprecated"
+ visibility="public"
+>
+</field>
+<field name="DISPLAY_HOME_AS_UP"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="DISPLAY_SHOW_CUSTOM"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="DISPLAY_SHOW_HOME"
+ type="int"
+ transient="false"
+ volatile="false"
  value="2"
  static="true"
  final="true"
@@ -19771,6 +19950,17 @@
  visibility="public"
 >
 </field>
+<field name="DISPLAY_SHOW_TITLE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="8"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="DISPLAY_USE_LOGO"
  type="int"
  transient="false"
@@ -19782,18 +19972,18 @@
  visibility="public"
 >
 </field>
-<field name="NAVIGATION_MODE_CUSTOM"
+<field name="NAVIGATION_MODE_DROPDOWN_LIST"
  type="int"
  transient="false"
  volatile="false"
- value="3"
+ value="1"
  static="true"
  final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </field>
-<field name="NAVIGATION_MODE_DROPDOWN_LIST"
+<field name="NAVIGATION_MODE_LIST"
  type="int"
  transient="false"
  volatile="false"
@@ -19827,6 +20017,93 @@
 >
 </field>
 </class>
+<class name="ActionBar.LayoutParams"
+ extends="android.view.ViewGroup.MarginLayoutParams"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="ActionBar.LayoutParams"
+ type="android.app.ActionBar.LayoutParams"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="c" type="android.content.Context">
+</parameter>
+<parameter name="attrs" type="android.util.AttributeSet">
+</parameter>
+</constructor>
+<constructor name="ActionBar.LayoutParams"
+ type="android.app.ActionBar.LayoutParams"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="width" type="int">
+</parameter>
+<parameter name="height" type="int">
+</parameter>
+</constructor>
+<constructor name="ActionBar.LayoutParams"
+ type="android.app.ActionBar.LayoutParams"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="width" type="int">
+</parameter>
+<parameter name="height" type="int">
+</parameter>
+<parameter name="gravity" type="int">
+</parameter>
+</constructor>
+<constructor name="ActionBar.LayoutParams"
+ type="android.app.ActionBar.LayoutParams"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="gravity" type="int">
+</parameter>
+</constructor>
+<constructor name="ActionBar.LayoutParams"
+ type="android.app.ActionBar.LayoutParams"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="source" type="android.app.ActionBar.LayoutParams">
+</parameter>
+</constructor>
+<constructor name="ActionBar.LayoutParams"
+ type="android.app.ActionBar.LayoutParams"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="source" type="android.view.ViewGroup.LayoutParams">
+</parameter>
+</constructor>
+<field name="gravity"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
 <interface name="ActionBar.NavigationCallback"
  abstract="true"
  static="true"
@@ -19933,7 +20210,7 @@
 >
 </method>
 <method name="setCustomView"
- return="void"
+ return="android.app.ActionBar.Tab"
  abstract="true"
  native="false"
  synchronized="false"
@@ -19946,7 +20223,7 @@
 </parameter>
 </method>
 <method name="setIcon"
- return="void"
+ return="android.app.ActionBar.Tab"
  abstract="true"
  native="false"
  synchronized="false"
@@ -19959,7 +20236,7 @@
 </parameter>
 </method>
 <method name="setTabListener"
- return="void"
+ return="android.app.ActionBar.Tab"
  abstract="true"
  native="false"
  synchronized="false"
@@ -19972,7 +20249,7 @@
 </parameter>
 </method>
 <method name="setTag"
- return="void"
+ return="android.app.ActionBar.Tab"
  abstract="true"
  native="false"
  synchronized="false"
@@ -19985,7 +20262,7 @@
 </parameter>
 </method>
 <method name="setText"
- return="void"
+ return="android.app.ActionBar.Tab"
  abstract="true"
  native="false"
  synchronized="false"
@@ -26381,6 +26658,17 @@
  visibility="public"
 >
 </field>
+<field name="EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;extra_click_download_ids&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="PAUSED_QUEUED_FOR_WIFI"
  type="int"
  transient="false"
@@ -27340,6 +27628,17 @@
  visibility="public"
 >
 </method>
+<method name="onDestroyOptionsMenu"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="onDestroyView"
  return="void"
  abstract="false"
@@ -49832,6 +50131,17 @@
  visibility="public"
 >
 </field>
+<field name="CATEGORY_HE_DESK_DOCK"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.intent.category.HE_DESK_DOCK&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="CATEGORY_HOME"
  type="java.lang.String"
  transient="false"
@@ -49865,6 +50175,17 @@
  visibility="public"
 >
 </field>
+<field name="CATEGORY_LE_DESK_DOCK"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.intent.category.LE_DESK_DOCK&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="CATEGORY_MONKEY"
  type="java.lang.String"
  transient="false"
@@ -50084,6 +50405,28 @@
  visibility="public"
 >
 </field>
+<field name="EXTRA_DOCK_STATE_HE_DESK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="EXTRA_DOCK_STATE_LE_DESK"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="EXTRA_DOCK_STATE_UNDOCKED"
  type="int"
  transient="false"
@@ -62838,7 +63181,7 @@
  synchronized="false"
  static="false"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 </method>
@@ -83323,6 +83666,17 @@
  visibility="public"
 >
 </method>
+<method name="getColor"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getOpacity"
  return="int"
  abstract="false"
@@ -83347,6 +83701,19 @@
 <parameter name="alpha" type="int">
 </parameter>
 </method>
+<method name="setColor"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="color" type="int">
+</parameter>
+</method>
 <method name="setColorFilter"
  return="void"
  abstract="false"
@@ -144771,6 +145138,23 @@
 <parameter name="key" type="java.lang.CharSequence">
 </parameter>
 </method>
+<method name="finishPreferencePanel"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="caller" type="android.app.Fragment">
+</parameter>
+<parameter name="resultCode" type="int">
+</parameter>
+<parameter name="resultData" type="android.content.Intent">
+</parameter>
+</method>
 <method name="getPreferenceManager"
  return="android.preference.PreferenceManager"
  abstract="false"
@@ -144999,7 +145383,7 @@
 <parameter name="push" type="boolean">
 </parameter>
 </method>
-<method name="startPreferenceFragment"
+<method name="startPreferencePanel"
  return="void"
  abstract="false"
  native="false"
@@ -145009,9 +145393,17 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="fragment" type="android.app.Fragment">
+<parameter name="fragmentClass" type="java.lang.String">
 </parameter>
-<parameter name="ft" type="android.app.FragmentTransaction">
+<parameter name="args" type="android.os.Bundle">
+</parameter>
+<parameter name="titleRes" type="int">
+</parameter>
+<parameter name="titleText" type="java.lang.CharSequence">
+</parameter>
+<parameter name="resultTo" type="android.app.Fragment">
+</parameter>
+<parameter name="resultRequestCode" type="int">
 </parameter>
 </method>
 <method name="startWithFragment"
@@ -145028,6 +145420,10 @@
 </parameter>
 <parameter name="args" type="android.os.Bundle">
 </parameter>
+<parameter name="resultTo" type="android.app.Fragment">
+</parameter>
+<parameter name="resultRequestCode" type="int">
+</parameter>
 </method>
 <method name="switchToHeader"
  return="void"
@@ -175724,6 +176120,28 @@
  visibility="public"
 >
 </field>
+<field name="TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="208"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="TYPE_TEXT_VARIATION_WEB_PASSWORD"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="224"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 </interface>
 <class name="Layout"
  extends="java.lang.Object"
@@ -211716,6 +212134,17 @@
  visibility="public"
 >
 </field>
+<field name="SOFT_INPUT_ADJUST_NOTHING"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="48"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="SOFT_INPUT_ADJUST_PAN"
  type="int"
  transient="false"
@@ -216030,6 +216459,19 @@
 <parameter name="prefix" type="java.lang.String">
 </parameter>
 </method>
+<method name="makeCompatible"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="targetSdkVersion" type="int">
+</parameter>
+</method>
 <method name="writeToParcel"
  return="void"
  abstract="false"
@@ -216099,6 +216541,17 @@
  visibility="public"
 >
 </field>
+<field name="IME_ACTION_PREVIOUS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="7"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="IME_ACTION_SEARCH"
  type="int"
  transient="false"
@@ -216132,6 +216585,28 @@
  visibility="public"
 >
 </field>
+<field name="IME_FLAG_NAVIGATE_NEXT"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="134217728"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="IME_FLAG_NAVIGATE_PREVIOUS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="67108864"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="IME_FLAG_NO_ACCESSORY_ACTION"
  type="int"
  transient="false"
@@ -216165,6 +216640,17 @@
  visibility="public"
 >
 </field>
+<field name="IME_FLAG_NO_FULLSCREEN"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="33554432"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="IME_MASK_ACTION"
  type="int"
  transient="false"
@@ -237331,21 +237817,6 @@
 <parameter name="value" type="long">
 </parameter>
 </method>
-<method name="setOnClickExtras"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="viewId" type="int">
-</parameter>
-<parameter name="extras" type="android.os.Bundle">
-</parameter>
-</method>
 <method name="setOnClickFillInIntent"
  return="void"
  abstract="false"
@@ -245127,7 +245598,7 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="arg0" type="T">
+<parameter name="t" type="T">
 </parameter>
 </method>
 </interface>
@@ -347200,7 +347671,7 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="toCopyIn" type="E[]">
+<parameter name="array" type="E[]">
 </parameter>
 </constructor>
 <method name="add"
@@ -347228,7 +347699,7 @@
 >
 <parameter name="index" type="int">
 </parameter>
-<parameter name="element" type="E">
+<parameter name="e" type="E">
 </parameter>
 </method>
 <method name="addAll"
@@ -347356,7 +347827,9 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="o" type="java.lang.Object">
+<parameter name="e" type="E">
+</parameter>
+<parameter name="index" type="int">
 </parameter>
 </method>
 <method name="indexOf"
@@ -347369,9 +347842,7 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="e" type="E">
-</parameter>
-<parameter name="index" type="int">
+<parameter name="o" type="java.lang.Object">
 </parameter>
 </method>
 <method name="isEmpty"
@@ -347406,7 +347877,9 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="o" type="java.lang.Object">
+<parameter name="e" type="E">
+</parameter>
+<parameter name="index" type="int">
 </parameter>
 </method>
 <method name="lastIndexOf"
@@ -347419,9 +347892,7 @@
  deprecated="not deprecated"
  visibility="public"
 >
-<parameter name="e" type="E">
-</parameter>
-<parameter name="index" type="int">
+<parameter name="o" type="java.lang.Object">
 </parameter>
 </method>
 <method name="listIterator"
@@ -347512,7 +347983,7 @@
 >
 <parameter name="index" type="int">
 </parameter>
-<parameter name="element" type="E">
+<parameter name="e" type="E">
 </parameter>
 </method>
 <method name="size"
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index 37c8ad0..b5fddfa 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -389,11 +389,13 @@
             if (err == 0) {
                 observer.waitForCompletion();
                 sets = observer.sets;
-                for (RestoreSet s : sets) {
-                    if (s.token == token) {
-                        System.out.println("Scheduling restore: " + s.name);
-                        didRestore = (mRestore.restoreAll(token, observer) == 0);
-                        break;
+                if (sets != null) {
+                    for (RestoreSet s : sets) {
+                        if (s.token == token) {
+                            System.out.println("Scheduling restore: " + s.name);
+                            didRestore = (mRestore.restoreAll(token, observer) == 0);
+                            break;
+                        }
                     }
                 }
             }
diff --git a/core/java/android/animation/KeyframeSet.java b/core/java/android/animation/KeyframeSet.java
index 1741e60..2242462 100644
--- a/core/java/android/animation/KeyframeSet.java
+++ b/core/java/android/animation/KeyframeSet.java
@@ -28,12 +28,18 @@
 
     private int mNumKeyframes;
 
-    ArrayList<Keyframe> mKeyframes;
+    Keyframe mFirstKeyframe;
+    Keyframe mLastKeyframe;
+    TimeInterpolator mInterpolator; // only used in the 2-keyframe case
+    ArrayList<Keyframe> mKeyframes; // only used when there are not 2 keyframes
 
     public KeyframeSet(Keyframe... keyframes) {
+        mNumKeyframes = keyframes.length;
         mKeyframes = new ArrayList<Keyframe>();
         mKeyframes.addAll(Arrays.asList(keyframes));
-        mNumKeyframes = mKeyframes.size();
+        mFirstKeyframe = mKeyframes.get(0);
+        mLastKeyframe = mKeyframes.get(mNumKeyframes - 1);
+        mInterpolator = mLastKeyframe.getInterpolator();
     }
 
     public static KeyframeSet ofInt(int... values) {
@@ -125,32 +131,40 @@
      * @return The animated value.
      */
     public Object getValue(float fraction, TypeEvaluator evaluator) {
-        // TODO: special-case 2-keyframe common case
+
+        // Special-case optimization for the common case of only two keyframes
+        if (mNumKeyframes == 2) {
+            if (mInterpolator != null) {
+                fraction = mInterpolator.getInterpolation(fraction);
+            }
+            return evaluator.evaluate(fraction, mFirstKeyframe.getValue(),
+                    mLastKeyframe.getValue());
+        }
 
         if (fraction <= 0f) {
-            final Keyframe prevKeyframe = mKeyframes.get(0);
             final Keyframe nextKeyframe = mKeyframes.get(1);
             final TimeInterpolator interpolator = nextKeyframe.getInterpolator();
             if (interpolator != null) {
                 fraction = interpolator.getInterpolation(fraction);
             }
-            float intervalFraction = (fraction - prevKeyframe.getFraction()) /
-                (nextKeyframe.getFraction() - prevKeyframe.getFraction());
-            return evaluator.evaluate(intervalFraction, prevKeyframe.getValue(),
+            final float prevFraction = mFirstKeyframe.getFraction();
+            float intervalFraction = (fraction - prevFraction) /
+                (nextKeyframe.getFraction() - prevFraction);
+            return evaluator.evaluate(intervalFraction, mFirstKeyframe.getValue(),
                     nextKeyframe.getValue());
         } else if (fraction >= 1f) {
             final Keyframe prevKeyframe = mKeyframes.get(mNumKeyframes - 2);
-            final Keyframe nextKeyframe = mKeyframes.get(mNumKeyframes - 1);
-            final TimeInterpolator interpolator = nextKeyframe.getInterpolator();
+            final TimeInterpolator interpolator = mLastKeyframe.getInterpolator();
             if (interpolator != null) {
                 fraction = interpolator.getInterpolation(fraction);
             }
-            float intervalFraction = (fraction - prevKeyframe.getFraction()) /
-                (nextKeyframe.getFraction() - prevKeyframe.getFraction());
+            final float prevFraction = prevKeyframe.getFraction();
+            float intervalFraction = (fraction - prevFraction) /
+                (mLastKeyframe.getFraction() - prevFraction);
             return evaluator.evaluate(intervalFraction, prevKeyframe.getValue(),
-                    nextKeyframe.getValue());
+                    mLastKeyframe.getValue());
         }
-        Keyframe prevKeyframe = mKeyframes.get(0);
+        Keyframe prevKeyframe = mFirstKeyframe;
         for (int i = 1; i < mNumKeyframes; ++i) {
             Keyframe nextKeyframe = mKeyframes.get(i);
             if (fraction < nextKeyframe.getFraction()) {
@@ -158,14 +172,15 @@
                 if (interpolator != null) {
                     fraction = interpolator.getInterpolation(fraction);
                 }
-                float intervalFraction = (fraction - prevKeyframe.getFraction()) /
-                    (nextKeyframe.getFraction() - prevKeyframe.getFraction());
+                final float prevFraction = prevKeyframe.getFraction();
+                float intervalFraction = (fraction - prevFraction) /
+                    (nextKeyframe.getFraction() - prevFraction);
                 return evaluator.evaluate(intervalFraction, prevKeyframe.getValue(),
                         nextKeyframe.getValue());
             }
             prevKeyframe = nextKeyframe;
         }
-        // shouldn't get here
-        return mKeyframes.get(mNumKeyframes - 1).getValue();
+        // shouldn't reach here
+        return mLastKeyframe.getValue();
     }
 }
diff --git a/core/java/android/animation/ObjectAnimator.java b/core/java/android/animation/ObjectAnimator.java
index 7427651..5b8c91d 100644
--- a/core/java/android/animation/ObjectAnimator.java
+++ b/core/java/android/animation/ObjectAnimator.java
@@ -376,9 +376,14 @@
      */
     @Override
     public void setTarget(Object target) {
-        mTarget = target;
-        // New property/values/target should cause re-initialization prior to starting
-        mInitialized = false;
+        if (mTarget != target) {
+            mTarget = target;
+            if (mTarget  != null && target != null && mTarget.getClass() == target.getClass()) {
+                return;
+            }
+            // New target type should cause re-initialization prior to starting
+            mInitialized = false;
+        }
     }
 
     @Override
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index ad8c971..a0b70b5 100755
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -1142,7 +1142,7 @@
         switch (mPlayingState) {
         case RUNNING:
         case SEEKED:
-            float fraction = (float)(currentTime - mStartTime) / mDuration;
+            float fraction = mDuration > 0 ? (float)(currentTime - mStartTime) / mDuration : 1f;
             if (fraction >= 1f) {
                 if (mCurrentIteration < mRepeatCount || mRepeatCount == INFINITE) {
                     // Time to repeat
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index 7df9295..b359ce6 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -16,8 +16,16 @@
 
 package android.app;
 
+import android.app.ActionBar.Tab;
+import android.content.Context;
+import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.Gravity;
 import android.view.View;
+import android.view.ViewDebug;
+import android.view.ViewGroup;
+import android.view.ViewGroup.MarginLayoutParams;
 import android.view.Window;
 import android.widget.SpinnerAdapter;
 
@@ -37,9 +45,16 @@
     public static final int NAVIGATION_MODE_STANDARD = 0;
     
     /**
-     * Dropdown list navigation mode. Instead of static title text this mode
-     * presents a dropdown menu for navigation within the activity.
+     * List navigation mode. Instead of static title text this mode
+     * presents a list menu for navigation within the activity.
+     * e.g. this might be presented to the user as a dropdown list.
      */
+    public static final int NAVIGATION_MODE_LIST = 1;
+
+    /**
+     * @deprecated use NAVIGATION_MODE_LIST
+     */
+    @Deprecated
     public static final int NAVIGATION_MODE_DROPDOWN_LIST = 1;
     
     /**
@@ -47,24 +62,77 @@
      * presents a series of tabs for navigation within the activity.
      */
     public static final int NAVIGATION_MODE_TABS = 2;
-    
-    /**
-     * Custom navigation mode. This navigation mode is set implicitly whenever
-     * a custom navigation view is set. See {@link #setCustomNavigationMode(View)}.
-     */
-    public static final int NAVIGATION_MODE_CUSTOM = 3;
 
     /**
      * Use logo instead of icon if available. This flag will cause appropriate
      * navigation modes to use a wider logo in place of the standard icon.
+     *
+     * @see #setDisplayOptions(int)
+     * @see #setDisplayOptions(int, int)
      */
     public static final int DISPLAY_USE_LOGO = 0x1;
     
     /**
-     * Hide 'home' elements in this action bar, leaving more space for other
+     * Show 'home' elements in this action bar, leaving more space for other
      * navigation elements. This includes logo and icon.
+     *
+     * @see #setDisplayOptions(int)
+     * @see #setDisplayOptions(int, int)
      */
-    public static final int DISPLAY_HIDE_HOME = 0x2;
+    public static final int DISPLAY_SHOW_HOME = 0x2;
+
+    /**
+     * @deprecated Display flags are now positive for consistency - 'show' instead of 'hide'.
+     *             Use DISPLAY_SHOW_HOME.
+     */
+    @Deprecated
+    public static final int DISPLAY_HIDE_HOME = 0x1000;
+
+    /**
+     * Display the 'home' element such that it appears as an 'up' affordance.
+     * e.g. show an arrow to the left indicating the action that will be taken.
+     *
+     * Set this flag if selecting the 'home' button in the action bar to return
+     * up by a single level in your UI rather than back to the top level or front page.
+     *
+     * @see #setDisplayOptions(int)
+     * @see #setDisplayOptions(int, int)
+     */
+    public static final int DISPLAY_HOME_AS_UP = 0x4;
+
+    /**
+     * Show the activity title and subtitle, if present.
+     *
+     * @see #setTitle(CharSequence)
+     * @see #setTitle(int)
+     * @see #setSubtitle(CharSequence)
+     * @see #setSubtitle(int)
+     * @see #setDisplayOptions(int)
+     * @see #setDisplayOptions(int, int)
+     */
+    public static final int DISPLAY_SHOW_TITLE = 0x8;
+
+    /**
+     * Show the custom view if one has been set.
+     * @see #setCustomView(View)
+     * @see #setDisplayOptions(int)
+     * @see #setDisplayOptions(int, int)
+     */
+    public static final int DISPLAY_SHOW_CUSTOM = 0x10;
+
+    /**
+     * Set the action bar into custom navigation mode, supplying a view
+     * for custom navigation.
+     *
+     * Custom navigation views appear between the application icon and
+     * any action buttons and may use any space available there. Common
+     * use cases for custom navigation views might include an auto-suggesting
+     * address bar for a browser or other navigation mechanisms that do not
+     * translate well to provided navigation modes.
+     *
+     * @param view Custom navigation view to place in the ActionBar.
+     */
+    public abstract void setCustomView(View view);
 
     /**
      * Set the action bar into custom navigation mode, supplying a view
@@ -77,7 +145,15 @@
      * translate well to provided navigation modes.
      * 
      * @param view Custom navigation view to place in the ActionBar.
+     * @param layoutParams How this custom view should layout in the bar.
      */
+    public abstract void setCustomView(View view, LayoutParams layoutParams);
+
+    /**
+     * @param view
+     * @deprecated Use {@link #setCustomView(View)} and {@link #setDisplayOptions(int)} instead.
+     */
+    @Deprecated
     public abstract void setCustomNavigationMode(View view);
     
     /**
@@ -89,11 +165,31 @@
      *                within the dropdown navigation menu.
      * @param callback A NavigationCallback that will receive events when the user
      *                 selects a navigation item.
+     * @deprecated See setListNavigationCallbacks.
      */
+    @Deprecated
     public abstract void setDropdownNavigationMode(SpinnerAdapter adapter,
             NavigationCallback callback);
 
     /**
+     * Set the adapter and navigation callback for list navigation mode.
+     *
+     * The supplied adapter will provide views for the expanded list as well as
+     * the currently selected item. (These may be displayed differently.)
+     *
+     * The supplied NavigationCallback will alert the application when the user
+     * changes the current list selection.
+     *
+     * @param adapter An adapter that will provide views both to display
+     *                the current navigation selection and populate views
+     *                within the dropdown navigation menu.
+     * @param callback A NavigationCallback that will receive events when the user
+     *                 selects a navigation item.
+     */
+    public abstract void setListNavigationCallbacks(SpinnerAdapter adapter,
+            NavigationCallback callback);
+
+    /**
      * Set the action bar into dropdown navigation mode and supply an adapter that will
      * provide views for navigation choices.
      *
@@ -104,23 +200,41 @@
      *                 selects a navigation item.
      * @param defaultSelectedPosition Position within the provided adapter that should be
      *                                selected from the outset.
+     * @deprecated See setListNavigationCallbacks and setSelectedNavigationItem.
      */
+    @Deprecated
     public abstract void setDropdownNavigationMode(SpinnerAdapter adapter,
             NavigationCallback callback, int defaultSelectedPosition);
 
     /**
-     * Set the selected navigation item in dropdown or tabbed navigation modes.
+     * Set the selected navigation item in list or tabbed navigation modes.
      *
      * @param position Position of the item to select.
      */
     public abstract void setSelectedNavigationItem(int position);
 
     /**
-     * Get the position of the selected navigation item in dropdown or tabbed navigation modes.
+     * Get the position of the selected navigation item in list or tabbed navigation modes.
+     *
+     * @return Position of the selected item.
+     * @deprecated Use {@link #getSelectedNavigationIndex()} instead.
+     */
+    @Deprecated
+    public abstract int getSelectedNavigationItem();
+
+    /**
+     * Get the position of the selected navigation item in list or tabbed navigation modes.
      *
      * @return Position of the selected item.
      */
-    public abstract int getSelectedNavigationItem();
+    public abstract int getSelectedNavigationIndex();
+
+    /**
+     * Get the number of navigation items present in the current navigation mode.
+     *
+     * @return Number of navigation items.
+     */
+    public abstract int getNavigationItemCount();
 
     /**
      * Set the action bar into standard navigation mode, using the currently set title
@@ -128,7 +242,9 @@
      *
      * Standard navigation mode is default. The title is automatically set to the name of
      * your Activity on startup if an action bar is present.
+     * @deprecated See setNavigationMode
      */
+    @Deprecated
     public abstract void setStandardNavigationMode();
 
     /**
@@ -181,10 +297,10 @@
      * Set selected display options. Only the options specified by mask will be changed.
      * To change all display option bits at once, see {@link #setDisplayOptions(int)}.
      * 
-     * <p>Example: setDisplayOptions(0, DISPLAY_HIDE_HOME) will disable the
-     * {@link #DISPLAY_HIDE_HOME} option.
-     * setDisplayOptions(DISPLAY_HIDE_HOME, DISPLAY_HIDE_HOME | DISPLAY_USE_LOGO)
-     * will enable {@link #DISPLAY_HIDE_HOME} and disable {@link #DISPLAY_USE_LOGO}.
+     * <p>Example: setDisplayOptions(0, DISPLAY_SHOW_HOME) will disable the
+     * {@link #DISPLAY_SHOW_HOME} option.
+     * setDisplayOptions(DISPLAY_SHOW_HOME, DISPLAY_SHOW_HOME | DISPLAY_USE_LOGO)
+     * will enable {@link #DISPLAY_SHOW_HOME} and disable {@link #DISPLAY_USE_LOGO}.
      * 
      * @param options A combination of the bits defined by the DISPLAY_ constants
      *                defined in ActionBar.
@@ -226,9 +342,8 @@
      * Returns the current navigation mode. The result will be one of:
      * <ul>
      * <li>{@link #NAVIGATION_MODE_STANDARD}</li>
-     * <li>{@link #NAVIGATION_MODE_DROPDOWN_LIST}</li>
+     * <li>{@link #NAVIGATION_MODE_LIST}</li>
      * <li>{@link #NAVIGATION_MODE_TABS}</li>
-     * <li>{@link #NAVIGATION_MODE_CUSTOM}</li>
      * </ul>
      *
      * @return The current navigation mode.
@@ -241,7 +356,17 @@
      * @see #setCustomNavigationMode(View)
      */
     public abstract int getNavigationMode();
-    
+
+    /**
+     * Set the current navigation mode.
+     *
+     * @param mode The new mode to set.
+     * @see #NAVIGATION_MODE_STANDARD
+     * @see #NAVIGATION_MODE_LIST
+     * @see #NAVIGATION_MODE_TABS
+     */
+    public abstract void setNavigationMode(int mode);
+
     /**
      * @return The current set of display options. 
      */
@@ -254,6 +379,8 @@
      * @see #insertTab(Tab, int)
      * @see #removeTab(Tab)
      * @see #removeTabAt(int)
+     *
+     * @deprecated See {@link #setNavigationMode(int)}
      */
     public abstract void setTabNavigationMode();
 
@@ -285,22 +412,31 @@
     public abstract void addTab(Tab tab, int position);
 
     /**
-     * Remove a tab from the action bar.
+     * Remove a tab from the action bar. If the removed tab was selected it will be deselected
+     * and another tab will be selected if present.
      *
      * @param tab The tab to remove
      */
     public abstract void removeTab(Tab tab);
 
     /**
-     * Remove a tab from the action bar.
+     * Remove a tab from the action bar. If the removed tab was selected it will be deselected
+     * and another tab will be selected if present.
      *
      * @param position Position of the tab to remove
      */
     public abstract void removeTabAt(int position);
 
     /**
+     * Remove all tabs from the action bar and deselect the current tab.
+     */
+    public abstract void removeAllTabs();
+
+    /**
      * Select the specified tab. If it is not a child of this action bar it will be added.
      *
+     * <p>Note: If you want to select by index, use {@link #setSelectedNavigationItem(int)}.</p>
+     *
      * @param tab Tab to select
      */
     public abstract void selectTab(Tab tab);
@@ -314,6 +450,14 @@
     public abstract Tab getSelectedTab();
 
     /**
+     * Returns the tab at the specified index.
+     *
+     * @param index Index value in the range 0-get
+     * @return
+     */
+    public abstract Tab getTabAt(int index);
+
+    /**
      * Retrieve the current height of the ActionBar.
      *
      * @return The ActionBar's height
@@ -395,24 +539,27 @@
          * Set the icon displayed on this tab.
          *
          * @param icon The drawable to use as an icon
+         * @return The current instance for call chaining
          */
-        public abstract void setIcon(Drawable icon);
+        public abstract Tab setIcon(Drawable icon);
 
         /**
          * Set the text displayed on this tab. Text may be truncated if there is not
          * room to display the entire string.
          *
          * @param text The text to display
+         * @return The current instance for call chaining
          */
-        public abstract void setText(CharSequence text);
+        public abstract Tab setText(CharSequence text);
 
         /**
          * Set a custom view to be used for this tab. This overrides values set by
          * {@link #setText(CharSequence)} and {@link #setIcon(Drawable)}.
          *
          * @param view Custom view to be used as a tab.
+         * @return The current instance for call chaining
          */
-        public abstract void setCustomView(View view);
+        public abstract Tab setCustomView(View view);
 
         /**
          * Retrieve a previously set custom view for this tab.
@@ -425,8 +572,9 @@
          * Give this Tab an arbitrary object to hold for later use.
          *
          * @param obj Object to store
+         * @return The current instance for call chaining
          */
-        public abstract void setTag(Object obj);
+        public abstract Tab setTag(Object obj);
 
         /**
          * @return This Tab's tag object.
@@ -438,8 +586,9 @@
          * All tabs must have a TabListener set before being added to the ActionBar.
          *
          * @param listener Listener to handle tab selection events
+         * @return The current instance for call chaining
          */
-        public abstract void setTabListener(TabListener listener);
+        public abstract Tab setTabListener(TabListener listener);
 
         /**
          * Select this tab. Only valid if the tab has been added to the action bar.
@@ -481,4 +630,65 @@
          */
         public void onTabReselected(Tab tab, FragmentTransaction ft);
     }
+
+    /**
+     * Per-child layout information associated with action bar custom views.
+     *
+     * @attr ref android.R.styleable#ActionBar_LayoutParams_layout_gravity
+     */
+    public static class LayoutParams extends MarginLayoutParams {
+        /**
+         * Gravity for the view associated with these LayoutParams.
+         *
+         * @see android.view.Gravity
+         */
+        @ViewDebug.ExportedProperty(category = "layout", mapping = {
+            @ViewDebug.IntToString(from =  -1,                       to = "NONE"),
+            @ViewDebug.IntToString(from = Gravity.NO_GRAVITY,        to = "NONE"),
+            @ViewDebug.IntToString(from = Gravity.TOP,               to = "TOP"),
+            @ViewDebug.IntToString(from = Gravity.BOTTOM,            to = "BOTTOM"),
+            @ViewDebug.IntToString(from = Gravity.LEFT,              to = "LEFT"),
+            @ViewDebug.IntToString(from = Gravity.RIGHT,             to = "RIGHT"),
+            @ViewDebug.IntToString(from = Gravity.CENTER_VERTICAL,   to = "CENTER_VERTICAL"),
+            @ViewDebug.IntToString(from = Gravity.FILL_VERTICAL,     to = "FILL_VERTICAL"),
+            @ViewDebug.IntToString(from = Gravity.CENTER_HORIZONTAL, to = "CENTER_HORIZONTAL"),
+            @ViewDebug.IntToString(from = Gravity.FILL_HORIZONTAL,   to = "FILL_HORIZONTAL"),
+            @ViewDebug.IntToString(from = Gravity.CENTER,            to = "CENTER"),
+            @ViewDebug.IntToString(from = Gravity.FILL,              to = "FILL")
+        })
+        public int gravity = -1;
+
+        public LayoutParams(Context c, AttributeSet attrs) {
+            super(c, attrs);
+
+            TypedArray a = c.obtainStyledAttributes(attrs,
+                    com.android.internal.R.styleable.ActionBar_LayoutParams);
+            gravity = a.getInt(
+                    com.android.internal.R.styleable.ActionBar_LayoutParams_layout_gravity, -1);
+        }
+
+        public LayoutParams(int width, int height) {
+            super(width, height);
+            this.gravity = Gravity.CENTER_VERTICAL | Gravity.LEFT;
+        }
+
+        public LayoutParams(int width, int height, int gravity) {
+            super(width, height);
+            this.gravity = gravity;
+        }
+
+        public LayoutParams(int gravity) {
+            this(WRAP_CONTENT, MATCH_PARENT, gravity);
+        }
+
+        public LayoutParams(LayoutParams source) {
+            super(source);
+
+            this.gravity = source.gravity;
+        }
+
+        public LayoutParams(ViewGroup.LayoutParams source) {
+            super(source);
+        }
+    }
 }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 7315f01..47efddb 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1781,6 +1781,17 @@
         performNewIntents(data.token, data.intents);
     }
 
+    private static final ThreadLocal<Intent> sCurrentBroadcastIntent = new ThreadLocal<Intent>();
+
+    /**
+     * Return the Intent that's currently being handled by a
+     * BroadcastReceiver on this thread, or null if none.
+     * @hide
+     */
+    public static Intent getIntentBeingBroadcast() {
+        return sCurrentBroadcastIntent.get();
+    }
+
     private final void handleReceiver(ReceiverData data) {
         // If we are getting ready to gc after going to the background, well
         // we are back active so skip it.
@@ -1820,6 +1831,7 @@
                 + ", dir=" + packageInfo.getAppDir());
 
             ContextImpl context = (ContextImpl)app.getBaseContext();
+            sCurrentBroadcastIntent.set(data.intent);
             receiver.setPendingResult(data);
             receiver.onReceive(context.getReceiverRestrictedContext(),
                     data.intent);
@@ -1832,6 +1844,8 @@
                     "Unable to start receiver " + component
                     + ": " + e.toString(), e);
             }
+        } finally {
+            sCurrentBroadcastIntent.set(null);
         }
 
         if (receiver.getPendingResult() != null) {
diff --git a/core/java/android/app/Application.java b/core/java/android/app/Application.java
index 45ce860..b9ac848 100644
--- a/core/java/android/app/Application.java
+++ b/core/java/android/app/Application.java
@@ -27,6 +27,14 @@
  * AndroidManifest.xml's &lt;application&gt; tag, which will cause that class
  * to be instantiated for you when the process for your application/package is
  * created.
+ * 
+ * <p class="note">There is normally no need to subclass Application.  In
+ * most situation, static singletons can provide the same functionality in a
+ * more modular way.  If your singleton needs a global context (for example
+ * to register broadcast receivers), the function to retrieve it can be
+ * given a {@link android.content.Context} which internally uses
+ * {@link android.content.Context#getApplicationContext() Context.getApplicationContext()}
+ * when first constructing the singleton.</p>
  */
 public class Application extends ContextWrapper implements ComponentCallbacks {
     
@@ -46,12 +54,10 @@
     }
 
     /**
-     * Called when the application is stopping.  There are no more application
-     * objects running and the process will exit.  <em>Note: never depend on
-     * this method being called; in many cases an unneeded application process
-     * will simply be killed by the kernel without executing any application
-     * code.</em>
-     * If you override this method, be sure to call super.onTerminate().
+     * This method is for use in emulated process environments.  It will
+     * never be called on a production Android device, where processes are
+     * removed by simply killing them; no user code (including this callback)
+     * is executed when doing so.
      */
     public void onTerminate() {
     }
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index a29acf1..5ce4cd6 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -265,7 +265,11 @@
     public Resources.Theme getTheme() {
         if (mTheme == null) {
             if (mThemeResource == 0) {
-                mThemeResource = com.android.internal.R.style.Theme;
+                final Context outerContext = getOuterContext();
+                mThemeResource = (outerContext.getApplicationInfo().targetSdkVersion
+                        >= Build.VERSION_CODES.HONEYCOMB)
+                                ? com.android.internal.R.style.Theme_Holo
+                                : com.android.internal.R.style.Theme;
             }
             mTheme = mResources.newTheme();
             mTheme.applyStyle(mThemeResource, true);
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index 570e494..592a63b 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -272,6 +272,14 @@
      */
     public static final String EXTRA_DOWNLOAD_ID = "extra_download_id";
 
+    /**
+     * When clicks on multiple notifications are received, the following
+     * provides an array of download ids corresponding to the download notification that was
+     * clicked. It can be retrieved by the receiver of this
+     * Intent using {@link android.content.Intent#getLongArrayExtra(String)}.
+     */
+    public static final String EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS = "extra_click_download_ids";
+
     // this array must contain all public columns
     private static final String[] COLUMNS = new String[] {
         COLUMN_ID,
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index f27a15e..eaf1aee 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -1027,6 +1027,16 @@
     }
 
     /**
+     * Called when this fragment's option menu items are no longer being
+     * included in the overall options menu.  Receiving this call means that
+     * the menu needed to be rebuilt, but this fragment's items were not
+     * included in the newly built menu (its {@link #onCreateOptionsMenu(Menu, MenuInflater)}
+     * was not called).
+     */
+    public void onDestroyOptionsMenu() {
+    }
+    
+    /**
      * This hook is called whenever an item in your options menu is selected.
      * The default implementation simply returns false to have the normal
      * processing happen (calling the item's Runnable or sending a message to
diff --git a/core/java/android/app/FragmentBreadCrumbs.java b/core/java/android/app/FragmentBreadCrumbs.java
index 22e0747..e924c1c 100644
--- a/core/java/android/app/FragmentBreadCrumbs.java
+++ b/core/java/android/app/FragmentBreadCrumbs.java
@@ -16,6 +16,7 @@
 
 package android.app;
 
+import android.animation.LayoutTransition;
 import android.app.FragmentManager.BackStackEntry;
 import android.content.Context;
 import android.util.AttributeSet;
@@ -69,6 +70,7 @@
         addView(mContainer);
         a.getFragmentManager().addOnBackStackChangedListener(this);
         updateCrumbs();
+        setLayoutTransition(new LayoutTransition());
     }
 
     /**
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 45f9325..512ca16 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -268,6 +268,7 @@
     ArrayList<Fragment> mAdded;
     ArrayList<Integer> mAvailIndices;
     ArrayList<BackStackRecord> mBackStack;
+    ArrayList<Fragment> mCreatedMenus;
     
     // Must be accessed while locked.
     ArrayList<BackStackRecord> mBackStackIndices;
@@ -1325,15 +1326,32 @@
     
     public boolean dispatchCreateOptionsMenu(Menu menu, MenuInflater inflater) {
         boolean show = false;
+        ArrayList<Fragment> newMenus = null;
         if (mActive != null) {
             for (int i=0; i<mAdded.size(); i++) {
                 Fragment f = mAdded.get(i);
                 if (f != null && !f.mHidden && f.mHasMenu) {
                     show = true;
                     f.onCreateOptionsMenu(menu, inflater);
+                    if (newMenus == null) {
+                        newMenus = new ArrayList<Fragment>();
+                    }
+                    newMenus.add(f);
                 }
             }
         }
+        
+        if (mCreatedMenus != null) {
+            for (int i=0; i<mCreatedMenus.size(); i++) {
+                Fragment f = mCreatedMenus.get(i);
+                if (newMenus == null || !newMenus.contains(f)) {
+                    f.onDestroyOptionsMenu();
+                }
+            }
+        }
+        
+        mCreatedMenus = newMenus;
+        
         return show;
     }
     
diff --git a/core/java/android/bluetooth/BluetoothDeviceProfileState.java b/core/java/android/bluetooth/BluetoothDeviceProfileState.java
index 0c8e4d9..138e7f2 100644
--- a/core/java/android/bluetooth/BluetoothDeviceProfileState.java
+++ b/core/java/android/bluetooth/BluetoothDeviceProfileState.java
@@ -773,6 +773,7 @@
 
                 case CONNECT_HFP_INCOMING:
                     transitionTo(mIncomingHandsfree);
+                    break;
                 case CONNECT_A2DP_INCOMING:
                     transitionTo(mIncomingA2dp);
 
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 8c36aa6..e14282c 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -533,6 +533,8 @@
  *     <li> {@link #CATEGORY_TEST}
  *     <li> {@link #CATEGORY_CAR_DOCK}
  *     <li> {@link #CATEGORY_DESK_DOCK}
+ *     <li> {@link #CATEGORY_LE_DESK_DOCK}
+ *     <li> {@link #CATEGORY_HE_DESK_DOCK}
  *     <li> {@link #CATEGORY_CAR_MODE}
  *     <li> {@link #CATEGORY_APP_MARKET}
  * </ul>
@@ -549,6 +551,8 @@
  *     <li> {@link #EXTRA_CHANGED_COMPONENT_NAME}
  *     <li> {@link #EXTRA_DATA_REMOVED}
  *     <li> {@link #EXTRA_DOCK_STATE}
+ *     <li> {@link #EXTRA_DOCK_STATE_HE_DESK}
+ *     <li> {@link #EXTRA_DOCK_STATE_LE_DESK}
  *     <li> {@link #EXTRA_DOCK_STATE_CAR}
  *     <li> {@link #EXTRA_DOCK_STATE_DESK}
  *     <li> {@link #EXTRA_DOCK_STATE_UNDOCKED}
@@ -1822,6 +1826,36 @@
             "android.intent.action.HEADSET_PLUG";
 
     /**
+     * Broadcast Action: An analog audio speaker/headset plugged in or unplugged.
+     *
+     * <p>The intent will have the following extra values:
+     * <ul>
+     *   <li><em>state</em> - 0 for unplugged, 1 for plugged. </li>
+     *   <li><em>name</em> - Headset type, human readable string </li>
+     * </ul>
+     * </ul>
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_USB_ANLG_HEADSET_PLUG =
+            "android.intent.action.DOCK_HEADSET_PLUG";
+
+    /**
+     * Broadcast Action: An analog audio speaker/headset plugged in or unplugged.
+     *
+     * <p>The intent will have the following extra values:
+     * <ul>
+     *   <li><em>state</em> - 0 for unplugged, 1 for plugged. </li>
+     *   <li><em>name</em> - Headset type, human readable string </li>
+     * </ul>
+     * </ul>
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_USB_DGTL_HEADSET_PLUG =
+            "android.intent.action.DOCK_HEADSET_PLUG";
+
+    /**
      * Broadcast Action: An outgoing call is about to be placed.
      *
      * <p>The Intent will have the following extra value:
@@ -2060,6 +2094,21 @@
      */
     @SdkConstant(SdkConstantType.INTENT_CATEGORY)
     public static final String CATEGORY_DESK_DOCK = "android.intent.category.DESK_DOCK";
+    /**
+     * An activity to run when device is inserted into a analog (low end) dock.
+     * Used with {@link #ACTION_MAIN} to launch an activity.  For more
+     * information, see {@link android.app.UiModeManager}.
+     */
+    @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+    public static final String CATEGORY_LE_DESK_DOCK = "android.intent.category.LE_DESK_DOCK";
+
+    /**
+     * An activity to run when device is inserted into a digital (high end) dock.
+     * Used with {@link #ACTION_MAIN} to launch an activity.  For more
+     * information, see {@link android.app.UiModeManager}.
+     */
+    @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+    public static final String CATEGORY_HE_DESK_DOCK = "android.intent.category.HE_DESK_DOCK";
 
     /**
      * Used to indicate that the activity can be used in a car environment.
@@ -2208,7 +2257,9 @@
      * intents to request the dock state.  Possible values are
      * {@link android.content.Intent#EXTRA_DOCK_STATE_UNDOCKED},
      * {@link android.content.Intent#EXTRA_DOCK_STATE_DESK}, or
-     * {@link android.content.Intent#EXTRA_DOCK_STATE_CAR}.
+     * {@link android.content.Intent#EXTRA_DOCK_STATE_CAR}, or
+     * {@link android.content.Intent#EXTRA_DOCK_STATE_LE_DESK}, or
+     * {@link android.content.Intent#EXTRA_DOCK_STATE_HE_DESK}.
      */
     public static final String EXTRA_DOCK_STATE = "android.intent.extra.DOCK_STATE";
 
@@ -2231,6 +2282,18 @@
     public static final int EXTRA_DOCK_STATE_CAR = 2;
 
     /**
+     * Used as an int value for {@link android.content.Intent#EXTRA_DOCK_STATE}
+     * to represent that the phone is in a analog (low end) dock.
+     */
+    public static final int EXTRA_DOCK_STATE_LE_DESK = 3;
+
+    /**
+     * Used as an int value for {@link android.content.Intent#EXTRA_DOCK_STATE}
+     * to represent that the phone is in a digital (high end) dock.
+     */
+    public static final int EXTRA_DOCK_STATE_HE_DESK = 4;
+
+    /**
      * Boolean that can be supplied as meta-data with a dock activity, to
      * indicate that the dock should take over the home key when it is active.
      */
diff --git a/core/java/android/content/UriMatcher.java b/core/java/android/content/UriMatcher.java
index 72ec469..841c8f4 100644
--- a/core/java/android/content/UriMatcher.java
+++ b/core/java/android/content/UriMatcher.java
@@ -25,8 +25,8 @@
 /**
 Utility class to aid in matching URIs in content providers.
 
-<p>To use this class, build up a tree of UriMatcher objects.
-Typically, it looks something like this:
+<p>To use this class, build up a tree of <code>UriMatcher</code> objects.
+For example:
 <pre>
     private static final int PEOPLE = 1;
     private static final int PEOPLE_ID = 2;
@@ -48,36 +48,35 @@
     private static final int CALLS_ID = 12;
     private static final int CALLS_FILTER = 15;
 
-    private static final UriMatcher sURIMatcher = new UriMatcher();
+    private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
 
     static
     {
-        sURIMatcher.addURI("contacts", "/people", PEOPLE);
-        sURIMatcher.addURI("contacts", "/people/#", PEOPLE_ID);
-        sURIMatcher.addURI("contacts", "/people/#/phones", PEOPLE_PHONES);
-        sURIMatcher.addURI("contacts", "/people/#/phones/#", PEOPLE_PHONES_ID);
-        sURIMatcher.addURI("contacts", "/people/#/contact_methods", PEOPLE_CONTACTMETHODS);
-        sURIMatcher.addURI("contacts", "/people/#/contact_methods/#", PEOPLE_CONTACTMETHODS_ID);
-        sURIMatcher.addURI("contacts", "/deleted_people", DELETED_PEOPLE);
-        sURIMatcher.addURI("contacts", "/phones", PHONES);
-        sURIMatcher.addURI("contacts", "/phones/filter/*", PHONES_FILTER);
-        sURIMatcher.addURI("contacts", "/phones/#", PHONES_ID);
-        sURIMatcher.addURI("contacts", "/contact_methods", CONTACTMETHODS);
-        sURIMatcher.addURI("contacts", "/contact_methods/#", CONTACTMETHODS_ID);
-        sURIMatcher.addURI("call_log", "/calls", CALLS);
-        sURIMatcher.addURI("call_log", "/calls/filter/*", CALLS_FILTER);
-        sURIMatcher.addURI("call_log", "/calls/#", CALLS_ID);
+        sURIMatcher.addURI("contacts", "people", PEOPLE);
+        sURIMatcher.addURI("contacts", "people/#", PEOPLE_ID);
+        sURIMatcher.addURI("contacts", "people/#/phones", PEOPLE_PHONES);
+        sURIMatcher.addURI("contacts", "people/#/phones/#", PEOPLE_PHONES_ID);
+        sURIMatcher.addURI("contacts", "people/#/contact_methods", PEOPLE_CONTACTMETHODS);
+        sURIMatcher.addURI("contacts", "people/#/contact_methods/#", PEOPLE_CONTACTMETHODS_ID);
+        sURIMatcher.addURI("contacts", "deleted_people", DELETED_PEOPLE);
+        sURIMatcher.addURI("contacts", "phones", PHONES);
+        sURIMatcher.addURI("contacts", "phones/filter/*", PHONES_FILTER);
+        sURIMatcher.addURI("contacts", "phones/#", PHONES_ID);
+        sURIMatcher.addURI("contacts", "contact_methods", CONTACTMETHODS);
+        sURIMatcher.addURI("contacts", "contact_methods/#", CONTACTMETHODS_ID);
+        sURIMatcher.addURI("call_log", "calls", CALLS);
+        sURIMatcher.addURI("call_log", "calls/filter/*", CALLS_FILTER);
+        sURIMatcher.addURI("call_log", "calls/#", CALLS_ID);
     }
 </pre>
-<p>Then when you need to match match against a URI, call {@link #match}, providing
-the tokenized url you've been given, and the value you want if there isn't
-a match.  You can use the result to build a query, return a type, insert or
-delete a row, or whatever you need, without duplicating all of the if-else
-logic you'd otherwise need.  Like this:
+<p>Then when you need to match against a URI, call {@link #match}, providing
+the URL that you have been given.  You can use the result to build a query,
+return a type, insert or delete a row, or whatever you need, without duplicating
+all of the if-else logic that you would otherwise need.  For example:
 <pre>
-    public String getType(String[] url)
+    public String getType(Uri url)
     {
-        int match = sURIMatcher.match(url, NO_MATCH);
+        int match = sURIMatcher.match(url);
         switch (match)
         {
             case PEOPLE:
@@ -93,19 +92,20 @@
         }
     }
 </pre>
-instead of
+instead of:
 <pre>
-    public String getType(String[] url)
+    public String getType(Uri url)
     {
-        if (url.length >= 2) {
-            if (url[1].equals("people")) {
-                if (url.length == 2) {
+        List<String> pathSegments = url.getPathSegments();
+        if (pathSegments.size() >= 2) {
+            if ("people".equals(pathSegments.get(1))) {
+                if (pathSegments.size() == 2) {
                     return "vnd.android.cursor.dir/person";
-                } else if (url.length == 3) {
+                } else if (pathSegments.size() == 3) {
                     return "vnd.android.cursor.item/person";
 ... snip ...
                     return "vnd.android.cursor.dir/snail-mail";
-                } else if (url.length == 3) {
+                } else if (pathSegments.size() == 3) {
                     return "vnd.android.cursor.item/snail-mail";
                 }
             }
diff --git a/core/java/android/database/Cursor.java b/core/java/android/database/Cursor.java
index c03c586..a344272 100644
--- a/core/java/android/database/Cursor.java
+++ b/core/java/android/database/Cursor.java
@@ -20,8 +20,6 @@
 import android.net.Uri;
 import android.os.Bundle;
 
-import java.util.Map;
-
 /**
  * This interface provides random read-write access to the result set returned
  * by a database query.
@@ -344,7 +342,10 @@
      *
      * @return true if the requery succeeded, false if not, in which case the
      *         cursor becomes invalid.
+     * @deprecated Don't use this. Just request a new cursor, so you can do this
+     * asynchronously and update your list view once the new cursor comes back.
      */
+    @Deprecated
     boolean requery();
 
     /**
diff --git a/core/java/android/database/RequeryOnUiThreadException.java b/core/java/android/database/RequeryOnUiThreadException.java
deleted file mode 100644
index 97a50d8..0000000
--- a/core/java/android/database/RequeryOnUiThreadException.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.database;
-
-/**
- * An exception that indicates invoking {@link Cursor#requery()} on Main thread could cause ANR.
- * This exception should encourage apps to invoke {@link Cursor#requery()} in a background thread. 
- * @hide
- */
-public class RequeryOnUiThreadException extends RuntimeException {
-    public RequeryOnUiThreadException(String packageName) {
-        super("In " + packageName + " Requery is executing on main (UI) thread. could cause ANR. " +
-                "do it in background thread.");
-    }
-}
diff --git a/core/java/android/database/sqlite/SQLiteCursor.java b/core/java/android/database/sqlite/SQLiteCursor.java
index 225eaab..fc30da2 100644
--- a/core/java/android/database/sqlite/SQLiteCursor.java
+++ b/core/java/android/database/sqlite/SQLiteCursor.java
@@ -16,13 +16,10 @@
 
 package android.database.sqlite;
 
-import android.app.ActivityThread;
 import android.database.AbstractWindowedCursor;
 import android.database.CursorWindow;
 import android.database.DataSetObserver;
-import android.database.RequeryOnUiThreadException;
 import android.os.Handler;
-import android.os.Looper;
 import android.os.Message;
 import android.os.Process;
 import android.os.StrictMode;
@@ -76,11 +73,6 @@
     private boolean mPendingData = false;
 
     /**
-     * Used by {@link #requery()} to remember for which database we've already shown the warning.
-     */
-    private static final HashMap<String, Boolean> sAlreadyWarned = new HashMap<String, Boolean>();
-    
-    /**
      *  support for a cursor variant that doesn't always read all results
      *  initialRead is the initial number of items that cursor window reads 
      *  if query contains more than this number of items, a thread will be
@@ -401,35 +393,11 @@
         }
     }
 
-    /**
-     * Show a warning against the use of requery() if called on the main thread.
-     * This warning is shown per database per process.
-     */
-    private void warnIfUiThread() {
-        if (Looper.getMainLooper() == Looper.myLooper()) {
-            String databasePath = getQuery().mDatabase.getPath();
-            // We show the warning once per database in order not to spam logcat.
-            if (!sAlreadyWarned.containsKey(databasePath)) {
-                sAlreadyWarned.put(databasePath, true);
-                String packageName = ActivityThread.currentPackageName();
-                Throwable t = null;
-                // BEGIN STOPSHIP remove the following line
-                t = new RequeryOnUiThreadException(packageName);
-                // END STOPSHIP
-                String s = packageName == null ? "'unknown'" : packageName;
-                Log.w(TAG, "should not attempt requery on main (UI) thread: app = " + s +
-                        " (database: " + mQuery.mDatabase.getPath() +
-                        ", query: " + mQuery.mSql + ")", t);
-            }
-        }
-    }
-
     @Override
     public boolean requery() {
         if (isClosed()) {
             return false;
         }
-        warnIfUiThread();
         long timeStart = 0;
         if (Config.LOGV) {
             timeStart = System.currentTimeMillis();
diff --git a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
index 44f30f7..01fc010 100644
--- a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
@@ -31,7 +31,6 @@
 import android.view.inputmethod.CompletionInfo;
 import android.view.inputmethod.ExtractedText;
 import android.view.inputmethod.InputMethodSession;
-import android.view.inputmethod.EditorInfo;
 
 class IInputMethodSessionWrapper extends IInputMethodSession.Stub
         implements HandlerCaller.Callback {
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java
index 24ea7d2..17c9ee7 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -70,6 +70,7 @@
     final WeakReference<AbstractInputMethodService> mTarget;
     final HandlerCaller mCaller;
     final WeakReference<InputMethod> mInputMethod;
+    final int mTargetSdkVersion;
     
     static class Notifier {
         boolean notified;
@@ -102,6 +103,7 @@
         mTarget = new WeakReference<AbstractInputMethodService>(context);
         mCaller = new HandlerCaller(context.getApplicationContext(), this);
         mInputMethod = new WeakReference<InputMethod>(inputMethod);
+        mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
     }
 
     public InputMethod getInternalInputMethod() {
@@ -151,7 +153,9 @@
                 IInputContext inputContext = (IInputContext)args.arg1;
                 InputConnection ic = inputContext != null
                         ? new InputConnectionWrapper(inputContext) : null;
-                inputMethod.startInput(ic, (EditorInfo)args.arg2);
+                EditorInfo info = (EditorInfo)args.arg2;
+                info.makeCompatible(mTargetSdkVersion);
+                inputMethod.startInput(ic, info);
                 return;
             }
             case DO_RESTART_INPUT: {
@@ -159,7 +163,9 @@
                 IInputContext inputContext = (IInputContext)args.arg1;
                 InputConnection ic = inputContext != null
                         ? new InputConnectionWrapper(inputContext) : null;
-                inputMethod.restartInput(ic, (EditorInfo)args.arg2);
+                EditorInfo info = (EditorInfo)args.arg2;
+                info.makeCompatible(mTargetSdkVersion);
+                inputMethod.restartInput(ic, info);
                 return;
             }
             case DO_CREATE_SESSION: {
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index c0743cfe..a1f2b63 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -1945,6 +1945,8 @@
                 return getText(com.android.internal.R.string.ime_action_next);
             case EditorInfo.IME_ACTION_DONE:
                 return getText(com.android.internal.R.string.ime_action_done);
+            case EditorInfo.IME_ACTION_PREVIOUS:
+                return getText(com.android.internal.R.string.ime_action_previous);
             default:
                 return getText(com.android.internal.R.string.ime_action_default);
         }
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 5a6369c..34d3b85 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -17,7 +17,9 @@
 
 import android.animation.ValueAnimator;
 import android.app.ActivityManagerNative;
+import android.app.ActivityThread;
 import android.app.ApplicationErrorReport;
+import android.content.Intent;
 import android.util.Log;
 import android.util.Printer;
 
@@ -1205,6 +1207,12 @@
         public long violationUptimeMillis;
 
         /**
+         * The action of the Intent being broadcast to somebody's onReceive
+         * on this thread right now, or null.
+         */
+        public String broadcastIntentAction;
+
+        /**
          * Create an uninitialized instance of ViolationInfo
          */
         public ViolationInfo() {
@@ -1220,6 +1228,10 @@
             violationUptimeMillis = SystemClock.uptimeMillis();
             this.policy = policy;
             this.numAnimationsRunning = ValueAnimator.getCurrentAnimationsCount();
+            Intent broadcastIntent = ActivityThread.getIntentBeingBroadcast();
+            if (broadcastIntent != null) {
+                broadcastIntentAction = broadcastIntent.getAction();
+            }
         }
 
         /**
@@ -1247,6 +1259,7 @@
             violationNumThisLoop = in.readInt();
             numAnimationsRunning = in.readInt();
             violationUptimeMillis = in.readLong();
+            broadcastIntentAction = in.readString();
         }
 
         /**
@@ -1259,6 +1272,7 @@
             dest.writeInt(violationNumThisLoop);
             dest.writeInt(numAnimationsRunning);
             dest.writeLong(violationUptimeMillis);
+            dest.writeString(broadcastIntentAction);
         }
 
 
@@ -1278,6 +1292,9 @@
                 pw.println(prefix + "numAnimationsRunning: " + numAnimationsRunning);
             }
             pw.println(prefix + "violationUptimeMillis: " + violationUptimeMillis);
+            if (broadcastIntentAction != null) {
+                pw.println(prefix + "broadcastIntentAction: " + broadcastIntentAction);
+            }
         }
 
     }
diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java
index 0c6a237..97c957d 100644
--- a/core/java/android/preference/PreferenceActivity.java
+++ b/core/java/android/preference/PreferenceActivity.java
@@ -825,7 +825,7 @@
 
     /**
      * Called when the user selects an item in the header list.  The default
-     * implementation will call either {@link #startWithFragment(String, Bundle)}
+     * implementation will call either {@link #startWithFragment(String, Bundle, Fragment, int)}
      * or {@link #switchToHeader(Header)} as appropriate.
      *
      * @param header The header that was selected.
@@ -834,7 +834,7 @@
     public void onHeaderClick(Header header, int position) {
         if (header.fragment != null) {
             if (mSinglePane) {
-                startWithFragment(header.fragment, header.fragmentArguments);
+                startWithFragment(header.fragment, header.fragmentArguments, null, 0);
             } else {
                 switchToHeader(header);
             }
@@ -852,13 +852,18 @@
      * @param fragmentName The name of the fragment to display.
      * @param args Optional arguments to supply to the fragment.
      */
-    public void startWithFragment(String fragmentName, Bundle args) {
+    public void startWithFragment(String fragmentName, Bundle args,
+            Fragment resultTo, int resultRequestCode) {
         Intent intent = new Intent(Intent.ACTION_MAIN);
         intent.setClass(this, getClass());
         intent.putExtra(EXTRA_SHOW_FRAGMENT, fragmentName);
         intent.putExtra(EXTRA_SHOW_FRAGMENT_ARGUMENTS, args);
         intent.putExtra(EXTRA_NO_HEADERS, true);
-        startActivity(intent);
+        if (resultTo == null) {
+            startActivity(intent);
+        } else {
+            resultTo.startActivityForResult(intent, resultRequestCode);
+        }
     }
 
     /**
@@ -923,9 +928,15 @@
      * @param header The new header to display.
      */
     public void switchToHeader(Header header) {
-        int direction = mHeaders.indexOf(header) - mHeaders.indexOf(mCurHeader);
-        switchToHeaderInner(header.fragment, header.fragmentArguments, direction);
-        setSelectedHeader(header);
+        if (mCurHeader == header) {
+            // This is the header we are currently displaying.  Just make sure
+            // to pop the stack up to its root state.
+            getFragmentManager().popBackStack(BACK_STACK_PREFS, POP_BACK_STACK_INCLUSIVE);
+        } else {
+            int direction = mHeaders.indexOf(header) - mHeaders.indexOf(mCurHeader);
+            switchToHeaderInner(header.fragment, header.fragmentArguments, direction);
+            setSelectedHeader(header);
+        }
     }
 
     Header findBestMatchingHeader(Header cur, ArrayList<Header> from) {
@@ -982,7 +993,7 @@
      */
     public void startPreferenceFragment(Fragment fragment, boolean push) {
         FragmentTransaction transaction = getFragmentManager().openTransaction();
-        startPreferenceFragment(fragment, transaction);
+        transaction.replace(com.android.internal.R.id.prefs, fragment);
         if (push) {
             transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
             transaction.addToBackStack(BACK_STACK_PREFS);
@@ -993,25 +1004,74 @@
     }
 
     /**
-     * Start a new fragment.
-     *
-     * @param fragment The fragment to start
-     * @param ft The FragmentTransaction in which to perform this operation.
-     * Will not be added to the back stack or committed for you; you use do that.
+     * Start a new fragment containing a preference panel.  If the prefences
+     * are being displayed in multi-pane mode, the given fragment class will
+     * be instantiated and placed in the appropriate pane.  If running in
+     * single-pane mode, a new activity will be launched in which to show the
+     * fragment.
+     * 
+     * @param fragmentClass Full name of the class implementing the fragment.
+     * @param args Any desired arguments to supply to the fragment.
+     * @param titleRes Optional resource identifier of the title of this
+     * fragment.
+     * @param titleText Optional text of the title of this fragment.
+     * @param resultTo Optional fragment that result data should be sent to.
+     * If non-null, resultTo.onActivityResult() will be called when this
+     * preference panel is done.  The launched panel must use
+     * {@link #finishPreferencePanel(Fragment, int, Intent)} when done.
+     * @param resultRequestCode If resultTo is non-null, this is the caller's
+     * request code to be received with the resut.
      */
-    public void startPreferenceFragment(Fragment fragment, FragmentTransaction ft) {
-        ft.replace(com.android.internal.R.id.prefs, fragment);
+    public void startPreferencePanel(String fragmentClass, Bundle args, int titleRes,
+            CharSequence titleText, Fragment resultTo, int resultRequestCode) {
+        if (mSinglePane) {
+            startWithFragment(fragmentClass, args, resultTo, resultRequestCode);
+        } else {
+            Fragment f = Fragment.instantiate(this, fragmentClass, args);
+            if (resultTo != null) {
+                f.setTargetFragment(resultTo, resultRequestCode);
+            }
+            FragmentTransaction transaction = getFragmentManager().openTransaction();
+            transaction.replace(com.android.internal.R.id.prefs, f);
+            if (titleRes != 0) {
+                transaction.setBreadCrumbTitle(titleRes);
+            } else if (titleText != null) {
+                transaction.setBreadCrumbTitle(titleText);
+            }
+            transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
+            transaction.addToBackStack(BACK_STACK_PREFS);
+            transaction.commit();
+        }
     }
-
+    
+    /**
+     * Called by a preference panel fragment to finish itself.
+     * 
+     * @param caller The fragment that is asking to be finished.
+     * @param resultCode Optional result code to send back to the original
+     * launching fragment.
+     * @param resultData Optional result data to send back to the original
+     * launching fragment.
+     */
+    public void finishPreferencePanel(Fragment caller, int resultCode, Intent resultData) {
+        if (mSinglePane) {
+            setResult(resultCode, resultData);
+            finish();
+        } else {
+            if (caller != null) {
+                if (caller.getTargetFragment() != null) {
+                    caller.getTargetFragment().onActivityResult(caller.getTargetRequestCode(),
+                            resultCode, resultData);
+                }
+            }
+            // XXX be smarter about popping the stack.
+            onBackPressed();
+        }
+    }
+    
     @Override
     public boolean onPreferenceStartFragment(PreferenceFragment caller, Preference pref) {
-        Fragment f = Fragment.instantiate(this, pref.getFragment(), pref.getExtras());
-        FragmentTransaction transaction = getFragmentManager().openTransaction();
-        startPreferenceFragment(f, transaction);
-        transaction.setBreadCrumbTitle(pref.getTitle());
-        transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
-        transaction.addToBackStack(BACK_STACK_PREFS);
-        transaction.commit();
+        startPreferencePanel(pref.getFragment(), pref.getExtras(), 0, pref.getTitle(), null, 0);
         return true;
     }
 
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 9e6434a..f0aa878 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -5245,7 +5245,7 @@
                         return com.android.internal.R.string.eventTypeAnniversary;
                     case TYPE_BIRTHDAY: return com.android.internal.R.string.eventTypeBirthday;
                     case TYPE_OTHER: return com.android.internal.R.string.eventTypeOther;
-                    default: return com.android.internal.R.string.eventTypeOther;
+                    default: return com.android.internal.R.string.eventTypeCustom;
                 }
             }
         }
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index 7289012..ec8f031 100644
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -385,11 +385,23 @@
         // Allow 3 seconds for profiles to gracefully disconnect
         // TODO: Introduce a callback mechanism so that each profile can notify
         // BluetoothService when it is done shutting down
+        disconnectDevices();
+
         mHandler.sendMessageDelayed(
                 mHandler.obtainMessage(MESSAGE_FINISH_DISABLE, saveSetting ? 1 : 0, 0), 3000);
         return true;
     }
 
+    private synchronized void disconnectDevices() {
+        // Disconnect devices handled by BluetoothService.
+        for (BluetoothDevice device: getConnectedInputDevices()) {
+            disconnectInputDevice(device);
+        }
+
+        for (BluetoothDevice device: getConnectedPanDevices()) {
+            disconnectPanDevice(device);
+        }
+    }
 
     private synchronized void finishDisable(boolean saveSetting) {
         if (mBluetoothState != BluetoothAdapter.STATE_TURNING_OFF) {
diff --git a/core/java/android/text/InputType.java b/core/java/android/text/InputType.java
index 8592221..7b8acd9 100644
--- a/core/java/android/text/InputType.java
+++ b/core/java/android/text/InputType.java
@@ -228,6 +228,28 @@
      */
     public static final int TYPE_TEXT_VARIATION_PHONETIC = 0x000000c0;
     
+    /**
+     * Variation of {@link #TYPE_CLASS_TEXT}: entering e-mail address inside
+     * of a web form.  This was added in
+     * {@link android.os.Build.VERSION_CODES#HONEYCOMB}.  An IME must target
+     * this API version or later to see this input type; if it doesn't, a request
+     * for this type will be seen as {@link #TYPE_TEXT_VARIATION_EMAIL_ADDRESS}
+     * when passed through {@link android.view.inputmethod.EditorInfo#makeCompatible(int)
+     * EditorInfo.makeCompatible(int)}.
+     */
+    public static final int TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS = 0x000000d0;
+
+    /**
+     * Variation of {@link #TYPE_CLASS_TEXT}: entering password inside
+     * of a web form.  This was added in
+     * {@link android.os.Build.VERSION_CODES#HONEYCOMB}.  An IME must target
+     * this API version or later to see this input type; if it doesn't, a request
+     * for this type will be seen as {@link #TYPE_TEXT_VARIATION_PASSWORD}
+     * when passed through {@link android.view.inputmethod.EditorInfo#makeCompatible(int)
+     * EditorInfo.makeCompatible(int)}.
+     */
+    public static final int TYPE_TEXT_VARIATION_WEB_PASSWORD = 0x000000e0;
+
     // ----------------------------------------------------------------------
     // ----------------------------------------------------------------------
     // ----------------------------------------------------------------------
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 87e03cf..a9f0780 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -6296,8 +6296,14 @@
             if (invalidateCache) {
                 mPrivateFlags &= ~DRAWING_CACHE_VALID;
             }
-            final ViewParent p = mParent;
             final AttachInfo ai = mAttachInfo;
+            final ViewParent p = mParent;
+            if (p != null && ai != null && ai.mHardwareAccelerated) {
+                // fast-track for GL-enabled applications; just invalidate the whole hierarchy
+                // with a null dirty rect, which tells the ViewRoot to redraw everything
+                p.invalidateChild(this, null);
+                return;
+            }
             if (p != null && ai != null) {
                 final Rect r = ai.mTmpInvalRect;
                 r.set(0, 0, mRight - mLeft, mBottom - mTop);
@@ -6321,7 +6327,8 @@
      */
     @ViewDebug.ExportedProperty(category = "drawing")
     public boolean isOpaque() {
-        return (mPrivateFlags & OPAQUE_MASK) == OPAQUE_MASK;
+        return (mPrivateFlags & OPAQUE_MASK) == OPAQUE_MASK &&
+                (mAlpha >= 1.0f - ViewConfiguration.ALPHA_THRESHOLD);
     }
 
     private void computeOpaqueFlags() {
@@ -8618,7 +8625,11 @@
      */
     @RemotableViewMethod
     public void setBackgroundColor(int color) {
-        setBackgroundDrawable(new ColorDrawable(color));
+        if (mBGDrawable instanceof ColorDrawable) {
+            ((ColorDrawable) mBGDrawable).setColor(color);
+        } else {
+            setBackgroundDrawable(new ColorDrawable(color));
+        }
     }
 
     /**
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index b881bdd..0f9312c 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -1298,8 +1298,9 @@
      * Returns true if a child view contains the specified point when transformed
      * into its coordinate space.
      * Child must not be null.
+     * @hide
      */
-    private boolean isTransformedTouchPointInView(float x, float y, View child,
+    protected boolean isTransformedTouchPointInView(float x, float y, View child,
             PointF outLocalPoint) {
         float localX = x + mScrollX - child.mLeft;
         float localY = y + mScrollY - child.mTop;
@@ -2101,6 +2102,8 @@
         final int cr = child.mRight;
         final int cb = child.mBottom;
 
+        final boolean childHasIdentityMatrix = child.hasIdentityMatrix();
+
         final int flags = mGroupFlags;
 
         if ((flags & FLAG_CLEAR_TRANSFORMATION) == FLAG_CLEAR_TRANSFORMATION) {
@@ -2182,7 +2185,7 @@
             }
         }
 
-        concatMatrix |= !child.hasIdentityMatrix();
+        concatMatrix |= !childHasIdentityMatrix;
 
         // Sets the flag as early as possible to allow draw() implementations
         // to call invalidate() successfully when doing animations
@@ -2231,40 +2234,41 @@
         }
 
         if (transformToApply != null || alpha < 1.0f || !child.hasIdentityMatrix()) {
-            int transX = 0;
-            int transY = 0;
+            if (transformToApply != null || !childHasIdentityMatrix) {
+                int transX = 0;
+                int transY = 0;
 
-            if (hasNoCache) {
-                transX = -sx;
-                transY = -sy;
-            }
+                if (hasNoCache) {
+                    transX = -sx;
+                    transY = -sy;
+                }
 
-            if (transformToApply != null) {
-                if (concatMatrix) {
-                    // Undo the scroll translation, apply the transformation matrix,
-                    // then redo the scroll translate to get the correct result.
+                if (transformToApply != null) {
+                    if (concatMatrix) {
+                        // Undo the scroll translation, apply the transformation matrix,
+                        // then redo the scroll translate to get the correct result.
+                        canvas.translate(-transX, -transY);
+                        canvas.concat(transformToApply.getMatrix());
+                        canvas.translate(transX, transY);
+                        mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
+                    }
+
+                    float transformAlpha = transformToApply.getAlpha();
+                    if (transformAlpha < 1.0f) {
+                        alpha *= transformToApply.getAlpha();
+                        mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
+                    }
+                }
+
+                if (!childHasIdentityMatrix) {
                     canvas.translate(-transX, -transY);
-                    canvas.concat(transformToApply.getMatrix());
+                    canvas.concat(child.getMatrix());
                     canvas.translate(transX, transY);
-                    mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
                 }
-
-                float transformAlpha = transformToApply.getAlpha();
-                if (transformAlpha < 1.0f) {
-                    alpha *= transformToApply.getAlpha();
-                    mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
-                }
-            }
-
-            if (!child.hasIdentityMatrix()) {
-                canvas.translate(-transX, -transY);
-                canvas.concat(child.getMatrix());
-                canvas.translate(transX, transY);
             }
 
             if (alpha < 1.0f) {
                 mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
-
                 if (hasNoCache) {
                     final int multipliedAlpha = (int) (255 * alpha);
                     if (!child.onSetAlpha(multipliedAlpha)) {
@@ -3209,19 +3213,6 @@
 
         final AttachInfo attachInfo = mAttachInfo;
         if (attachInfo != null) {
-            final int[] location = attachInfo.mInvalidateChildLocation;
-            location[CHILD_LEFT_INDEX] = child.mLeft;
-            location[CHILD_TOP_INDEX] = child.mTop;
-            Matrix childMatrix = child.getMatrix();
-            if (!childMatrix.isIdentity()) {
-                RectF boundingRect = attachInfo.mTmpTransformRect;
-                boundingRect.set(dirty);
-                childMatrix.mapRect(boundingRect);
-                dirty.set((int) boundingRect.left, (int) boundingRect.top,
-                        (int) (boundingRect.right + 0.5f),
-                        (int) (boundingRect.bottom + 0.5f));
-            }
-
             // If the child is drawing an animation, we want to copy this flag onto
             // ourselves and the parent to make sure the invalidate request goes
             // through
@@ -3229,45 +3220,95 @@
 
             // Check whether the child that requests the invalidate is fully opaque
             final boolean isOpaque = child.isOpaque() && !drawAnimation &&
-                    child.getAnimation() != null;
+                    child.getAnimation() == null;
             // Mark the child as dirty, using the appropriate flag
             // Make sure we do not set both flags at the same time
             final int opaqueFlag = isOpaque ? DIRTY_OPAQUE : DIRTY;
 
-            do {
-                View view = null;
-                if (parent instanceof View) {
-                    view = (View) parent;
+            if (dirty == null) {
+                do {
+                    View view = null;
+                    if (parent instanceof View) {
+                        view = (View) parent;
+                        if ((view.mPrivateFlags & DIRTY_MASK) != 0) {
+                            // already marked dirty - we're done
+                            break;
+                        }
+                    }
+
+                    if (drawAnimation) {
+                        if (view != null) {
+                            view.mPrivateFlags |= DRAW_ANIMATION;
+                        } else if (parent instanceof ViewRoot) {
+                            ((ViewRoot) parent).mIsAnimating = true;
+                        }
+                    }
+
+                    if (parent instanceof ViewRoot) {
+                        ((ViewRoot) parent).invalidate();
+                        parent = null;
+                    } else if (view != null) {
+                        if ((mPrivateFlags & DRAWN) == DRAWN) {
+                            view.mPrivateFlags &= ~DRAWING_CACHE_VALID;
+                            if (view != null && (view.mPrivateFlags & DIRTY_MASK) != DIRTY) {
+                                view.mPrivateFlags =
+                                        (view.mPrivateFlags & ~DIRTY_MASK) | opaqueFlag;
+                            }
+                            parent = view.mParent;
+                        } else {
+                            parent = null;
+                        }
+                    }
+                } while (parent != null);
+            } else {
+                final int[] location = attachInfo.mInvalidateChildLocation;
+                location[CHILD_LEFT_INDEX] = child.mLeft;
+                location[CHILD_TOP_INDEX] = child.mTop;
+                Matrix childMatrix = child.getMatrix();
+                if (!childMatrix.isIdentity()) {
+                    RectF boundingRect = attachInfo.mTmpTransformRect;
+                    boundingRect.set(dirty);
+                    childMatrix.mapRect(boundingRect);
+                    dirty.set((int) boundingRect.left, (int) boundingRect.top,
+                            (int) (boundingRect.right + 0.5f),
+                            (int) (boundingRect.bottom + 0.5f));
                 }
 
-                if (drawAnimation) {
+                do {
+                    View view = null;
+                    if (parent instanceof View) {
+                        view = (View) parent;
+                    }
+
+                    if (drawAnimation) {
+                        if (view != null) {
+                            view.mPrivateFlags |= DRAW_ANIMATION;
+                        } else if (parent instanceof ViewRoot) {
+                            ((ViewRoot) parent).mIsAnimating = true;
+                        }
+                    }
+
+                    // If the parent is dirty opaque or not dirty, mark it dirty with the opaque
+                    // flag coming from the child that initiated the invalidate
+                    if (view != null && (view.mPrivateFlags & DIRTY_MASK) != DIRTY) {
+                        view.mPrivateFlags = (view.mPrivateFlags & ~DIRTY_MASK) | opaqueFlag;
+                    }
+
+                    parent = parent.invalidateChildInParent(location, dirty);
                     if (view != null) {
-                        view.mPrivateFlags |= DRAW_ANIMATION;
-                    } else if (parent instanceof ViewRoot) {
-                        ((ViewRoot) parent).mIsAnimating = true;
+                        // Account for transform on current parent
+                        Matrix m = view.getMatrix();
+                        if (!m.isIdentity()) {
+                            RectF boundingRect = attachInfo.mTmpTransformRect;
+                            boundingRect.set(dirty);
+                            m.mapRect(boundingRect);
+                            dirty.set((int) boundingRect.left, (int) boundingRect.top,
+                                    (int) (boundingRect.right + 0.5f),
+                                    (int) (boundingRect.bottom + 0.5f));
+                        }
                     }
-                }
-
-                // If the parent is dirty opaque or not dirty, mark it dirty with the opaque
-                // flag coming from the child that initiated the invalidate
-                if (view != null && (view.mPrivateFlags & DIRTY_MASK) != DIRTY) {
-                    view.mPrivateFlags = (view.mPrivateFlags & ~DIRTY_MASK) | opaqueFlag;
-                }
-
-                parent = parent.invalidateChildInParent(location, dirty);
-                if (view != null) {
-                    // Account for transform on current parent
-                    Matrix m = view.getMatrix();
-                    if (!m.isIdentity()) {
-                        RectF boundingRect = attachInfo.mTmpTransformRect;
-                        boundingRect.set(dirty);
-                        m.mapRect(boundingRect);
-                        dirty.set((int) boundingRect.left, (int) boundingRect.top,
-                                (int) (boundingRect.right + 0.5f),
-                                (int) (boundingRect.bottom + 0.5f));
-                    }
-                }
-            } while (parent != null);
+                } while (parent != null);
+            }
         }
     }
 
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 06261bb..22a7773 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -543,6 +543,11 @@
     public void invalidateChild(View child, Rect dirty) {
         checkThread();
         if (DEBUG_DRAW) Log.v(TAG, "Invalidate child: " + dirty);
+        if (dirty == null) {
+            // Fast invalidation for GL-enabled applications; GL must redraw everything
+            invalidate();
+            return;
+        }
         if (mCurScrollY != 0 || mTranslator != null) {
             mTempRect.set(dirty);
             dirty = mTempRect;
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 0b2d0f6..c657a1c 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -762,6 +762,12 @@
          */
         public static final int SOFT_INPUT_ADJUST_PAN = 0x20;
         
+        /** Adjustment option for {@link #softInputMode}: set to have a window
+         * not adjust for a shown input method.  The window will not be resized,
+         * and it will not be panned to make its focus visible.
+         */
+        public static final int SOFT_INPUT_ADJUST_NOTHING = 0x30;
+
         /**
          * Bit for {@link #softInputMode}: set when the user has navigated
          * forward to the window.  This is normally set automatically for
@@ -772,27 +778,6 @@
         public static final int SOFT_INPUT_IS_FORWARD_NAVIGATION = 0x100;
 
         /**
-         * Default value for {@link #screenBrightness} and {@link #buttonBrightness}
-         * indicating that the brightness value is not overridden for this window
-         * and normal brightness policy should be used.
-         */
-        public static final float BRIGHTNESS_OVERRIDE_NONE = -1.0f;
-
-        /**
-         * Value for {@link #screenBrightness} and {@link #buttonBrightness}
-         * indicating that the screen or button backlight brightness should be set
-         * to the lowest value when this window is in front.
-         */
-        public static final float BRIGHTNESS_OVERRIDE_OFF = 0.0f;
-
-        /**
-         * Value for {@link #screenBrightness} and {@link #buttonBrightness}
-         * indicating that the screen or button backlight brightness should be set
-         * to the hightest value when this window is in front.
-         */
-        public static final float BRIGHTNESS_OVERRIDE_FULL = 1.0f;
-
-        /**
          * Desired operating mode for any soft input area.  May any combination
          * of:
          * 
@@ -809,7 +794,17 @@
         public int softInputMode;
         
         /**
-         * Placement of window within the screen as per {@link Gravity}
+         * Placement of window within the screen as per {@link Gravity}.  Both
+         * {@link Gravity#apply(int, int, int, android.graphics.Rect, int, int,
+         * android.graphics.Rect) Gravity.apply} and
+         * {@link Gravity#applyDisplay(int, android.graphics.Rect, android.graphics.Rect)
+         * Gravity.applyDisplay} are used during window layout, with this value
+         * given as the desired gravity.  For example you can specify
+         * {@link Gravity#DISPLAY_CLIP_HORIZONTAL Gravity.DISPLAY_CLIP_HORIZONTAL} and
+         * {@link Gravity#DISPLAY_CLIP_VERTICAL Gravity.DISPLAY_CLIP_VERTICAL} here
+         * to control the behavior of
+         * {@link Gravity#applyDisplay(int, android.graphics.Rect, android.graphics.Rect)
+         * Gravity.applyDisplay}.
          *
          * @see Gravity
          */
@@ -817,13 +812,19 @@
     
         /**
          * The horizontal margin, as a percentage of the container's width,
-         * between the container and the widget.
+         * between the container and the widget.  See
+         * {@link Gravity#apply(int, int, int, android.graphics.Rect, int, int,
+         * android.graphics.Rect) Gravity.apply} for how this is used.  This
+         * field is added with {@link #x} to supply the <var>xAdj</var> parameter.
          */
         public float horizontalMargin;
     
         /**
          * The vertical margin, as a percentage of the container's height,
-         * between the container and the widget.
+         * between the container and the widget.  See
+         * {@link Gravity#apply(int, int, int, android.graphics.Rect, int, int,
+         * android.graphics.Rect) Gravity.apply} for how this is used.  This
+         * field is added with {@link #y} to supply the <var>yAdj</var> parameter.
          */
         public float verticalMargin;
     
@@ -852,6 +853,27 @@
          * dim.
          */
         public float dimAmount = 1.0f;
+
+        /**
+         * Default value for {@link #screenBrightness} and {@link #buttonBrightness}
+         * indicating that the brightness value is not overridden for this window
+         * and normal brightness policy should be used.
+         */
+        public static final float BRIGHTNESS_OVERRIDE_NONE = -1.0f;
+
+        /**
+         * Value for {@link #screenBrightness} and {@link #buttonBrightness}
+         * indicating that the screen or button backlight brightness should be set
+         * to the lowest value when this window is in front.
+         */
+        public static final float BRIGHTNESS_OVERRIDE_OFF = 0.0f;
+
+        /**
+         * Value for {@link #screenBrightness} and {@link #buttonBrightness}
+         * indicating that the screen or button backlight brightness should be set
+         * to the hightest value when this window is in front.
+         */
+        public static final float BRIGHTNESS_OVERRIDE_FULL = 1.0f;
     
         /**
          * This can be used to override the user's preferred brightness of
@@ -1162,14 +1184,22 @@
             sb.append('x');
             sb.append((height== MATCH_PARENT ?"fill":(height==WRAP_CONTENT?"wrap":height)));
             sb.append(")");
-            if (softInputMode != 0) {
-                sb.append(" sim=#");
-                sb.append(Integer.toHexString(softInputMode));
+            if (horizontalMargin != 0) {
+                sb.append(" hm=");
+                sb.append(horizontalMargin);
+            }
+            if (verticalMargin != 0) {
+                sb.append(" vm=");
+                sb.append(verticalMargin);
             }
             if (gravity != 0) {
                 sb.append(" gr=#");
                 sb.append(Integer.toHexString(gravity));
             }
+            if (softInputMode != 0) {
+                sb.append(" sim=#");
+                sb.append(Integer.toHexString(softInputMode));
+            }
             sb.append(" ty=");
             sb.append(type);
             sb.append(" fl=#");
@@ -1184,6 +1214,18 @@
                 sb.append(" or=");
                 sb.append(screenOrientation);
             }
+            if (alpha != 1.0f) {
+                sb.append(" alpha=");
+                sb.append(alpha);
+            }
+            if (screenBrightness != BRIGHTNESS_OVERRIDE_NONE) {
+                sb.append(" sbrt=");
+                sb.append(screenBrightness);
+            }
+            if (buttonBrightness != BRIGHTNESS_OVERRIDE_NONE) {
+                sb.append(" bbrt=");
+                sb.append(buttonBrightness);
+            }
             if ((flags & FLAG_COMPATIBLE_WINDOW) != 0) {
                 sb.append(" compatible=true");
             }
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 1fd31a3..1a341e1 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -544,16 +544,18 @@
      * Generally, it's best to keep as little as possible in the queue thread
      * because it's the most fragile.
      * @param whenNanos The event time in uptime nanoseconds.
+     * @param action The key event action.
+     * @param flags The key event flags.
      * @param keyCode The key code.
-     * @param down True if the key is down.
+     * @param scanCode The key's scan code.
      * @param policyFlags The policy flags associated with the key.
      * @param isScreenOn True if the screen is already on
      *
      * @return The bitwise or of the {@link #ACTION_PASS_TO_USER},
      *          {@link #ACTION_POKE_USER_ACTIVITY} and {@link #ACTION_GO_TO_SLEEP} flags.
      */
-    public int interceptKeyBeforeQueueing(long whenNanos, int keyCode, boolean down, int policyFlags,
-            boolean isScreenOn);
+    public int interceptKeyBeforeQueueing(long whenNanos, int action, int flags,
+            int keyCode, int scanCode, int policyFlags, boolean isScreenOn);
     
     /**
      * Called from the input dispatcher thread before a key is dispatched to a window.
@@ -571,6 +573,7 @@
      * @param action The key event action.
      * @param flags The key event flags.
      * @param keyCode The key code.
+     * @param scanCode The key's scan code.
      * @param metaState bit mask of meta keys that are held.
      * @param repeatCount Number of times a key down has repeated.
      * @param policyFlags The policy flags associated with the key.
@@ -578,7 +581,7 @@
      * not be further dispatched.
      */
     public boolean interceptKeyBeforeDispatching(WindowState win, int action, int flags,
-            int keyCode, int metaState, int repeatCount, int policyFlags);
+            int keyCode, int scanCode, int metaState, int repeatCount, int policyFlags);
 
     /**
      * Called when layout of the windows is about to start.
diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java
index b98dcd2..300e5d6 100644
--- a/core/java/android/view/inputmethod/EditorInfo.java
+++ b/core/java/android/view/inputmethod/EditorInfo.java
@@ -94,6 +94,45 @@
     public static final int IME_ACTION_DONE = 0x00000006;
     
     /**
+     * Bits of {@link #IME_MASK_ACTION}: Like {@link #IME_ACTION_NEXT}, but
+     * for moving to the previous field.  This will normally not be used to
+     * specify an action (since it precludes {@link #IME_ACTION_NEXT}, but
+     * can be returned to the app if it sets {@link #IME_FLAG_NAVIGATE_PREVIOUS}.
+     */
+    public static final int IME_ACTION_PREVIOUS = 0x00000007;
+
+    /**
+     * Flag of {@link #imeOptions}: used to request that the IME never go
+     * into fullscreen mode.  Applications need to be aware that the flag is not
+     * a guarantee, and not all IMEs will respect it.
+     */
+    public static final int IME_FLAG_NO_FULLSCREEN = 0x2000000;
+
+    /**
+     * Flag of {@link #imeOptions}: like {@link #IME_FLAG_NAVIGATE_NEXT}, but
+     * specifies there is something interesting that a backward navigation
+     * can focus on.  If the user selects the IME's facility to backward
+     * navigate, this will show up in the application as an {@link #IME_ACTION_PREVIOUS}
+     * at {@link InputConnection#performEditorAction(int)
+     * InputConnection.performEditorAction(int)}.
+     */
+    public static final int IME_FLAG_NAVIGATE_PREVIOUS = 0x4000000;
+
+    /**
+     * Flag of {@link #imeOptions}: used to specify that there is something
+     * interesting that a forward navigation can focus on. This is like using
+     * {@link #IME_ACTION_NEXT}, except allows the IME to be multiline (with
+     * an enter key) as well as provide forward navigation.  Note that some
+     * IMEs may not be able to do this, especially when running on a small
+     * screen where there is little space.  In that case it does not need to
+     * present a UI for this option.  Like {@link #IME_ACTION_NEXT}, if the
+     * user selects the IME's facility to forward navigate, this will show up
+     * in the application at {@link InputConnection#performEditorAction(int)
+     * InputConnection.performEditorAction(int)}.
+     */
+    public static final int IME_FLAG_NAVIGATE_NEXT = 0x8000000;
+
+    /**
      * Flag of {@link #imeOptions}: used to specify that the IME does not need
      * to show its extracted text UI.  For input methods that may be fullscreen,
      * often when in landscape mode, this allows them to be smaller and let part
@@ -129,14 +168,6 @@
     public static final int IME_FLAG_NO_ENTER_ACTION = 0x40000000;
 
     /**
-     * Flag of {@link #imeOptions}: used to request that the IME never go
-     * into fullscreen mode.  Applications need to be aware that the flag is not
-     * a guarantee, and not all IMEs will respect it.
-     * @hide
-     */
-    public static final int IME_FLAG_NO_FULLSCREEN = 0x80000000;
-
-    /**
      * Generic unspecified type for {@link #imeOptions}.
      */
     public static final int IME_NULL = 0x00000000;
@@ -240,6 +271,34 @@
     public Bundle extras;
     
     /**
+     * Ensure that the data in this EditorInfo is compatible with an application
+     * that was developed against the given target API version.  This can
+     * impact the following input types:
+     * {@link InputType#TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS},
+     * {@link InputType#TYPE_TEXT_VARIATION_WEB_PASSWORD}.
+     *
+     * <p>This is called by the framework for input method implementations;
+     * you should not generally need to call it yourself.
+     *
+     * @param targetSdkVersion The API version number that the compatible
+     * application was developed against.
+     */
+    public final void makeCompatible(int targetSdkVersion) {
+        if (targetSdkVersion < android.os.Build.VERSION_CODES.HONEYCOMB) {
+            switch (inputType&(TYPE_MASK_CLASS|TYPE_MASK_VARIATION)) {
+                case TYPE_CLASS_TEXT|TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS:
+                    inputType = TYPE_CLASS_TEXT|TYPE_TEXT_VARIATION_EMAIL_ADDRESS
+                            | (inputType&(~TYPE_MASK_FLAGS));
+                    break;
+                case TYPE_CLASS_TEXT|TYPE_TEXT_VARIATION_WEB_PASSWORD:
+                    inputType = TYPE_CLASS_TEXT|TYPE_TEXT_VARIATION_PASSWORD
+                            | (inputType&(~TYPE_MASK_FLAGS));
+                    break;
+            }
+        }
+    }
+
+    /**
      * Write debug output of this object.
      */
     public void dump(Printer pw, String prefix) {
diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java
index 3bcd483a4..14dc61d 100644
--- a/core/java/android/webkit/WebTextView.java
+++ b/core/java/android/webkit/WebTextView.java
@@ -370,6 +370,7 @@
             int candEnd = EditableInputConnection.getComposingSpanEnd(sp);
             imm.updateSelection(this, selStart, selEnd, candStart, candEnd);
         }
+        updateCursorControllerPositions();
     }
 
     @Override
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 72b4e36..f5affe5 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -3477,7 +3477,9 @@
         if (AUTO_REDRAW_HACK && mAutoRedraw) {
             invalidate();
         }
-        if (inEditingMode()) mWebTextView.onDrawSubstitute();
+        if (inEditingMode()) {
+            mWebTextView.onDrawSubstitute();
+        }
         mWebViewCore.signalRepaintDone();
 
         // paint the highlight in the end
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 9a873b6..9edb267 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -472,6 +472,11 @@
      */
     private native int nativeRecordContent(Region invalRegion, Point wh);
 
+    /**
+     * Update the layers' content
+     */
+    private native int nativeUpdateLayers();
+
     private native boolean nativeFocusBoundsChanged();
 
     /**
@@ -798,6 +803,7 @@
             "FREE_MEMORY",  // = 145
             "VALID_NODE_BOUNDS", // = 146
             "SAVE_WEBARCHIVE", // = 147
+            "WEBKIT_DRAW_LAYERS", // = 148;
         };
 
     class EventHub {
@@ -868,6 +874,9 @@
         // Load and save web archives
         static final int SAVE_WEBARCHIVE = 147;
 
+        // Update layers
+        static final int WEBKIT_DRAW_LAYERS = 148;
+
         // Network-based messaging
         static final int CLEAR_SSL_PREF_TABLE = 150;
 
@@ -953,6 +962,10 @@
                             webkitDraw();
                             break;
 
+                        case WEBKIT_DRAW_LAYERS:
+                            webkitDrawLayers();
+                            break;
+
                         case DESTROY:
                             // Time to take down the world. Cancel all pending
                             // loads and destroy the native view and frame.
@@ -1800,6 +1813,7 @@
 
     // Used to avoid posting more than one draw message.
     private boolean mDrawIsScheduled;
+    private boolean mDrawLayersIsScheduled;
 
     // Used to avoid posting more than one split picture message.
     private boolean mSplitPictureIsScheduled;
@@ -1839,6 +1853,20 @@
         boolean mFocusSizeChanged;
     }
 
+    // Only update the layers' content, not the base surface
+    // PictureSet.
+    private void webkitDrawLayers() {
+        mDrawLayersIsScheduled = false;
+        if (mDrawIsScheduled) {
+            removeMessages(EventHub.WEBKIT_DRAW);
+            webkitDraw();
+            return;
+        }
+        DrawData draw = new DrawData();
+        draw.mBaseLayer = nativeUpdateLayers();
+        webkitDraw(draw);
+    }
+
     private void webkitDraw() {
         mDrawIsScheduled = false;
         DrawData draw = new DrawData();
@@ -1848,6 +1876,10 @@
             if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, "webkitDraw abort");
             return;
         }
+        webkitDraw(draw);
+    }
+
+    private void webkitDraw(DrawData draw) {
         if (mWebView != null) {
             draw.mFocusSizeChanged = nativeFocusBoundsChanged();
             draw.mViewSize = new Point(mCurrentViewWidth, mCurrentViewHeight);
@@ -1957,6 +1989,15 @@
         }
     }
 
+    // called from JNI
+    void layersDraw() {
+        synchronized (this) {
+            if (mDrawLayersIsScheduled) return;
+            mDrawLayersIsScheduled = true;
+            mEventHub.sendMessage(Message.obtain(null, EventHub.WEBKIT_DRAW_LAYERS));
+        }
+    }
+
     // called by JNI
     private void contentScrollBy(int dx, int dy, boolean animate) {
         if (!mBrowserFrame.firstLayoutDone()) {
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 728c2a7..4e90ecd 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2501,7 +2501,7 @@
 
                     deltaY -= mMotionCorrection;
                     int incrementalDeltaY = mLastY != Integer.MIN_VALUE ? y - mLastY : deltaY;
-                    
+
                     // No need to do all this work if we're not going to move anyway
                     boolean atEdge = false;
                     if (incrementalDeltaY != 0) {
diff --git a/core/java/android/widget/AbsoluteLayout.java b/core/java/android/widget/AbsoluteLayout.java
index b829655..970cbe3 100644
--- a/core/java/android/widget/AbsoluteLayout.java
+++ b/core/java/android/widget/AbsoluteLayout.java
@@ -187,7 +187,7 @@
          * </ul>
          *
          * @param c the application environment
-         * @param attrs the set of attributes fom which to extract the layout
+         * @param attrs the set of attributes from which to extract the layout
          *              parameters values
          */
         public LayoutParams(Context c, AttributeSet attrs) {
diff --git a/core/java/android/widget/AdapterViewAnimator.java b/core/java/android/widget/AdapterViewAnimator.java
index 5ac047c..1f98c88 100644
--- a/core/java/android/widget/AdapterViewAnimator.java
+++ b/core/java/android/widget/AdapterViewAnimator.java
@@ -24,16 +24,16 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.TypedArray;
+import android.graphics.Rect;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.AttributeSet;
+import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewConfiguration;
 import android.view.ViewGroup;
-import android.view.ViewGroup.LayoutParams;
-import android.view.animation.Animation;
-import android.view.animation.AnimationUtils;
 
 /**
  * Base class for a {@link AdapterView} that will perform animations
@@ -141,6 +141,20 @@
     ObjectAnimator mInAnimation;
     ObjectAnimator mOutAnimation;
 
+    /**
+     * Current touch state.
+     */
+    private int mTouchMode = TOUCH_MODE_NONE;
+
+    /**
+     * Private touch states.
+     */
+    static final int TOUCH_MODE_NONE = 0;
+    static final int TOUCH_MODE_DOWN_IN_CURRENT_VIEW = 1;
+    static final int TOUCH_MODE_HANDLED = 2;
+
+    private Runnable mPendingCheckForTap;
+
     private static final int DEFAULT_ANIMATION_DURATION = 200;
 
     public AdapterViewAnimator(Context context) {
@@ -528,7 +542,6 @@
             // above the layout will end up being ignored since we are currently laying out, so
             // we post a delayed requestLayout and invalidate
             mMainQueue.post(new Runnable() {
-                @Override
                 public void run() {
                     requestLayout();
                     invalidate();
@@ -551,6 +564,89 @@
         }
     }
 
+    void showTapFeedback(View v) {
+        v.setPressed(true);
+    }
+
+    void hideTapFeedback(View v) {
+        v.setPressed(false);
+    }
+
+    void cancelHandleClick() {
+        View v = getCurrentView();
+        if (v != null) {
+            hideTapFeedback(v);
+        }
+        mTouchMode = TOUCH_MODE_NONE;
+    }
+
+    final class CheckForTap implements Runnable {
+        public void run() {
+            if (mTouchMode == TOUCH_MODE_DOWN_IN_CURRENT_VIEW) {
+                View v = getCurrentView();
+                showTapFeedback(v);
+            }
+        }
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        int action = ev.getAction();
+        boolean handled = false;
+        switch (action) {
+            case MotionEvent.ACTION_DOWN: {
+                View v = getCurrentView();
+                if (v != null) {
+                    if (isTransformedTouchPointInView(ev.getX(), ev.getY(), v, null)) {
+                        if (mPendingCheckForTap == null) {
+                            mPendingCheckForTap = new CheckForTap();
+                        }
+                        mTouchMode = TOUCH_MODE_DOWN_IN_CURRENT_VIEW;
+                        postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
+                    }
+                }
+                break;
+            }
+            case MotionEvent.ACTION_MOVE: break;
+            case MotionEvent.ACTION_POINTER_UP: break;
+            case MotionEvent.ACTION_UP: {
+                if (mTouchMode == TOUCH_MODE_DOWN_IN_CURRENT_VIEW) {
+                    final View v = getCurrentView();
+                    if (v != null) {
+                        if (isTransformedTouchPointInView(ev.getX(), ev.getY(), v, null)) {
+                            final Handler handler = getHandler();
+                            if (handler != null) {
+                                handler.removeCallbacks(mPendingCheckForTap);
+                            }
+                            showTapFeedback(v);
+                            postDelayed(new Runnable() {
+                                public void run() {
+                                    hideTapFeedback(v);
+                                    post(new Runnable() {
+                                        public void run() {
+                                            performItemClick(v, 0, 0);
+                                        }
+                                    });
+                                }
+                            }, ViewConfiguration.getPressedStateDuration());
+                            handled = true;
+                        }
+                    }
+                }
+                mTouchMode = TOUCH_MODE_NONE;
+                break;
+            }
+            case MotionEvent.ACTION_CANCEL: {
+                View v = getCurrentView();
+                if (v != null) {
+                    hideTapFeedback(v);
+                }
+                mTouchMode = TOUCH_MODE_NONE;
+            }
+        }
+        return handled;
+    }
+
     private void measureChildren() {
         final int count = getChildCount();
         final int childWidth = mMeasuredWidth - mPaddingLeft - mPaddingRight;
diff --git a/core/java/android/widget/MediaController.java b/core/java/android/widget/MediaController.java
index 39b1377..be1234d 100644
--- a/core/java/android/widget/MediaController.java
+++ b/core/java/android/widget/MediaController.java
@@ -413,33 +413,46 @@
     @Override
     public boolean dispatchKeyEvent(KeyEvent event) {
         int keyCode = event.getKeyCode();
-        if (event.getRepeatCount() == 0 && event.isDown() && (
-                keyCode ==  KeyEvent.KEYCODE_HEADSETHOOK ||
-                keyCode ==  KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE ||
-                keyCode ==  KeyEvent.KEYCODE_SPACE)) {
-            doPauseResume();
-            show(sDefaultTimeout);
-            if (mPauseButton != null) {
-                mPauseButton.requestFocus();
+        final boolean uniqueDown = event.getRepeatCount() == 0
+                && event.getAction() == KeyEvent.ACTION_DOWN;
+        if (keyCode ==  KeyEvent.KEYCODE_HEADSETHOOK
+                || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE
+                || keyCode == KeyEvent.KEYCODE_SPACE) {
+            if (uniqueDown) {
+                doPauseResume();
+                show(sDefaultTimeout);
+                if (mPauseButton != null) {
+                    mPauseButton.requestFocus();
+                }
             }
             return true;
-        } else if (keyCode ==  KeyEvent.KEYCODE_MEDIA_STOP) {
-            if (mPlayer.isPlaying()) {
+        } else if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY) {
+            if (uniqueDown && !mPlayer.isPlaying()) {
+                mPlayer.start();
+                updatePausePlay();
+                show(sDefaultTimeout);
+            }
+            return true;
+        } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP
+                || keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE) {
+            if (uniqueDown && mPlayer.isPlaying()) {
                 mPlayer.pause();
                 updatePausePlay();
+                show(sDefaultTimeout);
             }
             return true;
-        } else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN ||
-                keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
+        } else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
+                || keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
             // don't show the controls for volume adjustment
             return super.dispatchKeyEvent(event);
         } else if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU) {
-            hide();
-
+            if (uniqueDown) {
+                hide();
+            }
             return true;
-        } else {
-            show(sDefaultTimeout);
         }
+
+        show(sDefaultTimeout);
         return super.dispatchKeyEvent(event);
     }
 
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 9d214fc..24165aa 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -45,6 +45,7 @@
 import android.view.ViewGroup;
 import android.view.LayoutInflater.Filter;
 import android.view.View.OnClickListener;
+import android.widget.AdapterView.OnItemClickListener;
 
 
 /**
@@ -110,7 +111,7 @@
             super(message);
         }
     }
-    
+
     /**
      * Base class for all actions that can be performed on an 
      * inflated view.
@@ -132,6 +133,25 @@
             // here
             return;
         }
+
+        protected boolean startIntentSafely(Context context, PendingIntent pendingIntent,
+                Intent fillInIntent) {
+            try {
+                // TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT?
+                context.startIntentSender(
+                        pendingIntent.getIntentSender(), fillInIntent,
+                        Intent.FLAG_ACTIVITY_NEW_TASK,
+                        Intent.FLAG_ACTIVITY_NEW_TASK, 0);
+            } catch (IntentSender.SendIntentException e) {
+                android.util.Log.e(LOG_TAG, "Cannot send pending intent: ", e);
+                return false;
+            } catch (Exception e) {
+                android.util.Log.e(LOG_TAG, "Cannot send pending intent due to " +
+                        "unknown exception: ", e);
+                return false;
+            }
+            return true;
+        }
     }
 
     private class SetEmptyView extends Action {
@@ -190,14 +210,16 @@
         @Override
         public void apply(View root) {
             final View target = root.findViewById(viewId);
+            if (target == null) return;
 
             if (!mIsWidgetCollectionChild) {
                 Log.e("RemoteViews", "The method setOnClickFillInIntent is available " +
                         "only from RemoteViewsFactory (ie. on collection items).");
                 return;
             }
-
-            if (target != null && fillInIntent != null) {
+            if (target == root) {
+                target.setTagInternal(com.android.internal.R.id.fillInIntent, fillInIntent);
+            } else if (target != null && fillInIntent != null) {
                 OnClickListener listener = new OnClickListener() {
                     public void onClick(View v) {
                         // Insure that this view is a child of an AdapterView
@@ -217,14 +239,14 @@
                         // Insure that a template pending intent has been set on an ancestor
                         if (!(parent.getTag() instanceof PendingIntent)) {
                             Log.e("RemoteViews", "Attempting setOnClickFillInIntent without" +
-					" calling setPendingIntentTemplate on parent.");
+                                    " calling setPendingIntentTemplate on parent.");
                             return;
                         }
 
                         PendingIntent pendingIntent = (PendingIntent) parent.getTag();
 
                         final float appScale = v.getContext().getResources()
-                        .getCompatibilityInfo().applicationScale;
+                                .getCompatibilityInfo().applicationScale;
                         final int[] pos = new int[2];
                         v.getLocationOnScreen(pos);
 
@@ -235,15 +257,7 @@
                         rect.bottom = (int) ((pos[1] + v.getHeight()) * appScale + 0.5f);
 
                         fillInIntent.setSourceBounds(rect);
-                        try {
-                            // TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT?
-                            v.getContext().startIntentSender(
-                                    pendingIntent.getIntentSender(), fillInIntent,
-                                    Intent.FLAG_ACTIVITY_NEW_TASK,
-                                    Intent.FLAG_ACTIVITY_NEW_TASK, 0);
-                        } catch (IntentSender.SendIntentException e) {
-                            android.util.Log.e(LOG_TAG, "Cannot send pending intent: ", e);
-                        }
+                        startIntentSafely(v.getContext(), pendingIntent, fillInIntent);
                     }
 
                 };
@@ -257,96 +271,6 @@
         public final static int TAG = 9;
     }
 
-    private class SetOnClickExtras extends Action {
-        public SetOnClickExtras(int id, Bundle extras) {
-            this.viewId = id;
-            this.extras = extras;
-        }
-
-        public SetOnClickExtras(Parcel parcel) {
-            viewId = parcel.readInt();
-            extras = Bundle.CREATOR.createFromParcel(parcel);
-        }
-
-        public void writeToParcel(Parcel dest, int flags) {
-            dest.writeInt(TAG);
-            dest.writeInt(viewId);
-            extras.writeToParcel(dest, 0 /* no flags */);
-        }
-
-        @Override
-        public void apply(View root) {
-            final View target = root.findViewById(viewId);
-
-            if (!mIsWidgetCollectionChild) {
-                Log.e("RemoteViews", "The method setOnClickExtras is available " +
-                        "only from RemoteViewsFactory (ie. on collection items).");
-                return;
-            }
-
-            if (target != null && extras != null) {
-                OnClickListener listener = new OnClickListener() {
-                    public void onClick(View v) {
-                        // Insure that this view is a child of an AdapterView
-                        View parent = (View) v.getParent();
-                        while (!(parent instanceof AdapterView<?>)
-                                && !(parent instanceof AppWidgetHostView)) {
-                            parent = (View) parent.getParent();
-                        }
-
-                        if (parent instanceof AppWidgetHostView) {
-                            // Somehow they've managed to get this far without having
-                            // and AdapterView as a parent.
-                            Log.e("RemoteViews", "Collection item doesn't have AdapterView parent");
-                            return;
-                        }
-
-                        // Insure that a template pending intent has been set on an ancestor
-                        if (!(parent.getTag() instanceof PendingIntent)) {
-                            Log.e("RemoteViews", "Attempting setOnClickExtras without calling " +
-                                "setPendingIntentTemplate on parent.");
-                            return;
-                        }
-
-                        PendingIntent pendingIntent = (PendingIntent) parent.getTag();
-
-                        final float appScale = v.getContext().getResources()
-                        .getCompatibilityInfo().applicationScale;
-                        final int[] pos = new int[2];
-                        v.getLocationOnScreen(pos);
-
-                        final Rect rect = new Rect();
-                        rect.left = (int) (pos[0] * appScale + 0.5f);
-                        rect.top = (int) (pos[1] * appScale + 0.5f);
-                        rect.right = (int) ((pos[0] + v.getWidth()) * appScale + 0.5f);
-                        rect.bottom = (int) ((pos[1] + v.getHeight()) * appScale + 0.5f);
-
-                        final Intent intent = new Intent();
-                        intent.setSourceBounds(rect);
-                        intent.putExtras(extras);
-
-                        try {
-                            // TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT?
-                            v.getContext().startIntentSender(
-                                    pendingIntent.getIntentSender(), intent,
-                                    Intent.FLAG_ACTIVITY_NEW_TASK,
-                                    Intent.FLAG_ACTIVITY_NEW_TASK, 0);
-                        } catch (IntentSender.SendIntentException e) {
-                            android.util.Log.e(LOG_TAG, "Cannot send pending intent: ", e);
-                        }
-                    }
-
-                };
-                target.setOnClickListener(listener);
-            }
-        }
-
-        int viewId;
-        Bundle extras;
-
-        public final static int TAG = 7;
-    }
-
     private class SetPendingIntentTemplate extends Action {
         public SetPendingIntentTemplate(int id, PendingIntent pendingIntentTemplate) {
             this.viewId = id;
@@ -367,11 +291,56 @@
         @Override
         public void apply(View root) {
             final View target = root.findViewById(viewId);
+            if (target == null) return;
 
             // If the view isn't an AdapterView, setting a PendingIntent template doesn't make sense
             if (target instanceof AdapterView<?>) {
+                AdapterView<?> av = (AdapterView<?>) target;
                 // The PendingIntent template is stored in the view's tag.
-                target.setTag(pendingIntentTemplate);
+                OnItemClickListener listener = new OnItemClickListener() {
+                    public void onItemClick(AdapterView<?> parent, View view,
+                            int position, long id) {
+                        // The view should be a frame layout
+                        if (view instanceof ViewGroup) {
+                            ViewGroup vg = (ViewGroup) view;
+
+                            // AdapterViews contain their children in a frame
+                            // so we need to go one layer deeper here.
+                            if (parent instanceof AdapterViewAnimator) {
+                                vg = (ViewGroup) vg.getChildAt(0);
+                            }
+                            if (vg == null) return;
+
+                            Intent fillInIntent = null;
+                            int childCount = vg.getChildCount();
+                            for (int i = 0; i < childCount; i++) {
+                                Object tag = vg.getChildAt(i).getTag(com.android.internal.R.id.fillInIntent);
+                                if (tag instanceof Intent) {
+                                    fillInIntent = (Intent) tag;
+                                    break;
+                                }
+                            }
+                            if (fillInIntent == null) return;
+
+                            final float appScale = view.getContext().getResources()
+                                    .getCompatibilityInfo().applicationScale;
+                            final int[] pos = new int[2];
+                            view.getLocationOnScreen(pos);
+
+                            final Rect rect = new Rect();
+                            rect.left = (int) (pos[0] * appScale + 0.5f);
+                            rect.top = (int) (pos[1] * appScale + 0.5f);
+                            rect.right = (int) ((pos[0] + view.getWidth()) * appScale + 0.5f);
+                            rect.bottom = (int) ((pos[1] + view.getHeight()) * appScale + 0.5f);
+
+                            final Intent intent = new Intent();
+                            intent.setSourceBounds(rect);
+                            startIntentSafely(view.getContext(), pendingIntentTemplate, fillInIntent);
+                        }
+                    }
+                };
+                av.setOnItemClickListener(listener);
+                av.setTag(pendingIntentTemplate);
             } else {
                 Log.e("RemoteViews", "Cannot setPendingIntentTemplate on a view which is not" +
                         "an AdapterView (id: " + viewId + ")");
@@ -410,6 +379,7 @@
         @Override
         public void apply(View root) {
             final View target = root.findViewById(viewId);
+            if (target == null) return;
 
             // If the view is an AdapterView, setting a PendingIntent on click doesn't make much
             // sense, do they mean to set a PendingIntent template for the AdapterView's children?
@@ -437,15 +407,7 @@
 
                         final Intent intent = new Intent();
                         intent.setSourceBounds(rect);
-                        try {
-                            // TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT?
-                            v.getContext().startIntentSender(
-                                    pendingIntent.getIntentSender(), intent,
-                                    Intent.FLAG_ACTIVITY_NEW_TASK,
-                                    Intent.FLAG_ACTIVITY_NEW_TASK, 0);
-                        } catch (IntentSender.SendIntentException e) {
-                            android.util.Log.e(LOG_TAG, "Cannot send pending intent: ", e);
-                        }
+                        startIntentSafely(v.getContext(), pendingIntent, intent);
                     }
                 };
                 target.setOnClickListener(listener);
@@ -513,9 +475,7 @@
         @Override
         public void apply(View root) {
             final View target = root.findViewById(viewId);
-            if (target == null) {
-                return;
-            }
+            if (target == null) return;
             
             // Pick the correct drawable to modify for this view
             Drawable targetDrawable = null;
@@ -575,9 +535,7 @@
         @Override
         public void apply(View root) {
             final View view = root.findViewById(viewId);
-            if (view == null) {
-                throw new ActionException("can't find view: 0x" + Integer.toHexString(viewId));
-            }
+            if (view == null) return;
 
             Class klass = view.getClass();
             Method method;
@@ -793,9 +751,7 @@
         @Override
         public void apply(View root) {
             final View view = root.findViewById(viewId);
-            if (view == null) {
-                throw new ActionException("can't find view: 0x" + Integer.toHexString(viewId));
-            }
+            if (view == null) return;
 
             Class param = getParameterType();
             if (param == null) {
@@ -888,10 +844,11 @@
         public void apply(View root) {
             final Context context = root.getContext();
             final ViewGroup target = (ViewGroup) root.findViewById(viewId);
+            if (target == null) return;
             if (nestedViews != null) {
                 // Inflate nested views and add as children
                 target.addView(nestedViews.apply(context, target));
-            } else if (target != null) {
+            } else {
                 // Clear all children when nested views omitted
                 target.removeAllViews();
             }
@@ -980,9 +937,6 @@
                 case SetEmptyView.TAG:
                     mActions.add(new SetEmptyView(parcel));
                     break;
-                case SetOnClickExtras.TAG:
-                    mActions.add(new SetOnClickExtras(parcel));
-                    break;
                 case SetPendingIntentTemplate.TAG:
                     mActions.add(new SetPendingIntentTemplate(parcel));
                     break;
@@ -1246,16 +1200,6 @@
     }
 
     /**
-     * Being deprecated. See {@link RemoteViews#setOnClickFillInIntent(int, Intent)}.
-     *
-     * @param viewId
-     * @param extras
-     */
-    public void setOnClickExtras(int viewId, Bundle extras) {
-        addAction(new SetOnClickExtras(viewId, extras));
-    }
-
-    /**
      * When using collections (eg. {@link ListView}, {@link StackView} etc.) in widgets, it is very
      * costly to set PendingIntents on the individual items, and is hence not permitted. Instead
      * a single PendingIntent template can be set on the collection, see {@link
diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java
index 40ac76c..26eb57c 100644
--- a/core/java/android/widget/RemoteViewsAdapter.java
+++ b/core/java/android/widget/RemoteViewsAdapter.java
@@ -319,7 +319,7 @@
                 if (mUserLoadingView != null) {
                     // A user-specified loading view
                     View loadingView = mUserLoadingView.apply(parent.getContext(), parent);
-                    loadingView.setTag(new Integer(0));
+                    loadingView.setTagInternal(com.android.internal.R.id.rowTypeId, new Integer(0));
                     layout.addView(loadingView);
                 } else {
                     // A default loading view
@@ -470,7 +470,9 @@
             int mem = 0;
             for (Integer i : mIndexRemoteViews.keySet()) {
                 final RemoteViews v = mIndexRemoteViews.get(i);
-                mem += v.estimateBitmapMemoryUsage();
+                if (v != null) {
+                    mem += v.estimateBitmapMemoryUsage();
+                }
             }
             return mem;
         }
@@ -739,8 +741,11 @@
      */
     private int getConvertViewTypeId(View convertView) {
         int typeId = -1;
-        if (convertView != null && convertView.getTag() != null) {
-            typeId = (Integer) convertView.getTag();
+        if (convertView != null) {
+            Object tag = convertView.getTag(com.android.internal.R.id.rowTypeId);
+            if (tag != null) {
+                typeId = (Integer) tag;
+            }
         }
         return typeId;
     }
@@ -779,7 +784,7 @@
 
                     // Otherwise, create a new view to be returned
                     View newView = rv.apply(context, parent);
-                    newView.setTag(new Integer(typeId));
+                    newView.setTagInternal(com.android.internal.R.id.rowTypeId, new Integer(typeId));
                     if (convertView != null) {
                         layout.removeAllViews();
                     } else {
diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java
index e6d5984..a27e1cc 100644
--- a/core/java/android/widget/StackView.java
+++ b/core/java/android/widget/StackView.java
@@ -429,11 +429,14 @@
 
             // We only register this gesture if we've made it this far without a problem
             mSwipeGestureType = swipeGestureType;
+            cancelHandleClick();
         }
     }
 
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
+        super.onTouchEvent(ev);
+
         int action = ev.getAction();
         int pointerIndex = ev.findPointerIndex(mActivePointerId);
         if (pointerIndex == INVALID_POINTER) {
diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java
index 36adacd..ce4e8e5 100644
--- a/core/java/android/widget/TabWidget.java
+++ b/core/java/android/widget/TabWidget.java
@@ -115,7 +115,6 @@
     }
 
     private void initTabWidget() {
-        setOrientation(LinearLayout.HORIZONTAL);
         mGroupFlags |= FLAG_USE_CHILD_DRAWING_ORDER;
 
         final Context context = mContext;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index ef15f6f..2fcae1c 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -3229,7 +3229,8 @@
      * for this text view.  The default implementation will call your action
      * listener supplied to {@link #setOnEditorActionListener}, or perform
      * a standard operation for {@link EditorInfo#IME_ACTION_NEXT
-     * EditorInfo.IME_ACTION_NEXT} or {@link EditorInfo#IME_ACTION_DONE
+     * EditorInfo.IME_ACTION_NEXT}, {@link EditorInfo#IME_ACTION_PREVIOUS
+     * EditorInfo.IME_ACTION_PREVIOUS}, or {@link EditorInfo#IME_ACTION_DONE
      * EditorInfo.IME_ACTION_DONE}.
      * 
      * <p>For backwards compatibility, if no IME options have been set and the
@@ -3266,6 +3267,16 @@
                 }
                 return;
                 
+            } else if (actionCode == EditorInfo.IME_ACTION_PREVIOUS) {
+                View v = focusSearch(FOCUS_UP);
+                if (v != null) {
+                    if (!v.requestFocus(FOCUS_UP)) {
+                        throw new IllegalStateException("focus search returned a view " +
+                                "that wasn't able to take focus!");
+                    }
+                }
+                return;
+
             } else if (actionCode == EditorInfo.IME_ACTION_DONE) {
                 InputMethodManager imm = InputMethodManager.peekInstance();
                 if (imm != null) {
@@ -4266,6 +4277,15 @@
 
         canvas.restore();
 
+        updateCursorControllerPositions();
+    }
+
+    /**
+     * Update the positions of the CursorControllers.  Needed by WebTextView,
+     * which does not draw.
+     * @hide
+     */
+    protected void updateCursorControllerPositions() {
         if (mInsertionPointCursorController != null &&
                 mInsertionPointCursorController.isShowing()) {
             mInsertionPointCursorController.updatePosition();
@@ -4680,9 +4700,15 @@
             } else {
                 outAttrs.imeOptions = EditorInfo.IME_NULL;
             }
+            if (focusSearch(FOCUS_DOWN) != null) {
+                outAttrs.imeOptions |= EditorInfo.IME_FLAG_NAVIGATE_NEXT;
+            }
+            if (focusSearch(FOCUS_UP) != null) {
+                outAttrs.imeOptions |= EditorInfo.IME_FLAG_NAVIGATE_PREVIOUS;
+            }
             if ((outAttrs.imeOptions&EditorInfo.IME_MASK_ACTION)
                     == EditorInfo.IME_ACTION_UNSPECIFIED) {
-                if (focusSearch(FOCUS_DOWN) != null) {
+                if ((outAttrs.imeOptions&EditorInfo.IME_FLAG_NAVIGATE_NEXT) != 0) {
                     // An action has not been set, but the enter key will move to
                     // the next focus, so set the action to that.
                     outAttrs.imeOptions |= EditorInfo.IME_ACTION_NEXT;
diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java
index 3d9cde4..2be7bca 100644
--- a/core/java/android/widget/VideoView.java
+++ b/core/java/android/widget/VideoView.java
@@ -529,10 +529,19 @@
                     mMediaController.hide();
                 }
                 return true;
+            } else if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY) {
+                if (mMediaPlayer.isPlaying()) {
+                    start();
+                    mMediaController.hide();
+                }
+                return true;
             } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP
-                    && mMediaPlayer.isPlaying()) {
-                pause();
-                mMediaController.show();
+                    || keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE) {
+                if (!mMediaPlayer.isPlaying()) {
+                    pause();
+                    mMediaController.show();
+                }
+                return true;
             } else {
                 toggleMediaControlsVisiblity();
             }
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index 3015363..f4a041c 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -52,9 +52,6 @@
 public class ActionBarImpl extends ActionBar {
     private static final int NORMAL_VIEW = 0;
     private static final int CONTEXT_VIEW = 1;
-    
-    private static final int TAB_SWITCH_SHOW_HIDE = 0;
-    private static final int TAB_SWITCH_ADD_REMOVE = 1;
 
     private Context mContext;
     private Activity mActivity;
@@ -67,9 +64,7 @@
 
     private ArrayList<TabImpl> mTabs = new ArrayList<TabImpl>();
 
-    private int mTabContainerViewId = android.R.id.content;
     private TabImpl mSelectedTab;
-    private int mTabSwitchMode = TAB_SWITCH_ADD_REMOVE;
     
     private ActionMode mActionMode;
     
@@ -133,7 +128,9 @@
 
     public void setCustomNavigationMode(View view) {
         cleanupTabs();
-        mActionView.setCustomNavigationView(view);
+        setCustomView(view);
+        setDisplayOptions(DISPLAY_SHOW_CUSTOM, DISPLAY_SHOW_CUSTOM | DISPLAY_SHOW_TITLE);
+        mActionView.setNavigationMode(NAVIGATION_MODE_STANDARD);
         mActionView.setCallback(null);
     }
 
@@ -144,16 +141,17 @@
     public void setDropdownNavigationMode(SpinnerAdapter adapter, NavigationCallback callback,
             int defaultSelectedPosition) {
         cleanupTabs();
-        mActionView.setNavigationMode(NAVIGATION_MODE_DROPDOWN_LIST);
-        mActionView.setDropdownAdapter(adapter);
+        setDisplayOptions(0, DISPLAY_SHOW_CUSTOM | DISPLAY_SHOW_TITLE);
+        mActionView.setNavigationMode(NAVIGATION_MODE_LIST);
+        setListNavigationCallbacks(adapter, callback);
         if (defaultSelectedPosition >= 0) {
             mActionView.setDropdownSelectedPosition(defaultSelectedPosition);
         }
-        mActionView.setCallback(callback);
     }
 
     public void setStandardNavigationMode() {
         cleanupTabs();
+        setDisplayOptions(DISPLAY_SHOW_TITLE, DISPLAY_SHOW_TITLE | DISPLAY_SHOW_CUSTOM);
         mActionView.setNavigationMode(NAVIGATION_MODE_STANDARD);
         mActionView.setCallback(null);
     }
@@ -163,24 +161,21 @@
         case NAVIGATION_MODE_TABS:
             selectTab(mTabs.get(position));
             break;
-        case NAVIGATION_MODE_DROPDOWN_LIST:
+        case NAVIGATION_MODE_LIST:
             mActionView.setDropdownSelectedPosition(position);
             break;
         default:
             throw new IllegalStateException(
-                    "setSelectedNavigationItem not valid for current navigation mode");
+                    "setSelectedNavigationIndex not valid for current navigation mode");
         }
     }
 
     public int getSelectedNavigationItem() {
-        switch (mActionView.getNavigationMode()) {
-        case NAVIGATION_MODE_TABS:
-            return mSelectedTab.getPosition();
-        case NAVIGATION_MODE_DROPDOWN_LIST:
-            return mActionView.getDropdownSelectedPosition();
-        default:
-            return -1;
-        }
+        return getSelectedNavigationIndex();
+    }
+
+    public void removeAllTabs() {
+        cleanupTabs();
     }
 
     private void cleanupTabs() {
@@ -321,6 +316,7 @@
             throw new IllegalStateException(
                     "Tab navigation mode cannot be used outside of an Activity");
         }
+        setDisplayOptions(0, DISPLAY_SHOW_TITLE | DISPLAY_SHOW_CUSTOM);
         mActionView.setNavigationMode(NAVIGATION_MODE_TABS);
     }
 
@@ -510,8 +506,9 @@
         }
 
         @Override
-        public void setTag(Object tag) {
+        public Tab setTag(Object tag) {
             mTag = tag;
+            return this;
         }
 
         public ActionBar.TabListener getCallback() {
@@ -519,8 +516,9 @@
         }
 
         @Override
-        public void setTabListener(ActionBar.TabListener callback) {
+        public Tab setTabListener(ActionBar.TabListener callback) {
             mCallback = callback;
+            return this;
         }
 
         @Override
@@ -529,8 +527,9 @@
         }
 
         @Override
-        public void setCustomView(View view) {
+        public Tab setCustomView(View view) {
             mCustomView = view;
+            return this;
         }
 
         @Override
@@ -553,13 +552,15 @@
         }
 
         @Override
-        public void setIcon(Drawable icon) {
+        public Tab setIcon(Drawable icon) {
             mIcon = icon;
+            return this;
         }
 
         @Override
-        public void setText(CharSequence text) {
+        public Tab setText(CharSequence text) {
             mText = text;
+            return this;
         }
 
         @Override
@@ -567,4 +568,56 @@
             selectTab(this);
         }
     }
+
+    @Override
+    public void setCustomView(View view) {
+        mActionView.setCustomNavigationView(view);
+    }
+
+    @Override
+    public void setCustomView(View view, LayoutParams layoutParams) {
+        view.setLayoutParams(layoutParams);
+        mActionView.setCustomNavigationView(view);
+    }
+
+    @Override
+    public void setListNavigationCallbacks(SpinnerAdapter adapter, NavigationCallback callback) {
+        mActionView.setDropdownAdapter(adapter);
+        mActionView.setCallback(callback);
+    }
+
+    @Override
+    public int getSelectedNavigationIndex() {
+        switch (mActionView.getNavigationMode()) {
+            case NAVIGATION_MODE_TABS:
+                return mSelectedTab.getPosition();
+            case NAVIGATION_MODE_LIST:
+                return mActionView.getDropdownSelectedPosition();
+            default:
+                return -1;
+        }
+    }
+
+    @Override
+    public int getNavigationItemCount() {
+        switch (mActionView.getNavigationMode()) {
+            case NAVIGATION_MODE_TABS:
+                return mTabs.size();
+            case NAVIGATION_MODE_LIST:
+                SpinnerAdapter adapter = mActionView.getDropdownAdapter();
+                return adapter != null ? adapter.getCount() : 0;
+            default:
+                return 0;
+        }
+    }
+
+    @Override
+    public void setNavigationMode(int mode) {
+        mActionView.setNavigationMode(mode);
+    }
+
+    @Override
+    public Tab getTabAt(int index) {
+        return mTabs.get(index);
+    }
 }
diff --git a/core/java/com/android/internal/os/SamplingProfilerIntegration.java b/core/java/com/android/internal/os/SamplingProfilerIntegration.java
index b87ac90..6d2bcae 100644
--- a/core/java/com/android/internal/os/SamplingProfilerIntegration.java
+++ b/core/java/com/android/internal/os/SamplingProfilerIntegration.java
@@ -82,8 +82,8 @@
         }
         ThreadGroup group = Thread.currentThread().getThreadGroup();
         SamplingProfiler.ThreadSet threadSet = SamplingProfiler.newThreadGroupTheadSet(group);
-        INSTANCE = new SamplingProfiler(4, threadSet);
-        INSTANCE.start(samplingProfilerHz);
+        INSTANCE = new SamplingProfiler(4, threadSet); // TODO parameter for depth
+        INSTANCE.start(1000/samplingProfilerHz);
     }
 
     /**
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index d5ae1f0..19666fd 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -38,7 +38,7 @@
     // You need the STATUS_BAR_SERVICE permission
     void registerStatusBar(IStatusBar callbacks, out StatusBarIconList iconList,
             out List<IBinder> notificationKeys, out List<StatusBarNotification> notifications,
-            out boolean[] switches);
+            out int[] switches);
     void onPanelRevealed();
     void onNotificationClick(String pkg, String tag, int id);
     void onNotificationError(String pkg, String tag, int id,
diff --git a/core/java/com/android/internal/view/menu/ActionMenuView.java b/core/java/com/android/internal/view/menu/ActionMenuView.java
index 2888074..621defe 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuView.java
@@ -24,10 +24,10 @@
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewParent;
 import android.widget.ImageButton;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
-import android.widget.LinearLayout.LayoutParams;
 
 import java.util.ArrayList;
 
@@ -169,6 +169,10 @@
             final MenuItemImpl itemData = itemsToShow.get(i);
             final View actionView = itemData.getActionView();
             if (actionView != null) {
+                final ViewParent parent = actionView.getParent();
+                if (parent instanceof ViewGroup) {
+                    ((ViewGroup) parent).removeView(actionView);
+                }
                 addView(actionView, makeActionViewLayoutParams());
             } else {
                 needsDivider = addItemView(i == 0 || !needsDivider,
diff --git a/core/java/com/android/internal/widget/ActionBarContextView.java b/core/java/com/android/internal/widget/ActionBarContextView.java
index 38f76d3..e93c414 100644
--- a/core/java/com/android/internal/widget/ActionBarContextView.java
+++ b/core/java/com/android/internal/widget/ActionBarContextView.java
@@ -26,9 +26,6 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.ButtonGroup;
-import android.widget.ImageButton;
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 4c3bba1..be96e48 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -26,20 +26,21 @@
 import android.app.Activity;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.ComponentInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.TypedArray;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffColorFilter;
 import android.graphics.drawable.Drawable;
 import android.text.TextUtils.TruncateAt;
 import android.util.AttributeSet;
-import android.util.DisplayMetrics;
+import android.util.Log;
 import android.view.ActionMode;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewParent;
 import android.widget.AdapterView;
 import android.widget.HorizontalScrollView;
 import android.widget.ImageView;
@@ -63,19 +64,27 @@
      * Display options that require re-layout as opposed to a simple invalidate
      */
     private static final int DISPLAY_RELAYOUT_MASK =
-            ActionBar.DISPLAY_HIDE_HOME |
-            ActionBar.DISPLAY_USE_LOGO;
+            ActionBar.DISPLAY_SHOW_HOME |
+            ActionBar.DISPLAY_USE_LOGO |
+            ActionBar.DISPLAY_HOME_AS_UP |
+            ActionBar.DISPLAY_SHOW_CUSTOM |
+            ActionBar.DISPLAY_SHOW_TITLE;
+
+    private static final int DEFAULT_CUSTOM_GRAVITY = Gravity.LEFT | Gravity.CENTER_VERTICAL;
     
     private final int mContentHeight;
 
     private int mNavigationMode;
-    private int mDisplayOptions;
+    private int mDisplayOptions = ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_HOME_AS_UP;
     private CharSequence mTitle;
     private CharSequence mSubtitle;
     private Drawable mIcon;
     private Drawable mLogo;
     private Drawable mDivider;
+    private Drawable mHomeAsUpIndicator;
 
+    private LinearLayout mHomeLayout;
+    private ImageView mHomeAsUpView;
     private ImageView mIconView;
     private ImageView mLogoView;
     private LinearLayout mTitleLayout;
@@ -98,7 +107,8 @@
     private ActionBarContextView mContextView;
 
     private ActionMenuItem mLogoNavItem;
-    
+
+    private SpinnerAdapter mSpinnerAdapter;
     private NavigationCallback mCallback;
 
     private final AdapterView.OnItemSelectedListener mNavItemSelectedListener =
@@ -122,30 +132,56 @@
 
         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ActionBar);
 
-        final int colorFilter = a.getColor(R.styleable.ActionBar_colorFilter, 0);
-
-        if (colorFilter != 0) {
-            final Drawable d = getBackground();
-            d.setDither(true);
-            d.setColorFilter(new PorterDuffColorFilter(colorFilter, PorterDuff.Mode.OVERLAY));
-        }
-
-        ApplicationInfo info = context.getApplicationInfo();
+        ApplicationInfo appInfo = context.getApplicationInfo();
         PackageManager pm = context.getPackageManager();
         mNavigationMode = a.getInt(R.styleable.ActionBar_navigationMode,
                 ActionBar.NAVIGATION_MODE_STANDARD);
         mTitle = a.getText(R.styleable.ActionBar_title);
         mSubtitle = a.getText(R.styleable.ActionBar_subtitle);
-        mDisplayOptions = a.getInt(R.styleable.ActionBar_displayOptions, DISPLAY_DEFAULT);
         
         mLogo = a.getDrawable(R.styleable.ActionBar_logo);
         if (mLogo == null) {
-            mLogo = info.loadLogo(pm);
+            if (context instanceof Activity) {
+                try {
+                    mLogo = pm.getActivityLogo(((Activity) context).getComponentName());
+                } catch (NameNotFoundException e) {
+                    Log.e(TAG, "Activity component name not found!", e);
+                }
+            }
+            if (mLogo == null) {
+                mLogo = appInfo.loadLogo(pm);
+            }
         }
+
         mIcon = a.getDrawable(R.styleable.ActionBar_icon);
         if (mIcon == null) {
-            mIcon = info.loadIcon(pm);
+            if (context instanceof Activity) {
+                try {
+                    mIcon = pm.getActivityIcon(((Activity) context).getComponentName());
+                } catch (NameNotFoundException e) {
+                    Log.e(TAG, "Activity component name not found!", e);
+                }
+            }
+            if (mIcon == null) {
+                mIcon = appInfo.loadIcon(pm);
+            }
         }
+
+        mHomeLayout = new LinearLayout(context, null,
+                com.android.internal.R.attr.actionButtonStyle);
+        mHomeLayout.setClickable(true);
+        mHomeLayout.setFocusable(true);
+        mHomeLayout.setOnClickListener(mHomeClickListener);
+        mHomeLayout.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
+                LayoutParams.MATCH_PARENT));
+
+        mHomeAsUpIndicator = a.getDrawable(R.styleable.ActionBar_homeAsUpIndicator);
+
+        mHomeAsUpView = new ImageView(context);
+        mHomeAsUpView.setImageDrawable(mHomeAsUpIndicator);
+        mHomeAsUpView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
+                LayoutParams.MATCH_PARENT));
+        mHomeLayout.addView(mHomeAsUpView);
         
         Drawable background = a.getDrawable(R.styleable.ActionBar_background);
         if (background != null) {
@@ -155,11 +191,14 @@
         mTitleStyleRes = a.getResourceId(R.styleable.ActionBar_titleTextStyle, 0);
         mSubtitleStyleRes = a.getResourceId(R.styleable.ActionBar_subtitleTextStyle, 0);
 
+        setDisplayOptions(a.getInt(R.styleable.ActionBar_displayOptions, DISPLAY_DEFAULT));
+
         final int customNavId = a.getResourceId(R.styleable.ActionBar_customNavigationLayout, 0);
         if (customNavId != 0) {
             LayoutInflater inflater = LayoutInflater.from(context);
             mCustomNavView = (View) inflater.inflate(customNavId, null);
-            mNavigationMode = ActionBar.NAVIGATION_MODE_CUSTOM;
+            mNavigationMode = ActionBar.NAVIGATION_MODE_STANDARD;
+            setDisplayOptions(mDisplayOptions | ActionBar.DISPLAY_SHOW_CUSTOM);
         }
 
         mContentHeight = a.getLayoutDimension(R.styleable.ActionBar_height, 0);
@@ -241,9 +280,13 @@
     }
 
     public void setCustomNavigationView(View view) {
+        final boolean showCustom = (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0;
+        if (mCustomNavView != null && showCustom) {
+            removeView(mCustomNavView);
+        }
         mCustomNavView = view;
-        if (view != null) {
-            setNavigationMode(ActionBar.NAVIGATION_MODE_CUSTOM);
+        if (mCustomNavView != null && showCustom) {
+            addView(mCustomNavView);
         }
     }
 
@@ -296,15 +339,43 @@
     }
 
     public void setDisplayOptions(int options) {
+        // TODO Remove this once DISPLAY_HIDE_HOME is removed
+        if ((options & ActionBar.DISPLAY_HIDE_HOME) != 0) {
+            options &= ~(ActionBar.DISPLAY_HIDE_HOME | ActionBar.DISPLAY_SHOW_HOME);
+        }
+        // End TODO
+
         final int flagsChanged = options ^ mDisplayOptions;
         mDisplayOptions = options;
         if ((flagsChanged & DISPLAY_RELAYOUT_MASK) != 0) {
-            final int vis = (options & ActionBar.DISPLAY_HIDE_HOME) != 0 ? GONE : VISIBLE;
-            if (mLogoView != null) {
-                mLogoView.setVisibility(vis);
+            final int vis = (options & ActionBar.DISPLAY_SHOW_HOME) != 0 ? VISIBLE : GONE;
+            mHomeLayout.setVisibility(vis);
+
+            if ((flagsChanged & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
+                mHomeAsUpView.setVisibility((options & ActionBar.DISPLAY_HOME_AS_UP) != 0
+                        ? VISIBLE : GONE);
             }
-            if (mIconView != null) {
-                mIconView.setVisibility(vis);
+
+            if (mLogoView != null && (flagsChanged & ActionBar.DISPLAY_USE_LOGO) != 0) {
+                final boolean logoVis = (options & ActionBar.DISPLAY_USE_LOGO) != 0;
+                mLogoView.setVisibility(logoVis ? VISIBLE : GONE);
+                mIconView.setVisibility(logoVis ? GONE : VISIBLE);
+            }
+
+            if ((flagsChanged & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
+                if ((options & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
+                    initTitle();
+                } else {
+                    removeView(mTitleLayout);
+                }
+            }
+
+            if ((flagsChanged & ActionBar.DISPLAY_SHOW_CUSTOM) != 0 && mCustomNavView != null) {
+                if ((options & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) {
+                    addView(mCustomNavView);
+                } else {
+                    removeView(mCustomNavView);
+                }
             }
             
             requestLayout();
@@ -317,52 +388,27 @@
         final int oldMode = mNavigationMode;
         if (mode != oldMode) {
             switch (oldMode) {
-            case ActionBar.NAVIGATION_MODE_STANDARD:
-                if (mTitleLayout != null) {
-                    removeView(mTitleLayout);
-                    mTitleLayout = null;
-                    mTitleView = null;
-                    mSubtitleView = null;
-                }
-                break;
-            case ActionBar.NAVIGATION_MODE_DROPDOWN_LIST:
+            case ActionBar.NAVIGATION_MODE_LIST:
                 if (mSpinner != null) {
                     removeView(mSpinner);
-                    mSpinner = null;
-                }
-                break;
-            case ActionBar.NAVIGATION_MODE_CUSTOM:
-                if (mCustomNavView != null) {
-                    removeView(mCustomNavView);
-                    mCustomNavView = null;
                 }
                 break;
             case ActionBar.NAVIGATION_MODE_TABS:
                 if (mTabLayout != null) {
                     removeView(mTabScrollView);
-                    mTabLayout = null;
-                    mTabScrollView = null;
                 }
             }
             
             switch (mode) {
-            case ActionBar.NAVIGATION_MODE_STANDARD:
-                initTitle();
-                break;
-            case ActionBar.NAVIGATION_MODE_DROPDOWN_LIST:
+            case ActionBar.NAVIGATION_MODE_LIST:
                 mSpinner = new Spinner(mContext, null,
                         com.android.internal.R.attr.actionDropDownStyle);
+                mSpinner.setAdapter(mSpinnerAdapter);
                 mSpinner.setOnItemSelectedListener(mNavItemSelectedListener);
                 addView(mSpinner);
                 break;
-            case ActionBar.NAVIGATION_MODE_CUSTOM:
-                addView(mCustomNavView);
-                break;
             case ActionBar.NAVIGATION_MODE_TABS:
-                mTabScrollView = new HorizontalScrollView(getContext());
-                mTabLayout = new LinearLayout(getContext(), null,
-                        com.android.internal.R.attr.actionBarTabBarStyle);
-                mTabScrollView.addView(mTabLayout);
+                ensureTabsExist();
                 addView(mTabScrollView);
                 break;
             }
@@ -371,8 +417,24 @@
         }
     }
     
+    private void ensureTabsExist() {
+        if (mTabScrollView == null) {
+            mTabScrollView = new HorizontalScrollView(getContext());
+            mTabLayout = new LinearLayout(getContext(), null,
+                    com.android.internal.R.attr.actionBarTabBarStyle);
+            mTabScrollView.addView(mTabLayout);
+        }
+    }
+
     public void setDropdownAdapter(SpinnerAdapter adapter) {
-        mSpinner.setAdapter(adapter);
+        mSpinnerAdapter = adapter;
+        if (mSpinner != null) {
+            mSpinner.setAdapter(adapter);
+        }
+    }
+
+    public SpinnerAdapter getDropdownAdapter() {
+        return mSpinnerAdapter;
     }
 
     public void setDropdownSelectedPosition(int position) {
@@ -407,6 +469,7 @@
     }
 
     public void addTab(ActionBar.Tab tab) {
+        ensureTabsExist();
         final boolean isFirst = mTabLayout.getChildCount() == 0;
         View tabView = createTabView(tab);
         mTabLayout.addView(tabView);
@@ -416,6 +479,7 @@
     }
 
     public void addTab(ActionBar.Tab tab, int position) {
+        ensureTabsExist();
         final boolean isFirst = mTabLayout.getChildCount() == 0;
         final TabView tabView = createTabView(tab);
         mTabLayout.addView(tabView, position);
@@ -425,46 +489,50 @@
     }
 
     public void removeTabAt(int position) {
-        mTabLayout.removeViewAt(position);
+        if (mTabLayout != null) {
+            mTabLayout.removeViewAt(position);
+        }
     }
 
     @Override
     protected LayoutParams generateDefaultLayoutParams() {
         // Used by custom nav views if they don't supply layout params. Everything else
         // added to an ActionBarView should have them already.
-        return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+        return new ActionBar.LayoutParams(DEFAULT_CUSTOM_GRAVITY);
     }
 
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
 
-        if ((mDisplayOptions & ActionBar.DISPLAY_HIDE_HOME) == 0) {
-            if (mLogo != null && (mDisplayOptions & ActionBar.DISPLAY_USE_LOGO) != 0) {
-                mLogoView = new ImageView(getContext(), null,
-                        com.android.internal.R.attr.actionButtonStyle);
-                mLogoView.setAdjustViewBounds(true);
-                mLogoView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
-                        LayoutParams.MATCH_PARENT));
-                mLogoView.setImageDrawable(mLogo);
-                mLogoView.setClickable(true);
-                mLogoView.setFocusable(true);
-                mLogoView.setOnClickListener(mHomeClickListener);
-                addView(mLogoView);
-            } else if (mIcon != null) {
-                mIconView = new ImageView(getContext(), null,
-                        com.android.internal.R.attr.actionButtonStyle);
-                mIconView.setAdjustViewBounds(true);
-                mIconView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
-                        LayoutParams.MATCH_PARENT));
-                mIconView.setImageDrawable(mIcon);
-                mIconView.setClickable(true);
-                mIconView.setFocusable(true);
-                mIconView.setOnClickListener(mHomeClickListener);
-                addView(mIconView);
-            }
+        final Context context = getContext();
+
+        if (mLogo != null) {
+            mLogoView = new ImageView(context);
+            mLogoView.setScaleType(ImageView.ScaleType.CENTER);
+            mLogoView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
+                    LayoutParams.MATCH_PARENT));
+            mLogoView.setImageDrawable(mLogo);
+            mLogoView.setVisibility((mDisplayOptions & ActionBar.DISPLAY_USE_LOGO) != 0
+                    ? VISIBLE : GONE);
+            mHomeLayout.addView(mLogoView);
         }
 
+        if (mIcon != null) {
+            mIconView = new ImageView(context, null,
+                    com.android.internal.R.attr.actionButtonStyle);
+            mIconView.setScaleType(ImageView.ScaleType.CENTER);
+            mIconView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
+                    LayoutParams.MATCH_PARENT));
+            mIconView.setImageDrawable(mIcon);
+            mIconView.setVisibility(
+                    (mDisplayOptions & ActionBar.DISPLAY_USE_LOGO) == 0 || mLogo == null
+                    ? VISIBLE : GONE);
+            mHomeLayout.addView(mIconView);
+        }
+
+        addView(mHomeLayout);
+
         switch (mNavigationMode) {
         case ActionBar.NAVIGATION_MODE_STANDARD:
             if (mLogoView == null) {
@@ -472,19 +540,23 @@
             }
             break;
             
-        case ActionBar.NAVIGATION_MODE_DROPDOWN_LIST:
+        case ActionBar.NAVIGATION_MODE_LIST:
             throw new UnsupportedOperationException(
-                    "Inflating dropdown list navigation isn't supported yet!");
+                    "Inflating list navigation isn't supported yet!");
             
         case ActionBar.NAVIGATION_MODE_TABS:
             throw new UnsupportedOperationException(
                     "Inflating tab navigation isn't supported yet!");
-            
-        case ActionBar.NAVIGATION_MODE_CUSTOM:
-            if (mCustomNavView != null) {
+        }
+
+        if (mCustomNavView != null && (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) {
+            final ViewParent parent = mCustomNavView.getParent();
+            if (parent != this) {
+                if (parent instanceof ViewGroup) {
+                    ((ViewGroup) parent).removeView(mCustomNavView);
+                }
                 addView(mCustomNavView);
             }
-            break;
         }
     }
     
@@ -513,6 +585,7 @@
     }
 
     public void setTabSelected(int position) {
+        ensureTabsExist();
         final int tabCount = mTabLayout.getChildCount();
         for (int i = 0; i < tabCount; i++) {
             final View child = mTabLayout.getChildAt(i);
@@ -544,57 +617,40 @@
                 mContentHeight : MeasureSpec.getSize(heightMeasureSpec);
         
         final int verticalPadding = getPaddingTop() + getPaddingBottom();
-        int availableWidth = contentWidth - getPaddingLeft() - getPaddingRight();
+        final int paddingLeft = getPaddingLeft();
+        final int paddingRight = getPaddingRight();
         final int height = maxHeight - verticalPadding;
         final int childSpecHeight = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
 
-        if (mLogoView != null && mLogoView.getVisibility() != GONE) {
-            availableWidth = measureChildView(mLogoView, availableWidth, childSpecHeight, 0);
-        }
-        if (mIconView != null && mIconView.getVisibility() != GONE) {
-            availableWidth = measureChildView(mIconView, availableWidth, childSpecHeight, 0);
+        int availableWidth = contentWidth - paddingLeft - paddingRight;
+        int leftOfCenter = availableWidth / 2;
+        int rightOfCenter = leftOfCenter;
+
+        if (mHomeLayout.getVisibility() != GONE) {
+            availableWidth = measureChildView(mHomeLayout, availableWidth, childSpecHeight, 0);
+            leftOfCenter -= mHomeLayout.getMeasuredWidth();
         }
         
         if (mMenuView != null) {
             availableWidth = measureChildView(mMenuView, availableWidth,
                     childSpecHeight, 0);
+            rightOfCenter -= mMenuView.getMeasuredWidth();
         }
-        
+
+        if (mTitleLayout != null && (mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
+            availableWidth = measureChildView(mTitleLayout, availableWidth, childSpecHeight, 0);
+            leftOfCenter -= mTitleLayout.getMeasuredWidth();
+        }
+
         switch (mNavigationMode) {
-        case ActionBar.NAVIGATION_MODE_STANDARD:
-            if (mTitleLayout != null) {
-                measureChildView(mTitleLayout, availableWidth, childSpecHeight, 0);
-            }
-            break;
-        case ActionBar.NAVIGATION_MODE_DROPDOWN_LIST:
+        case ActionBar.NAVIGATION_MODE_LIST:
             if (mSpinner != null) {
                 mSpinner.measure(
                         MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST),
                         MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST));
-            }
-            break;
-        case ActionBar.NAVIGATION_MODE_CUSTOM:
-            if (mCustomNavView != null) {
-                LayoutParams lp = mCustomNavView.getLayoutParams();
-                final int customNavWidthMode = lp.width != LayoutParams.WRAP_CONTENT ?
-                        MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
-                final int customNavWidth = lp.width >= 0 ?
-                        Math.min(lp.width, availableWidth) : availableWidth;
-
-                // If the action bar is wrapping to its content height, don't allow a custom
-                // view to MATCH_PARENT.
-                int customNavHeightMode;
-                if (mContentHeight <= 0) {
-                    customNavHeightMode = MeasureSpec.AT_MOST;
-                } else {
-                    customNavHeightMode = lp.height != LayoutParams.WRAP_CONTENT ?
-                            MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
-                }
-                final int customNavHeight = lp.height >= 0 ?
-                        Math.min(lp.height, height) : height;
-                mCustomNavView.measure(
-                        MeasureSpec.makeMeasureSpec(customNavWidth, customNavWidthMode),
-                        MeasureSpec.makeMeasureSpec(customNavHeight, customNavHeightMode));
+                final int spinnerWidth = mSpinner.getMeasuredWidth();
+                availableWidth -= spinnerWidth;
+                leftOfCenter -= spinnerWidth;
             }
             break;
         case ActionBar.NAVIGATION_MODE_TABS:
@@ -602,10 +658,56 @@
                 mTabScrollView.measure(
                         MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST),
                         MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
+                final int tabWidth = mTabScrollView.getMeasuredWidth();
+                availableWidth -= tabWidth;
+                leftOfCenter -= tabWidth;
             }
             break;
         }
 
+        if ((mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0 && mCustomNavView != null) {
+            final LayoutParams lp = generateLayoutParams(mCustomNavView.getLayoutParams());
+            final ActionBar.LayoutParams ablp = lp instanceof ActionBar.LayoutParams ?
+                    (ActionBar.LayoutParams) lp : null;
+
+            int horizontalMargin = 0;
+            int verticalMargin = 0;
+            if (ablp != null) {
+                horizontalMargin = ablp.leftMargin + ablp.rightMargin;
+                verticalMargin = ablp.topMargin + ablp.bottomMargin;
+            }
+
+            // If the action bar is wrapping to its content height, don't allow a custom
+            // view to MATCH_PARENT.
+            int customNavHeightMode;
+            if (mContentHeight <= 0) {
+                customNavHeightMode = MeasureSpec.AT_MOST;
+            } else {
+                customNavHeightMode = lp.height != LayoutParams.WRAP_CONTENT ?
+                        MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
+            }
+            final int customNavHeight = Math.max(0,
+                    (lp.height >= 0 ? Math.min(lp.height, height) : height) - verticalMargin);
+
+            final int customNavWidthMode = lp.width != LayoutParams.WRAP_CONTENT ?
+                    MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
+            int customNavWidth = Math.max(0,
+                    (lp.width >= 0 ? Math.min(lp.width, availableWidth) : availableWidth)
+                    - horizontalMargin);
+            final int hgrav = (ablp != null ? ablp.gravity : DEFAULT_CUSTOM_GRAVITY) &
+                    Gravity.HORIZONTAL_GRAVITY_MASK;
+
+            // Centering a custom view is treated specially; we try to center within the whole
+            // action bar rather than in the available space.
+            if (hgrav == Gravity.CENTER_HORIZONTAL && lp.width == LayoutParams.MATCH_PARENT) {
+                customNavWidth = Math.min(leftOfCenter, rightOfCenter) * 2;
+            }
+
+            mCustomNavView.measure(
+                    MeasureSpec.makeMeasureSpec(customNavWidth, customNavWidthMode),
+                    MeasureSpec.makeMeasureSpec(customNavHeight, customNavHeightMode));
+        }
+
         if (mContentHeight <= 0) {
             int measuredHeight = 0;
             final int count = getChildCount();
@@ -642,39 +744,89 @@
         final int y = getPaddingTop();
         final int contentHeight = b - t - getPaddingTop() - getPaddingBottom();
 
-        if (mLogoView != null && mLogoView.getVisibility() != GONE) {
-            x += positionChild(mLogoView, x, y, contentHeight);
-        }
-        if (mIconView != null && mIconView.getVisibility() != GONE) {
-            x += positionChild(mIconView, x, y, contentHeight);
+        if (mHomeLayout.getVisibility() != GONE) {
+            x += positionChild(mHomeLayout, x, y, contentHeight);
         }
         
+        if (mTitleLayout != null && (mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
+            x += positionChild(mTitleLayout, x, y, contentHeight);
+        }
+
         switch (mNavigationMode) {
         case ActionBar.NAVIGATION_MODE_STANDARD:
-            if (mTitleLayout != null) {
-                x += positionChild(mTitleLayout, x, y, contentHeight);
-            }
             break;
-        case ActionBar.NAVIGATION_MODE_DROPDOWN_LIST:
+        case ActionBar.NAVIGATION_MODE_LIST:
             if (mSpinner != null) {
                 x += positionChild(mSpinner, x, y, contentHeight);
             }
             break;
-        case ActionBar.NAVIGATION_MODE_CUSTOM:
-            if (mCustomNavView != null) {
-                x += positionChild(mCustomNavView, x, y, contentHeight);
-            }
-            break;
         case ActionBar.NAVIGATION_MODE_TABS:
             if (mTabScrollView != null) {
                 x += positionChild(mTabScrollView, x, y, contentHeight);
             }
         }
 
-        x = r - l - getPaddingRight();
-
+        int menuLeft = r - l - getPaddingRight();
         if (mMenuView != null) {
-            x -= positionChildInverse(mMenuView, x, y, contentHeight);
+            positionChildInverse(mMenuView, menuLeft, y, contentHeight);
+            menuLeft -= mMenuView.getMeasuredWidth();
+        }
+
+        if (mCustomNavView != null && (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) {
+            LayoutParams lp = mCustomNavView.getLayoutParams();
+            final ActionBar.LayoutParams ablp = lp instanceof ActionBar.LayoutParams ?
+                    (ActionBar.LayoutParams) lp : null;
+
+            final int gravity = ablp != null ? ablp.gravity : DEFAULT_CUSTOM_GRAVITY;
+            final int navWidth = mCustomNavView.getMeasuredWidth();
+
+            int topMargin = 0;
+            int bottomMargin = 0;
+            if (ablp != null) {
+                x += ablp.leftMargin;
+                menuLeft -= ablp.rightMargin;
+                topMargin = ablp.topMargin;
+                bottomMargin = ablp.bottomMargin;
+            }
+
+            int hgravity = gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
+            // See if we actually have room to truly center; if not push against left or right.
+            if (hgravity == Gravity.CENTER_HORIZONTAL) {
+                final int centeredLeft = ((mRight - mLeft) - navWidth) / 2;
+                if (centeredLeft < x) {
+                    hgravity = Gravity.LEFT;
+                } else if (centeredLeft + navWidth > menuLeft) {
+                    hgravity = Gravity.RIGHT;
+                }
+            }
+
+            int xpos = 0;
+            switch (hgravity) {
+                case Gravity.CENTER_HORIZONTAL:
+                    xpos = ((mRight - mLeft) - navWidth) / 2;
+                    break;
+                case Gravity.LEFT:
+                    xpos = x;
+                    break;
+                case Gravity.RIGHT:
+                    xpos = menuLeft - navWidth;
+                    break;
+            }
+
+            int ypos = 0;
+            switch (gravity & Gravity.VERTICAL_GRAVITY_MASK) {
+                case Gravity.CENTER_VERTICAL:
+                    ypos = ((mBottom - mTop) - mCustomNavView.getMeasuredHeight()) / 2;
+                    break;
+                case Gravity.TOP:
+                    ypos = getPaddingTop() + topMargin;
+                    break;
+                case Gravity.BOTTOM:
+                    ypos = getHeight() - getPaddingBottom() - mCustomNavView.getMeasuredHeight()
+                            - bottomMargin;
+                    break;
+            }
+            x += positionChild(mCustomNavView, xpos, ypos, contentHeight);
         }
     }
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 2444fce..3635fab 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -532,6 +532,13 @@
         android:description="@string/permdesc_sdcardWrite"
         android:protectionLevel="dangerous" />
 
+    <!-- Allows an application to write to internal media storage -->
+    <permission android:name="android.permission.WRITE_MEDIA_STORAGE"
+        android:permissionGroup="android.permission-group.STORAGE"
+        android:label="@string/permlab_mediaStorageWrite"
+        android:description="@string/permdesc_mediaStorageWrite"
+        android:protectionLevel="signatureOrSystem" />
+
     <!-- ============================================ -->
     <!-- Permissions for low-level system interaction -->
     <!-- ============================================ -->
diff --git a/core/res/res/anim/fragment_close_enter.xml b/core/res/res/anim/fragment_close_enter.xml
index 7a9a3b9..edf1948 100644
--- a/core/res/res/anim/fragment_close_enter.xml
+++ b/core/res/res/anim/fragment_close_enter.xml
@@ -26,7 +26,7 @@
         android:duration="@android:integer/config_mediumAnimTime"/>
     <objectAnimator
         android:interpolator="@anim/decelerate_interpolator"
-        android:valueFrom="-400"
+        android:valueFrom="-100"
         android:valueTo="0"
         android:valueType="floatType"
         android:propertyName="translationX"
diff --git a/core/res/res/anim/fragment_close_exit.xml b/core/res/res/anim/fragment_close_exit.xml
index 0743577..fbba476 100644
--- a/core/res/res/anim/fragment_close_exit.xml
+++ b/core/res/res/anim/fragment_close_exit.xml
@@ -27,7 +27,7 @@
     <objectAnimator
         android:interpolator="@anim/accelerate_interpolator"
         android:valueFrom="0"
-        android:valueTo="400"
+        android:valueTo="100"
         android:valueType="floatType"
         android:propertyName="translationX"
         android:duration="@android:integer/config_mediumAnimTime"/>
diff --git a/core/res/res/anim/fragment_open_enter.xml b/core/res/res/anim/fragment_open_enter.xml
index ac60494..334f4ef 100644
--- a/core/res/res/anim/fragment_open_enter.xml
+++ b/core/res/res/anim/fragment_open_enter.xml
@@ -24,7 +24,7 @@
         android:propertyName="alpha"
         android:duration="@android:integer/config_mediumAnimTime"/>
     <objectAnimator
-        android:valueFrom="400"
+        android:valueFrom="100"
         android:valueTo="0"
         android:valueType="floatType"
         android:propertyName="translationX"
diff --git a/core/res/res/anim/fragment_open_exit.xml b/core/res/res/anim/fragment_open_exit.xml
index 3bf1ad4..764fc39 100644
--- a/core/res/res/anim/fragment_open_exit.xml
+++ b/core/res/res/anim/fragment_open_exit.xml
@@ -25,7 +25,7 @@
         android:duration="@android:integer/config_mediumAnimTime"/>
     <objectAnimator
         android:valueFrom="0"
-        android:valueTo="-400"
+        android:valueTo="-100"
         android:valueType="floatType"
         android:propertyName="translationX"
         android:duration="@android:integer/config_mediumAnimTime"/>
diff --git a/core/res/res/drawable-hdpi/ic_ab_back_holo_dark.png b/core/res/res/drawable-hdpi/ic_ab_back_holo_dark.png
new file mode 100644
index 0000000..a8da981
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_ab_back_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/ic_ab_back_holo_light.png b/core/res/res/drawable-hdpi/ic_ab_back_holo_light.png
new file mode 100644
index 0000000..af0f308
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_ab_back_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_ab_back_holo_dark.png b/core/res/res/drawable-mdpi/ic_ab_back_holo_dark.png
new file mode 100644
index 0000000..7aae741
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_ab_back_holo_dark.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_ab_back_holo_light.png b/core/res/res/drawable-mdpi/ic_ab_back_holo_light.png
new file mode 100644
index 0000000..66ef51c
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_ab_back_holo_light.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/text_edit_paste_window.9.png b/core/res/res/drawable-mdpi/text_edit_paste_window.9.png
index 2738b62..6b98c13 100644
--- a/core/res/res/drawable-mdpi/text_edit_paste_window.9.png
+++ b/core/res/res/drawable-mdpi/text_edit_paste_window.9.png
Binary files differ
diff --git a/core/res/res/layout/tab_content.xml b/core/res/res/layout/tab_content.xml
index 0ee87ce..79147fb 100644
--- a/core/res/res/layout/tab_content.xml
+++ b/core/res/res/layout/tab_content.xml
@@ -22,8 +22,9 @@
 	android:layout_width="match_parent" android:layout_height="match_parent">
 	<LinearLayout android:orientation="vertical"
     	android:layout_width="match_parent" android:layout_height="match_parent">
-        <TabWidget android:id="@android:id/tabs" android:layout_width="match_parent"
-        	android:layout_height="wrap_content" android:layout_weight="0" />
+    <TabWidget android:id="@android:id/tabs"
+        android:orientation="horizontal" android:layout_width="match_parent"
+        android:layout_height="wrap_content" android:layout_weight="0" />
         <FrameLayout android:id="@android:id/tabcontent"
         	android:layout_width="match_parent" android:layout_height="0dip"
             android:layout_weight="1"/>
diff --git a/core/res/res/layout/text_edit_no_paste_window.xml b/core/res/res/layout/text_edit_no_paste_window.xml
index f288e6f6..84b6103 100644
--- a/core/res/res/layout/text_edit_no_paste_window.xml
+++ b/core/res/res/layout/text_edit_no_paste_window.xml
@@ -22,6 +22,10 @@
     <ImageView android:id="@+id/paste_icon"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        android:paddingLeft="16dip"
+        android:paddingRight="8dip"
+        android:paddingTop="8dip"
+        android:paddingBottom="8dip"
         android:layout_centerVertical="true"
         android:background="@android:drawable/ic_menu_paste_dark"
     />
@@ -29,6 +33,10 @@
     <TextView android:id="@+id/title"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        android:paddingLeft="0dip"
+        android:paddingRight="16dip"
+        android:paddingTop="8dip"
+        android:paddingBottom="8dip"
         android:layout_centerVertical="true"
         android:textAppearance="?android:attr/textAppearanceMedium"
         android:text="@android:string/pasteDisabled"
diff --git a/core/res/res/layout/text_edit_paste_window.xml b/core/res/res/layout/text_edit_paste_window.xml
index ee2c4d2..369f4a5 100644
--- a/core/res/res/layout/text_edit_paste_window.xml
+++ b/core/res/res/layout/text_edit_paste_window.xml
@@ -22,6 +22,10 @@
     <ImageView android:id="@+id/paste_icon"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        android:paddingLeft="16dip"
+        android:paddingRight="8dip"
+        android:paddingTop="8dip"
+        android:paddingBottom="8dip"
         android:layout_centerVertical="true"
         android:background="@android:drawable/ic_menu_paste_light"
     />
@@ -29,6 +33,10 @@
     <TextView android:id="@+id/title"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        android:paddingLeft="0dip"
+        android:paddingRight="16dip"
+        android:paddingTop="8dip"
+        android:paddingBottom="8dip"
         android:layout_centerVertical="true"
         android:textAppearance="?android:attr/textAppearanceMediumInverse"
         android:text="@android:string/paste"
diff --git a/core/res/res/raw/loaderror.html b/core/res/res/raw/loaderror.html
index fd3d766..565e8e9 100644
--- a/core/res/res/raw/loaderror.html
+++ b/core/res/res/raw/loaderror.html
@@ -1,7 +1,7 @@
 <html>
     <head>
         <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
-        <title>Web page not available</title>
+        <title>Webpage not available</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
             h2   { margin-top: 5px; padding-top: 0px; }
@@ -10,8 +10,8 @@
         <body>
 
             <img src="file:///android_asset/webkit/android-weberror.png" align="top" />
-            <h2>Web page not available</h2>
-            <p>The Web page at <a href="%s">%s</a> could not be loaded as:</p>
+            <h2>Webpage not available</h2>
+            <p>The webpage at <a href="%s">%s</a> could not be loaded because:</p>
             <!-- The %e is replaced by a localized error string -->
             <p>%e</p>
         </body>
diff --git a/core/res/res/raw/nodomain.html b/core/res/res/raw/nodomain.html
index a71dbcd..d757483 100644
--- a/core/res/res/raw/nodomain.html
+++ b/core/res/res/raw/nodomain.html
@@ -1,7 +1,7 @@
 <html>
     <head>
         <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
-        <title>Web page not available</title>
+        <title>Webpage not available</title>
         <style type="text/css">
             body { margin-top: 0px; padding-top: 0px; }
             h2   { margin-top: 5px; padding-top: 0px; }
@@ -10,18 +10,16 @@
         <body>
 
             <img src="file:///android_asset/webkit/android-weberror.png" align="top" />
-            <h2>Web page not available</h2>
-            <p>The Web page at <a href="%s">%s</a> might be
+            <h2>Webpage not available</h2>
+            <p>The webpage at <a href="%s">%s</a> might be
             temporarily down or it may have moved permanently to a new web
             address.</p>
 
-            <p><b>Here are some suggestions:</b></p>
+            <p><b>Suggestions:</b></p>
             <ul>
-                <li>Check to make sure your device has a signal and data
-                connection</li>
-                <li>Reload this web page later.</li>
-                <li>View a cached copy of the web page from Google</li>
-
+                <li>Make sure you have a data connection</li>
+                <li>Reload this webpage later</li>
+                <li>Check the address you entered</li>
             </ul>
         </body>
     </head>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index f0d5fd8..79131ba 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -326,6 +326,9 @@
                  need to close the input area to get at and interact with
                  parts of the window. -->
             <flag name="adjustPan" value="0x20" />
+            <!-- Don't resize <em>or</em> pan the window to make room for the
+                 soft input area; the window is never adjusted for it. -->
+            <flag name="adjustNothing" value="0x30" />
         </attr>
 
         <!-- Flag allowing you to disable the preview animation for a window.
@@ -737,6 +740,14 @@
              {@link android.text.InputType#TYPE_CLASS_TEXT} |
              {@link android.text.InputType#TYPE_TEXT_VARIATION_PHONETIC}. -->
         <flag name="textPhonetic" value="0x000000c1" />
+        <!-- Text that will be used as an e-mail address on a web form.  Corresponds to
+             {@link android.text.InputType#TYPE_CLASS_TEXT} |
+             {@link android.text.InputType#TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS}. -->
+        <flag name="textWebEmailAddress" value="0x000000d1" />
+        <!-- Text that will be used as a password on a web form.  Corresponds to
+             {@link android.text.InputType#TYPE_CLASS_TEXT} |
+             {@link android.text.InputType#TYPE_TEXT_VARIATION_WEB_PASSWORD}. -->
+        <flag name="textWebPassword" value="0x000000e1" />
         <!-- A numeric only field.  Corresponds to
              {@link android.text.InputType#TYPE_CLASS_NUMBER}. -->
         <flag name="number" value="0x00000002" />
@@ -811,6 +822,40 @@
              Corresponds to
              {@link android.view.inputmethod.EditorInfo#IME_ACTION_DONE}. -->
         <flag name="actionDone" value="0x00000006" />
+        <!-- The action key performs a "previous"
+             operation, taking the user to the previous field that will accept text.
+             Corresponds to
+             {@link android.view.inputmethod.EditorInfo#IME_ACTION_PREVIOUS}. -->
+        <flag name="actionPrevious" value="0x00000007" />
+        <!-- Used to request that the IME never go
+             into fullscreen mode.  Applications need to be aware that the flag is not
+             a guarantee, and not all IMEs will respect it.
+             <p>Corresponds to
+             {@link android.view.inputmethod.EditorInfo#IME_FLAG_NO_FULLSCREEN}. -->
+        <flag name="flagNoFullscreen" value="0x2000000" />
+        <!-- Like flagNavigateNext, but
+             specifies there is something interesting that a backward navigation
+             can focus on.  If the user selects the IME's facility to backward
+             navigate, this will show up in the application as an actionPrevious
+             at {@link android.view.inputmethod.InputConnection#performEditorAction(int)
+             InputConnection.performEditorAction(int)}.
+             <p>Corresponds to
+             {@link android.view.inputmethod.EditorInfo#IME_FLAG_NO_FULLSCREEN}. -->
+        <flag name="flagNavigatePrevious" value="0x4000000" />
+        <!-- Used to specify that there is something
+             interesting that a forward navigation can focus on. This is like using
+             actionNext, except allows the IME to be multiline (with
+             an enter key) as well as provide forward navigation.  Note that some
+             IMEs may not be able to do this, especially when running on a small
+             screen where there is little space.  In that case it does not need to
+             present a UI for this option.  Like actionNext, if the
+             user selects the IME's facility to forward navigate, this will show up
+             in the application at
+             {@link android.view.inputmethod.InputConnection#performEditorAction(int)
+             InputConnection.performEditorAction(int)}.
+             <p>Corresponds to
+             {@link android.view.inputmethod.EditorInfo#IME_FLAG_NAVIGATE_NEXT}. -->
+        <flag name="flagNavigateNext" value="0x8000000" />
         <!-- Used to specify that the IME does not need
              to show its extracted text UI.  For input methods that may be fullscreen,
              often when in landscape mode, this allows them to be smaller and let part
@@ -4240,18 +4285,21 @@
         <attr name="navigationMode">
             <!-- Normal static title text -->
             <enum name="normal" value="0" />
-            <!-- The action bar will use a drop-down selection in place of title text. -->
-            <enum name="dropdownList" value="1" />
-            <!-- The action bar will use a series of horizontal tabs in place of title text. -->
-            <enum name="tabBar" value="2" />
+            <!-- The action bar will use a selection list for navigation. -->
+            <enum name="listMode" value="1" />
+            <!-- The action bar will use a series of horizontal tabs for navigation. -->
+            <enum name="tabMode" value="2" />
         </attr>
         <!-- Options affecting how the action bar is displayed. -->
         <attr name="displayOptions">
-            <flag name="useLogo" value="1" />
-            <flag name="hideHome" value="2" />
+            <flag name="useLogo" value="0x1" />
+            <flag name="showHome" value="0x2" />
+            <flag name="homeAsUp" value="0x4" />
+            <flag name="showTitle" value="0x8" />
+            <flag name="showCustom" value="0x10" />
+            <!-- DEPRECATED - Remove this later!! -->
+            <flag name="hideHome" value="0x1000" />
         </attr>
-        <!-- Specifies the color used to style the action bar. -->
-        <attr name="colorFilter" format="color" />
         <!-- Specifies title text used for navigationMode="normal" -->
         <attr name="title" />
         <!-- Specifies subtitle text used for navigationMode="normal" -->
@@ -4272,6 +4320,8 @@
         <attr name="customNavigationLayout" format="reference" />
         <!-- Specifies a fixed height. -->
         <attr name="height" />
+        <!-- Specifies a drawable to use for the 'home as up' indicator. -->
+        <attr name="homeAsUpIndicator" format="reference" />
     </declare-styleable>
 
     <declare-styleable name="ActionMode">
@@ -4305,4 +4355,8 @@
             <flag name="end" value="4" />
         </attr>
     </declare-styleable>
+
+    <declare-styleable name="ActionBar_LayoutParams">
+        <attr name="layout_gravity" />
+    </declare-styleable>
 </resources>
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index 33cd100..b7f177f 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -70,4 +70,6 @@
   <item type="id" name="smallIcon" />
   <item type="id" name="custom" />
   <item type="id" name="home" />
+  <item type="id" name="fillInIntent" />
+  <item type="id" name="rowTypeId" />
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index bc20fbb..f905725 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1357,6 +1357,7 @@
   <public type="attr" name="dividerVertical" />
   <public type="attr" name="buttonGroupStyle" />
   <public type="attr" name="alertDialogButtonGroupStyle" />
+  <public type="attr" name="homeAsUpIndicator" />
 
   <public type="anim" name="animator_fade_in" />
   <public type="anim" name="animator_fade_out" />
@@ -1401,6 +1402,8 @@
   <public type="style" name="Theme.Holo.Light" />
   <public type="style" name="Theme.Holo.Dialog" />
   <public type="style" name="Theme.Holo.Light.Dialog" />
+  <public type="style" name="Theme.Holo.Extended" />
+  <public type="style" name="Theme.Holo.Light.Extended" />
 
   <public type="style" name="Widget.ListPopupWindow" />
   <public type="style" name="Widget.PopupMenu" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 8a5af7d..541835f 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1231,6 +1231,11 @@
     <string name="permdesc_sdcardWrite" product="default">Allows an application to write to the SD card.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_mediaStorageWrite" product="default">modify/delete internal media storage contents</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_mediaStorageWrite" product="default">Allows an application to modify the contents of the internal media storage.</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_cache_filesystem">access the cache filesystem</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_cache_filesystem">Allows an application to read and write the cache filesystem.</string>
@@ -1376,12 +1381,14 @@
     <!-- MMS phone number type -->
     <string name="phoneTypeMms">MMS</string>
 
-    <!-- Label for a birthday event -->
+    <!-- Label for custom events  [CHAR LIMIT=20] -->
+    <string name="eventTypeCustom">Custom</string>
+    <!-- Label for a birthday event  [CHAR LIMIT=20] -->
     <string name="eventTypeBirthday">Birthday</string>
-    <!-- Label for an anniversary event -->
+    <!-- Label for an anniversary event  [CHAR LIMIT=20] -->
     <string name="eventTypeAnniversary">Anniversary</string>
-    <!-- Label for other events -->
-    <string name="eventTypeOther">Event</string>
+    <!-- Label for other events  [CHAR LIMIT=20] -->
+    <string name="eventTypeOther">Other</string>
 
     <!-- Custom email type -->
     <string name="emailTypeCustom">Custom</string>
@@ -2321,6 +2328,9 @@
     <!-- Long label for a button on a full-screen input method for the "Done" action. -->
     <string name="ime_action_done">Done</string>
 
+    <!-- [CHAR LIMIT=6] Long label for a button on a full-screen input method for the "Previous" action. -->
+    <string name="ime_action_previous">Prev</string>
+
     <!-- Long label for a button on a full-screen input method for an unknown action. -->
     <string name="ime_action_default">Execute</string>
 
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index df11c34..adf1715 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -911,7 +911,7 @@
 
     <style name="Widget.ActionBar">
         <item name="android:background">@android:drawable/action_bar_background</item>
-        <item name="android:displayOptions">useLogo</item>
+        <item name="android:displayOptions">useLogo|showHome|showTitle</item>
         <item name="android:divider">@android:drawable/action_bar_divider</item>
         <item name="android:height">?android:attr/actionBarSize</item>
         <item name="android:paddingLeft">0dip</item>
@@ -1536,6 +1536,7 @@
         <item name="android:subtitleTextStyle">@android:style/TextAppearance.Holo.Widget.ActionBar.Subtitle</item>
         <item name="android:background">@null</item>
         <item name="android:divider">?android:attr/dividerVertical</item>
+        <item name="android:homeAsUpIndicator">@android:drawable/ic_ab_back_holo_dark</item>
     </style>
 
     <!-- Light widget styles -->
@@ -1788,6 +1789,7 @@
         <item name="android:titleTextStyle">@android:style/TextAppearance.Holo.Widget.ActionBar.Title</item>
         <item name="android:subtitleTextStyle">@android:style/TextAppearance.Holo.Widget.ActionBar.Subtitle</item>
         <item name="android:background">@null</item>
+        <item name="android:homeAsUpIndicator">@android:drawable/ic_ab_back_holo_light</item>
     </style>
 
     <!-- Animation Styles -->
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index eeefa9e..80072f4 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -572,7 +572,7 @@
     <style name="Theme.IconMenu">
         <!-- Menu/item attributes -->
         <item name="android:itemTextAppearance">@android:style/TextAppearance.Widget.IconMenu.Item</item>
-        <item name="android:selectableItemBackground">@android:drawable/menu_selector</item>
+        <item name="android:itemBackground">@android:drawable/menu_selector</item>
         <item name="android:itemIconDisabledAlpha">?android:attr/disabledAlpha</item>
         <item name="android:horizontalDivider">@android:drawable/divider_horizontal_dark</item>
         <item name="android:verticalDivider">@android:drawable/divider_vertical_dark</item>
@@ -641,7 +641,7 @@
         <item name="colorForeground">@android:color/bright_foreground_holo_dark</item>
         <item name="colorForegroundInverse">@android:color/bright_foreground_inverse_holo_dark</item>
         <item name="colorBackground">@android:color/background_holo_dark</item>
-        <item name="colorBackgroundCacheHint">@android:color/transparent</item>
+        <item name="colorBackgroundCacheHint">?android:attr/colorBackground</item>
         <item name="disabledAlpha">0.5</item>
         <item name="backgroundDimAmount">0.6</item>
 
@@ -734,7 +734,7 @@
         <item name="galleryItemBackground">@android:drawable/gallery_item_background</item>
         
         <!-- Window attributes -->
-        <item name="windowBackground">@android:drawable/background_holo_dark</item>
+        <item name="windowBackground">?android:attr/colorBackground</item>
         <item name="windowFrame">@null</item>
         <item name="windowNoTitle">false</item>
         <item name="windowFullscreen">false</item>
@@ -875,7 +875,7 @@
         <item name="colorForeground">@android:color/bright_foreground_holo_light</item>
         <item name="colorForegroundInverse">@android:color/bright_foreground_inverse_holo_light</item>
         <item name="colorBackground">@android:color/background_holo_light</item>
-        <item name="colorBackgroundCacheHint">@android:color/transparent</item>
+        <item name="colorBackgroundCacheHint">?android:attr/colorBackground</item>
         <item name="disabledAlpha">0.5</item>
         <item name="backgroundDimAmount">0.6</item>
 
@@ -968,7 +968,7 @@
         <item name="galleryItemBackground">@android:drawable/gallery_item_background</item>
         
         <!-- Window attributes -->
-        <item name="windowBackground">@android:drawable/background_holo_light</item>
+        <item name="windowBackground">?android:attr/colorBackground</item>
         <item name="windowFrame">@null</item>
         <item name="windowNoTitle">false</item>
         <item name="windowFullscreen">false</item>
@@ -1129,6 +1129,20 @@
         <item name="android:windowFullscreen">true</item>
         <item name="android:windowContentOverlay">@null</item>
     </style>
+
+    <!-- Variant of the holographic dark theme that includes extra decorations
+         appropriate for when hardware acceleration is in use. -->
+    <style name="Theme.Holo.Extended">
+        <item name="windowBackground">@android:drawable/background_holo_dark</item>
+        <item name="colorBackgroundCacheHint">@android:color/transparent</item>
+    </style>
+
+    <!-- Variant of the holographic light theme that includes extra decorations
+         appropriate for when hardware acceleration is in use. -->
+    <style name="Theme.Holo.Light.Extended">
+        <item name="windowBackground">@android:drawable/background_holo_light</item>
+        <item name="colorBackgroundCacheHint">@android:color/transparent</item>
+    </style>
  
     <!-- Dialog themes for Holo -->
 
diff --git a/core/tests/coretests/res/raw/obb_enc_file100_orig1.obb b/core/tests/coretests/res/raw/obb_enc_file100_orig1.obb
new file mode 100644
index 0000000..373b8e4
--- /dev/null
+++ b/core/tests/coretests/res/raw/obb_enc_file100_orig1.obb
Binary files differ
diff --git a/core/tests/coretests/res/raw/obb_enc_file100_orig3.obb b/core/tests/coretests/res/raw/obb_enc_file100_orig3.obb
new file mode 100644
index 0000000..aa531d8
--- /dev/null
+++ b/core/tests/coretests/res/raw/obb_enc_file100_orig3.obb
Binary files differ
diff --git a/core/tests/coretests/res/raw/obb_file1.obb b/core/tests/coretests/res/raw/obb_file1.obb
new file mode 100644
index 0000000..e71a680
--- /dev/null
+++ b/core/tests/coretests/res/raw/obb_file1.obb
Binary files differ
diff --git a/core/tests/coretests/res/raw/obb_file2.obb b/core/tests/coretests/res/raw/obb_file2.obb
new file mode 100644
index 0000000..1c397df
--- /dev/null
+++ b/core/tests/coretests/res/raw/obb_file2.obb
Binary files differ
diff --git a/core/tests/coretests/res/raw/obb_file2_nosign.obb b/core/tests/coretests/res/raw/obb_file2_nosign.obb
new file mode 100644
index 0000000..8292361
--- /dev/null
+++ b/core/tests/coretests/res/raw/obb_file2_nosign.obb
Binary files differ
diff --git a/core/tests/coretests/res/raw/obb_file3.obb b/core/tests/coretests/res/raw/obb_file3.obb
new file mode 100644
index 0000000..7f97a88
--- /dev/null
+++ b/core/tests/coretests/res/raw/obb_file3.obb
Binary files differ
diff --git a/core/tests/coretests/res/raw/obb_file3_bad_packagename.obb b/core/tests/coretests/res/raw/obb_file3_bad_packagename.obb
new file mode 100644
index 0000000..baa714a
--- /dev/null
+++ b/core/tests/coretests/res/raw/obb_file3_bad_packagename.obb
Binary files differ
diff --git a/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java b/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java
index 37fc6c7..8df37ad 100644
--- a/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java
+++ b/core/tests/coretests/src/android/app/DownloadManagerBaseTest.java
@@ -83,6 +83,7 @@
 
     protected static final int WAIT_FOR_DOWNLOAD_POLL_TIME = 1 * 1000;  // 1 second
     protected static final int MAX_WAIT_FOR_DOWNLOAD_TIME = 5 * 60 * 1000; // 5 minutes
+    protected static final int MAX_WAIT_FOR_LARGE_DOWNLOAD_TIME = 15 * 60 * 1000; // 15 minutes
 
     // Just a few popular file types used to return from a download
     protected enum DownloadFileType {
@@ -132,14 +133,34 @@
          */
         @Override
         public void onReceive(Context context, Intent intent) {
-            Log.i(LOG_TAG, "Received Notification:");
             if (intent.getAction().equalsIgnoreCase(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) {
                 synchronized(this) {
-                    ++mNumDownloadsCompleted;
-                    Log.i(LOG_TAG, "MultipleDownloadsCompletedReceiver got intent: " +
-                            intent.getAction() + " --> total count: " + mNumDownloadsCompleted);
-                    Bundle extras = intent.getExtras();
-                    downloadIds.add(new Long(extras.getLong(DownloadManager.EXTRA_DOWNLOAD_ID)));
+                    long id = intent.getExtras().getLong(DownloadManager.EXTRA_DOWNLOAD_ID);
+                    Log.i(LOG_TAG, "Received Notification for download: " + id);
+                    if (!downloadIds.contains(id)) {
+                        ++mNumDownloadsCompleted;
+                        Log.i(LOG_TAG, "MultipleDownloadsCompletedReceiver got intent: " +
+                                intent.getAction() + " --> total count: " + mNumDownloadsCompleted);
+                        downloadIds.add(id);
+
+                        DownloadManager dm = (DownloadManager)context.getSystemService(
+                                Context.DOWNLOAD_SERVICE);
+
+                        Cursor cursor = dm.query(new Query().setFilterById(id));
+                        try {
+                            if (cursor.moveToFirst()) {
+                                int status = cursor.getInt(cursor.getColumnIndex(
+                                        DownloadManager.COLUMN_STATUS));
+                                Log.i(LOG_TAG, "Download status is: " + status);
+                            } else {
+                                fail("No status found for completed download!");
+                            }
+                        } finally {
+                            cursor.close();
+                        }
+                    } else {
+                        Log.i(LOG_TAG, "Notification for id: " + id + " has already been made.");
+                    }
                 }
             }
         }
@@ -160,7 +181,7 @@
          * @return A Set<Long> with the ids of the completed downloads.
          */
         public Set<Long> getDownloadIds() {
-            synchronized(downloadIds) {
+            synchronized(this) {
                 Set<Long> returnIds = new HashSet<Long>(downloadIds);
                 return returnIds;
             }
@@ -204,6 +225,7 @@
             ConnectivityManager connManager = (ConnectivityManager)mContext.getSystemService(
                     Context.CONNECTIVITY_SERVICE);
             NetworkInfo info = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
+            Log.i(LOG_TAG, "WiFi Connection state is currently: " + info.isConnected());
             return info.isConnected();
         }
     }
@@ -491,6 +513,7 @@
      * @param enable true if it should be enabled, false if it should be disabled
      */
     protected void setWiFiStateOn(boolean enable) throws Exception {
+        Log.i(LOG_TAG, "Setting WiFi State to: " + enable);
         WifiManager manager = (WifiManager)mContext.getSystemService(Context.WIFI_SERVICE);
 
         manager.setWifiEnabled(enable);
@@ -508,7 +531,7 @@
 
             while (receiver.getWiFiIsOn() != enable && !timedOut) {
                 try {
-                    receiver.wait(DEFAULT_MAX_WAIT_TIME);
+                    receiver.wait(DEFAULT_WAIT_POLL_TIME);
 
                     if (SystemClock.elapsedRealtime() > timeoutTime) {
                         timedOut = true;
@@ -621,9 +644,11 @@
     /**
      * Helper to wait for a particular download to finish, or else a timeout to occur
      *
+     * Does not wait for a receiver notification of the download.
+     *
      * @param id The download id to query on (wait for)
      */
-    protected void waitForDownloadOrTimeout(long id) throws TimeoutException,
+    protected void waitForDownloadOrTimeout_skipNotification(long id) throws TimeoutException,
             InterruptedException {
         waitForDownloadOrTimeout(id, WAIT_FOR_DOWNLOAD_POLL_TIME, MAX_WAIT_FOR_DOWNLOAD_TIME);
     }
@@ -631,6 +656,21 @@
     /**
      * Helper to wait for a particular download to finish, or else a timeout to occur
      *
+     * Also guarantees a notification has been posted for the download.
+     *
+     * @param id The download id to query on (wait for)
+     */
+    protected void waitForDownloadOrTimeout(long id) throws TimeoutException,
+            InterruptedException {
+        waitForDownloadOrTimeout_skipNotification(id);
+        waitForReceiverNotifications(1);
+    }
+
+    /**
+     * Helper to wait for a particular download to finish, or else a timeout to occur
+     *
+     * Also guarantees a notification has been posted for the download.
+     *
      * @param id The download id to query on (wait for)
      * @param poll The amount of time to wait
      * @param timeoutMillis The max time (in ms) to wait for the download(s) to complete
@@ -638,11 +678,14 @@
     protected void waitForDownloadOrTimeout(long id, long poll, long timeoutMillis)
             throws TimeoutException, InterruptedException {
         doWaitForDownloadsOrTimeout(new Query().setFilterById(id), poll, timeoutMillis);
+        waitForReceiverNotifications(1);
     }
 
     /**
      * Helper to wait for all downloads to finish, or else a specified timeout to occur
      *
+     * Makes no guaranee that notifications have been posted for all downloads.
+     *
      * @param poll The amount of time to wait
      * @param timeoutMillis The max time (in ms) to wait for the download(s) to complete
      */
@@ -654,6 +697,8 @@
     /**
      * Helper to wait for all downloads to finish, or else a timeout to occur, but does not throw
      *
+     * Also guarantees a notification has been posted for the download.
+     *
      * @param id The id of the download to query against
      * @param poll The amount of time to wait
      * @param timeoutMillis The max time (in ms) to wait for the download(s) to complete
@@ -662,6 +707,7 @@
     protected boolean waitForDownloadOrTimeoutNoThrow(long id, long poll, long timeoutMillis) {
         try {
             doWaitForDownloadsOrTimeout(new Query().setFilterById(id), poll, timeoutMillis);
+            waitForReceiverNotifications(1);
         } catch (TimeoutException e) {
             return false;
         }
@@ -717,9 +763,8 @@
             Cursor cursor = mDownloadManager.query(query);
 
             try {
-                // @TODO: there may be a little cleaner way to check for success, perhaps
-                // via STATUS_SUCCESSFUL and/or STATUS_FAILED
-                if (cursor.getCount() == 0 && mReceiver.numDownloadsCompleted() > 0) {
+                if (cursor.getCount() == 0) {
+                    Log.i(LOG_TAG, "All downloads should be done...");
                     break;
                 }
                 currentWaitTime = timeoutWait(currentWaitTime, poll, timeoutMillis,
@@ -779,6 +824,36 @@
     }
 
     /**
+     * Convenience function to wait for just 1 notification of a download.
+     *
+     * @throws Exception if timed out while waiting
+     */
+    protected void waitForReceiverNotification() throws Exception {
+        waitForReceiverNotifications(1);
+    }
+
+    /**
+     * Synchronously waits for our receiver to receive notification for a given number of
+     * downloads.
+     *
+     * @param targetNumber The number of notifications for unique downloads to wait for; pass in
+     *         -1 to not wait for notification.
+     * @throws Exception if timed out while waiting
+     */
+    protected void waitForReceiverNotifications(int targetNumber) throws TimeoutException {
+        int count = mReceiver.numDownloadsCompleted();
+        int currentWaitTime = 0;
+
+        while (count < targetNumber) {
+            Log.i(LOG_TAG, "Waiting for notification of downloads...");
+            currentWaitTime = timeoutWait(currentWaitTime, WAIT_FOR_DOWNLOAD_POLL_TIME,
+                    MAX_WAIT_FOR_DOWNLOAD_TIME, "Timed out waiting for download notifications!"
+                    + " Received " + count + "notifications.");
+            count = mReceiver.numDownloadsCompleted();
+        }
+    }
+
+    /**
      * Synchronously waits for a file to increase in size (such as to monitor that a download is
      * progressing).
      *
diff --git a/core/tests/coretests/src/android/app/DownloadManagerIntegrationTest.java b/core/tests/coretests/src/android/app/DownloadManagerIntegrationTest.java
index cb7c2d2..4f79108 100644
--- a/core/tests/coretests/src/android/app/DownloadManagerIntegrationTest.java
+++ b/core/tests/coretests/src/android/app/DownloadManagerIntegrationTest.java
@@ -197,7 +197,7 @@
     public void testMultipleDownloads() throws Exception {
         // need to be sure all current downloads have stopped first
         removeAllCurrentDownloads();
-        int NUM_FILES = 50;
+        int NUM_FILES = 10;
         int MAX_FILE_SIZE = 500 * 1024; // 500 kb
 
         Random r = new LoggingRng();
@@ -205,15 +205,15 @@
             int size = r.nextInt(MAX_FILE_SIZE);
             byte[] blobData = generateData(size, DataType.TEXT);
 
-            Uri uri = getServerUri(DEFAULT_FILENAME);
+            Uri uri = getServerUri(DEFAULT_FILENAME + i);
             Request request = new Request(uri);
-            request.setTitle(String.format("%s--%d", DEFAULT_FILENAME, i));
+            request.setTitle(String.format("%s--%d", DEFAULT_FILENAME + i, i));
 
             // Prepare the mock server with a standard response
             enqueueResponse(HTTP_OK, blobData);
 
-            Log.i(LOG_TAG, "request: " + i);
-            mDownloadManager.enqueue(request);
+            long requestID = mDownloadManager.enqueue(request);
+            Log.i(LOG_TAG, "request: " + i + " -- requestID: " + requestID);
         }
 
         waitForDownloadsOrTimeout(WAIT_FOR_DOWNLOAD_POLL_TIME, MAX_WAIT_FOR_DOWNLOAD_TIME);
@@ -236,6 +236,8 @@
 
             assertEquals(NUM_FILES, mReceiver.numDownloadsCompleted());
         } finally {
+            Log.i(LOG_TAG, "All download IDs: " + mReceiver.getDownloadIds().toString());
+            Log.i(LOG_TAG, "Total downloads completed: " + mReceiver.getDownloadIds().size());
             cursor.close();
         }
     }
diff --git a/core/tests/coretests/src/android/app/DownloadManagerStressTest.java b/core/tests/coretests/src/android/app/DownloadManagerStressTest.java
index ddf138f..e0b28d0 100644
--- a/core/tests/coretests/src/android/app/DownloadManagerStressTest.java
+++ b/core/tests/coretests/src/android/app/DownloadManagerStressTest.java
@@ -24,7 +24,6 @@
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.ParcelFileDescriptor;
-import android.test.suitebuilder.annotation.LargeTest;
 import android.util.Log;
 
 
@@ -38,6 +37,7 @@
     public void setUp() throws Exception {
         super.setUp();
         mServer.play(0);
+        setWiFiStateOn(true);
         removeAllCurrentDownloads();
     }
 
@@ -71,7 +71,8 @@
             }
 
             // wait for the download to complete or timeout
-            waitForDownloadsOrTimeout(WAIT_FOR_DOWNLOAD_POLL_TIME, MAX_WAIT_FOR_DOWNLOAD_TIME);
+            waitForDownloadsOrTimeout(WAIT_FOR_DOWNLOAD_POLL_TIME,
+                    MAX_WAIT_FOR_LARGE_DOWNLOAD_TIME);
             cursor = mDownloadManager.query(new Query());
             assertEquals(NUM_FILES, cursor.getCount());
             Log.i(LOG_TAG, "Verified number of downloads in download manager is what we expect.");
@@ -130,10 +131,11 @@
     }
 
     /**
-     * Tests trying to download a large file (~300M bytes) when there's not enough space in cache
+     * Tests trying to download a large file (~600M bytes) when there's not enough space in cache
      */
     public void testInsufficientSpace() throws Exception {
-        long fileSize = 300000000L;
+        // @TODO: Rework this to fill up cache partition with a dynamically calculated size
+        long fileSize = 600000000L;
         File largeFile = createFileOnSD(null, fileSize, DataType.TEXT, null);
 
         Cursor cursor = null;
diff --git a/core/tests/coretests/src/android/os/storage/StorageManagerBaseTest.java b/core/tests/coretests/src/android/os/storage/StorageManagerBaseTest.java
new file mode 100644
index 0000000..90cb9a5
--- /dev/null
+++ b/core/tests/coretests/src/android/os/storage/StorageManagerBaseTest.java
@@ -0,0 +1,644 @@
+/*
+ * Copyright (C) 2010 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.storage;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.Resources.NotFoundException;
+import android.os.Environment;
+import android.os.SystemClock;
+import android.test.InstrumentationTestCase;
+import android.util.Log;
+import android.os.Environment;
+import android.os.FileUtils;
+import android.os.storage.OnObbStateChangeListener;
+import android.os.storage.StorageManager;
+
+import java.io.BufferedReader;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.StringReader;
+
+public class StorageManagerBaseTest extends InstrumentationTestCase {
+
+    protected Context mContext = null;
+    protected StorageManager mSm = null;
+    private static String LOG_TAG = "StorageManagerBaseTest";
+    protected static final long MAX_WAIT_TIME = 120*1000;
+    protected static final long WAIT_TIME_INCR = 5*1000;
+    protected static String OBB_FILE_1 = "obb_file1.obb";
+    protected static String OBB_FILE_1_CONTENTS_1 = "OneToOneThousandInts.bin";
+    protected static String OBB_FILE_2 = "obb_file2.obb";
+    protected static String OBB_FILE_3 = "obb_file3.obb";
+    protected static String OBB_FILE_1_PASSWORD = "password1";
+    protected static String OBB_FILE_1_ENCRYPTED = "obb_enc_file100_orig1.obb";
+    protected static String OBB_FILE_2_UNSIGNED = "obb_file2_nosign.obb";
+    protected static String OBB_FILE_3_PASSWORD = "password3";
+    protected static String OBB_FILE_3_ENCRYPTED = "obb_enc_file100_orig3.obb";
+    protected static String OBB_FILE_3_BAD_PACKAGENAME = "obb_file3_bad_packagename.obb";
+
+    protected static boolean FORCE = true;
+    protected static boolean DONT_FORCE = false;
+
+    private static final String SAMPLE1_TEXT = "This is sample text.\n\nTesting 1 2 3.";
+
+    private static final String SAMPLE2_TEXT =
+        "We the people of the United States, in order to form a more perfect union,\n"
+        + "establish justice, insure domestic tranquility, provide for the common\n"
+        + "defense, promote the general welfare, and secure the blessings of liberty\n"
+        + "to ourselves and our posterity, do ordain and establish this Constitution\n"
+        + "for the United States of America.\n\n";
+
+    class MountingObbThread extends Thread {
+        boolean mStop = false;
+        volatile boolean mFileOpenOnObb = false;
+        private String mObbFilePath = null;
+        private String mPathToContentsFile = null;
+        private String mOfficialObbFilePath = null;
+
+        /**
+         * Constructor
+         *
+         * @param obbFilePath path to the OBB image file
+         * @param pathToContentsFile path to a file on the mounted OBB volume to open after the OBB
+         *      has been mounted
+         */
+        public MountingObbThread (String obbFilePath, String pathToContentsFile) {
+            assertTrue("obbFilePath cannot be null!", obbFilePath != null);
+            mObbFilePath = obbFilePath;
+            assertTrue("path to contents file cannot be null!", pathToContentsFile != null);
+            mPathToContentsFile = pathToContentsFile;
+        }
+
+        /**
+         * Runs the thread
+         *
+         * Mounts OBB_FILE_1, and tries to open a file on the mounted OBB (specified in the
+         * constructor). Once it's open, it waits until someone calls its doStop(), after which it
+         * closes the opened file.
+         */
+        public void run() {
+            // the official OBB file path and the mount-request file path should be the same, but
+            // let's distinguish the two as they may make for some interesting tests later
+            mOfficialObbFilePath = mountObb(mObbFilePath);
+            assertEquals("Expected and actual OBB file paths differ!", mObbFilePath,
+                    mOfficialObbFilePath);
+
+            // open a file on OBB 1...
+            DataInputStream inputFile = openFileOnMountedObb(mOfficialObbFilePath,
+                    mPathToContentsFile);
+            assertTrue("Failed to open file!", inputFile != null);
+
+            synchronized (this) {
+                mFileOpenOnObb = true;
+                notifyAll();
+            }
+
+            while (!mStop) {
+                try {
+                    Thread.sleep(WAIT_TIME_INCR);
+                } catch (InterruptedException e) {
+                    // nothing special to be done for interruptions
+                }
+            }
+            try {
+                inputFile.close();
+            } catch (IOException e) {
+                fail("Failed to close file on OBB due to error: " + e.toString());
+            }
+        }
+
+        /**
+         * Tells whether a file has yet been successfully opened on the OBB or not
+         *
+         * @return true if the specified file on the OBB was opened; false otherwise
+         */
+        public boolean isFileOpenOnObb() {
+            return mFileOpenOnObb;
+        }
+
+        /**
+         * Returns the official path of the OBB file that was mounted
+         *
+         * This is not the mount path, but the normalized path to the actual OBB file
+         *
+         * @return a {@link String} representation of the path to the OBB file that was mounted
+         */
+        public String officialObbFilePath() {
+            return mOfficialObbFilePath;
+        }
+
+        /**
+         * Requests the thread to stop running
+         *
+         * Closes the opened file and returns
+         */
+        public void doStop() {
+            mStop = true;
+        }
+    }
+
+    public class ObbListener extends OnObbStateChangeListener {
+        private String LOG_TAG = "StorageManagerBaseTest.ObbListener";
+
+        String mOfficialPath = null;
+        boolean mDone = false;
+        int mState = -1;
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public void onObbStateChange(String path, int state) {
+            Log.i(LOG_TAG, "Storage state changing to: " + state);
+
+            synchronized (this) {
+                Log.i(LOG_TAG, "OfficialPath is now: " + path);
+                mState = state;
+                mOfficialPath = path;
+                mDone = true;
+                notifyAll();
+            }
+        }
+
+        /**
+         * Tells whether we are done or not (system told us the OBB has changed state)
+         *
+         * @return true if the system has told us this OBB's state has changed, false otherwise
+         */
+        public boolean isDone() {
+            return mDone;
+        }
+
+        /**
+         * The last state of the OBB, according to the system
+         *
+         * @return A {@link String} representation of the state of the OBB
+         */
+        public int state() {
+            return mState;
+        }
+
+        /**
+         * The normalized, official path to the OBB file (according to the system)
+         *
+         * @return A {@link String} representation of the official path to the OBB file
+         */
+        public String officialPath() {
+            return mOfficialPath;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setUp() throws Exception {
+        mContext = getInstrumentation().getContext();
+        mSm = (StorageManager)mContext.getSystemService(android.content.Context.STORAGE_SERVICE);
+
+    }
+
+    /**
+     * Helper to copy a raw resource file to an actual specified file
+     *
+     * @param rawResId The raw resource ID of the OBB resource file
+     * @param outFile A File representing the file we want to copy the OBB to
+     * @throws NotFoundException If the resource file could not be found
+     */
+    private void copyRawToFile(int rawResId, File outFile) throws NotFoundException {
+        Resources res = mContext.getResources();
+        InputStream is = null;
+        try {
+            is = res.openRawResource(rawResId);
+        } catch (NotFoundException e) {
+            Log.i(LOG_TAG, "Failed to load resource with id: " + rawResId);
+            throw e;
+        }
+        FileUtils.setPermissions(outFile.getPath(), FileUtils.S_IRWXU | FileUtils.S_IRWXG
+                | FileUtils.S_IRWXO, -1, -1);
+        assertTrue(FileUtils.copyToFile(is, outFile));
+        FileUtils.setPermissions(outFile.getPath(), FileUtils.S_IRWXU | FileUtils.S_IRWXG
+                | FileUtils.S_IRWXO, -1, -1);
+    }
+
+    /**
+     * Creates an OBB file (with the given name), into the app's standard files directory
+     *
+     * @param name The name of the OBB file we want to create/write to
+     * @param rawResId The raw resource ID of the OBB file in the package
+     * @return A {@link File} representing the file to write to
+     */
+    protected File createObbFile(String name, int rawResId) {
+        File outFile = null;
+        try {
+            final File filesDir = mContext.getFilesDir();
+            outFile = new File(filesDir, name);
+            copyRawToFile(rawResId, outFile);
+        } catch (NotFoundException e) {
+            if (outFile != null) {
+                outFile.delete();
+            }
+        }
+        return outFile;
+    }
+
+    /**
+     * Mounts an OBB file and opens a file located on it
+     *
+     * @param obbPath Path to OBB image
+     * @param fileName The full name and path to the file on the OBB to open once the OBB is mounted
+     * @return The {@link DataInputStream} representing the opened file, if successful in opening
+     *      the file, or null of unsuccessful.
+     */
+    protected DataInputStream openFileOnMountedObb(String obbPath, String fileName) {
+
+        // get mSm obb mount path
+        assertTrue("Cannot open file when OBB is not mounted!", mSm.isObbMounted(obbPath));
+
+        String path = mSm.getMountedObbPath(obbPath);
+        assertTrue("Path should not be null!", path != null);
+
+        File inFile = new File(path, fileName);
+        DataInputStream inStream = null;
+        try {
+            inStream = new DataInputStream(new FileInputStream(inFile));
+            Log.i(LOG_TAG, "Opened file: " + fileName + " for read at path: " + path);
+        } catch (FileNotFoundException e) {
+            Log.e(LOG_TAG, e.toString());
+            return null;
+        } catch (SecurityException e) {
+            Log.e(LOG_TAG, e.toString());
+            return null;
+        }
+        return inStream;
+    }
+
+    /**
+     * Mounts an OBB file
+     *
+     * @param obbFilePath The full path to the OBB file to mount
+     * @param key (optional) The key to use to unencrypt the OBB; pass null for no encryption
+     * @param expectedState The expected state resulting from trying to mount the OBB
+     * @return A {@link String} representing the normalized path to OBB file that was mounted
+     */
+    protected String mountObb(String obbFilePath, String key, int expectedState) {
+        return doMountObb(obbFilePath, key, expectedState);
+    }
+
+    /**
+     * Mounts an OBB file with default options (no encryption, mounting succeeds)
+     *
+     * @param obbFilePath The full path to the OBB file to mount
+     * @return A {@link String} representing the normalized path to OBB file that was mounted
+     */
+    protected String mountObb(String obbFilePath) {
+        return doMountObb(obbFilePath, null, OnObbStateChangeListener.MOUNTED);
+    }
+
+    /**
+     * Synchronously waits for an OBB listener to be signaled of a state change, but does not throw
+     *
+     * @param obbListener The listener for the OBB file
+     * @return true if the listener was signaled of a state change by the system, else returns
+     *      false if we time out.
+     */
+    protected boolean doWaitForObbStateChange(ObbListener obbListener) {
+        synchronized(obbListener) {
+            long waitTimeMillis = 0;
+            while (!obbListener.isDone()) {
+                try {
+                    Log.i(LOG_TAG, "Waiting for listener...");
+                    obbListener.wait(WAIT_TIME_INCR);
+                    Log.i(LOG_TAG, "Awoke from waiting for listener...");
+                    waitTimeMillis += WAIT_TIME_INCR;
+                    if (waitTimeMillis > MAX_WAIT_TIME) {
+                        fail("Timed out waiting for OBB state to change!");
+                    }
+                } catch (InterruptedException e) {
+                    Log.i(LOG_TAG, e.toString());
+                }
+            }
+            return obbListener.isDone();
+            }
+    }
+
+    /**
+     * Synchronously waits for an OBB listener to be signaled of a state change
+     *
+     * @param obbListener The listener for the OBB file
+     * @return true if the listener was signaled of a state change by the system; else a fail()
+     *      is triggered if we timed out
+     */
+    protected String doMountObb_noThrow(String obbFilePath, String key, int expectedState) {
+        Log.i(LOG_TAG, "doMountObb() on " + obbFilePath + " using key: " + key);
+        assertTrue ("Null path was passed in for OBB file!", obbFilePath != null);
+        assertTrue ("Null path was passed in for OBB file!", obbFilePath != null);
+
+        ObbListener obbListener = new ObbListener();
+        boolean success = mSm.mountObb(obbFilePath, key, obbListener);
+        success &= obbFilePath.equals(doWaitForObbStateChange(obbListener));
+        success &= (expectedState == obbListener.state());
+
+        if (OnObbStateChangeListener.MOUNTED == expectedState) {
+            success &= obbFilePath.equals(obbListener.officialPath());
+            success &= mSm.isObbMounted(obbListener.officialPath());
+        } else {
+            success &= !mSm.isObbMounted(obbListener.officialPath());
+        }
+
+        if (success) {
+            return obbListener.officialPath();
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Mounts an OBB file without throwing and synchronously waits for it to finish mounting
+     *
+     * @param obbFilePath The full path to the OBB file to mount
+     * @param key (optional) The key to use to unencrypt the OBB; pass null for no encryption
+     * @param expectedState The expected state resulting from trying to mount the OBB
+     * @return A {@link String} representing the actual normalized path to OBB file that was
+     *      mounted, or null if the mounting failed
+     */
+    protected String doMountObb(String obbFilePath, String key, int expectedState) {
+        Log.i(LOG_TAG, "doMountObb() on " + obbFilePath + " using key: " + key);
+        assertTrue ("Null path was passed in for OBB file!", obbFilePath != null);
+
+        ObbListener obbListener = new ObbListener();
+        assertTrue("mountObb call failed", mSm.mountObb(obbFilePath, key, obbListener));
+        assertTrue("Failed to get OBB mount status change for file: " + obbFilePath,
+                doWaitForObbStateChange(obbListener));
+        assertEquals("OBB mount state not what was expected!", expectedState, obbListener.state());
+
+        if (OnObbStateChangeListener.MOUNTED == expectedState) {
+            assertEquals(obbFilePath, obbListener.officialPath());
+            assertTrue("Obb should be mounted, but SM reports it is not!",
+                    mSm.isObbMounted(obbListener.officialPath()));
+        } else if (OnObbStateChangeListener.UNMOUNTED == expectedState) {
+            assertFalse("Obb should not be mounted, but SM reports it is!",
+                    mSm.isObbMounted(obbListener.officialPath()));
+        }
+
+        assertEquals("Mount state is not what was expected!", expectedState, obbListener.state());
+        return obbListener.officialPath();
+    }
+
+    /**
+     * Unmounts an OBB file without throwing, and synchronously waits for it to finish unmounting
+     *
+     * @param obbFilePath The full path to the OBB file to mount
+     * @param force true if we shuold force the unmount, false otherwise
+     * @return true if the unmount was successful, false otherwise
+     */
+    protected boolean unmountObb_noThrow(String obbFilePath, boolean force) {
+        Log.i(LOG_TAG, "doUnmountObb_noThrow() on " + obbFilePath);
+        assertTrue ("Null path was passed in for OBB file!", obbFilePath != null);
+        boolean success = true;
+
+        ObbListener obbListener = new ObbListener();
+        assertTrue("unmountObb call failed", mSm.unmountObb(obbFilePath, force, obbListener));
+
+        boolean stateChanged = doWaitForObbStateChange(obbListener);
+        if (force) {
+            success &= stateChanged;
+            success &= (OnObbStateChangeListener.UNMOUNTED == obbListener.state());
+            success &= !mSm.isObbMounted(obbFilePath);
+        }
+        return success;
+    }
+
+    /**
+     * Unmounts an OBB file and synchronously waits for it to finish unmounting
+     *
+     * @param obbFilePath The full path to the OBB file to mount
+     * @param force true if we shuold force the unmount, false otherwise
+     */
+    protected void unmountObb(String obbFilePath, boolean force) {
+        Log.i(LOG_TAG, "doUnmountObb() on " + obbFilePath);
+        assertTrue ("Null path was passed in for OBB file!", obbFilePath != null);
+
+        ObbListener obbListener = new ObbListener();
+        assertTrue("unmountObb call failed", mSm.unmountObb(obbFilePath, force, obbListener));
+
+        boolean stateChanged = doWaitForObbStateChange(obbListener);
+        if (force) {
+            assertTrue("Timed out waiting to unmount OBB file " + obbFilePath, stateChanged);
+            assertEquals("OBB failed to unmount", OnObbStateChangeListener.UNMOUNTED,
+                    obbListener.state());
+            assertFalse("Obb should NOT be mounted, but SM reports it is!", mSm.isObbMounted(
+                    obbFilePath));
+        }
+    }
+
+    /**
+     * Helper to validate the contents of an "int" file in an OBB.
+     *
+     * The format of the files are sequential int's, in the range of: [start..end)
+     *
+     * @param path The full path to the file (path to OBB)
+     * @param filename The filename containing the ints to validate
+     * @param start The first int expected to be found in the file
+     * @param end The last int + 1 expected to be found in the file
+     */
+    protected void doValidateIntContents(String path, String filename, int start, int end) {
+        File inFile = new File(path, filename);
+        DataInputStream inStream = null;
+        Log.i(LOG_TAG, "Validating file " + filename + " at " + path);
+        try {
+            inStream = new DataInputStream(new FileInputStream(inFile));
+
+            for (int i = start; i < end; ++i) {
+                if (inStream.readInt() != i) {
+                    fail("Unexpected value read in OBB file");
+                }
+            }
+            if (inStream != null) {
+                inStream.close();
+            }
+            Log.i(LOG_TAG, "Successfully validated file " + filename);
+        } catch (FileNotFoundException e) {
+            fail("File " + inFile + " not found: " + e.toString());
+        } catch (IOException e) {
+            fail("IOError with file " + inFile + ":" + e.toString());
+        }
+    }
+
+    /**
+     * Helper to validate the contents of a text file in an OBB
+     *
+     * @param path The full path to the file (path to OBB)
+     * @param filename The filename containing the ints to validate
+     * @param contents A {@link String} containing the expected contents of the file
+     */
+    protected void doValidateTextContents(String path, String filename, String contents) {
+        File inFile = new File(path, filename);
+        BufferedReader fileReader = null;
+        BufferedReader textReader = null;
+        Log.i(LOG_TAG, "Validating file " + filename + " at " + path);
+        try {
+            fileReader = new BufferedReader(new FileReader(inFile));
+            textReader = new BufferedReader(new StringReader(contents));
+            String actual = null;
+            String expected = null;
+            while ((actual = fileReader.readLine()) != null) {
+                expected = textReader.readLine();
+                if (!actual.equals(expected)) {
+                    fail("File " + filename + " in OBB " + path + " does not match expected value");
+                }
+            }
+            fileReader.close();
+            textReader.close();
+            Log.i(LOG_TAG, "File " + filename + " successfully verified.");
+        } catch (IOException e) {
+            fail("IOError with file " + inFile + ":" + e.toString());
+        }
+    }
+
+    /**
+     * Helper to validate the contents of a "long" file on our OBBs
+     *
+     * The format of the files are sequential 0's of type long
+     *
+     * @param path The full path to the file (path to OBB)
+     * @param filename The filename containing the ints to validate
+     * @param size The number of zero's expected in the file
+     * @param checkContents If true, the contents of the file are actually verified; if false,
+     *      we simply verify that the file can be opened
+     */
+    protected void doValidateZeroLongFile(String path, String filename, long size,
+            boolean checkContents) {
+        File inFile = new File(path, filename);
+        DataInputStream inStream = null;
+        Log.i(LOG_TAG, "Validating file " + filename + " at " + path);
+        try {
+            inStream = new DataInputStream(new FileInputStream(inFile));
+
+            if (checkContents) {
+                for (long i = 0; i < size; ++i) {
+                    if (inStream.readLong() != 0) {
+                        fail("Unexpected value read in OBB file" + filename);
+                    }
+                }
+            }
+
+            if (inStream != null) {
+                inStream.close();
+            }
+            Log.i(LOG_TAG, "File " + filename + " successfully verified for " + size + " zeros");
+        } catch (IOException e) {
+            fail("IOError with file " + inFile + ":" + e.toString());
+        }
+    }
+
+    /**
+     * Helper to synchronously wait until we can get a path for a given OBB file
+     *
+     * @param filePath The full normalized path to the OBB file
+     * @return The mounted path of the OBB, used to access contents in it
+     */
+    protected String doWaitForPath(String filePath) {
+        String path = null;
+
+        long waitTimeMillis = 0;
+        assertTrue("OBB " + filePath + " is not currently mounted!", mSm.isObbMounted(filePath));
+        while (path == null) {
+            try {
+                Thread.sleep(WAIT_TIME_INCR);
+                waitTimeMillis += WAIT_TIME_INCR;
+                if (waitTimeMillis > MAX_WAIT_TIME) {
+                    fail("Timed out waiting to get path of OBB file " + filePath);
+                }
+            } catch (InterruptedException e) {
+                // do nothing
+            }
+            path = mSm.getMountedObbPath(filePath);
+        }
+        Log.i(LOG_TAG, "Got OBB path: " + path);
+        return path;
+    }
+
+    /**
+     * Verifies the pre-defined contents of our first OBB (OBB_FILE_1)
+     *
+     * The OBB contains 4 files and no subdirectories
+     *
+     * @param filePath The normalized path to the already-mounted OBB file
+     */
+    protected void verifyObb1Contents(String filePath) {
+        String path = null;
+        path = doWaitForPath(filePath);
+
+        // Validate contents of 2 files in this obb
+        doValidateIntContents(path, "OneToOneThousandInts.bin", 0, 1000);
+        doValidateIntContents(path, "SevenHundredInts.bin", 0, 700);
+        doValidateZeroLongFile(path, "FiveLongs.bin", 5, true);
+    }
+
+    /**
+     * Verifies the pre-defined contents of our second OBB (OBB_FILE_2)
+     *
+     * The OBB contains 2 files and no subdirectories
+     *
+     * @param filePath The normalized path to the already-mounted OBB file
+     */
+    protected void verifyObb2Contents(String filename) {
+        String path = null;
+        path = doWaitForPath(filename);
+
+        // Validate contents of file
+        doValidateTextContents(path, "sample.txt", SAMPLE1_TEXT);
+        doValidateTextContents(path, "sample2.txt", SAMPLE2_TEXT);
+    }
+
+    /**
+     * Verifies the pre-defined contents of our third OBB (OBB_FILE_3)
+     *
+     * The OBB contains nested files and subdirectories
+     *
+     * @param filePath The normalized path to the already-mounted OBB file
+     */
+    protected void verifyObb3Contents(String filename) {
+        String path = null;
+        path = doWaitForPath(filename);
+
+        // Validate contents of file
+        doValidateIntContents(path, "OneToOneThousandInts.bin", 0, 1000);
+        doValidateZeroLongFile(path, "TwoHundredLongs", 200, true);
+
+        // validate subdirectory 1
+        doValidateZeroLongFile(path + File.separator + "subdir1", "FiftyLongs", 50, true);
+
+        // validate subdirectory subdir2/
+        doValidateIntContents(path + File.separator + "subdir2", "OneToOneThousandInts", 0, 1000);
+
+        // validate subdirectory subdir2/subdir2a/
+        doValidateZeroLongFile(path + File.separator + "subdir2" + File.separator + "subdir2a",
+                "TwoHundredLongs", 200, true);
+
+        // validate subdirectory subdir2/subdir2a/subdir2a1/
+        doValidateIntContents(path + File.separator + "subdir2" + File.separator + "subdir2a"
+                + File.separator + "subdir2a1", "OneToOneThousandInts", 0, 1000);
+    }
+}
\ No newline at end of file
diff --git a/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java b/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java
new file mode 100644
index 0000000..71772d9
--- /dev/null
+++ b/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2010 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.storage;
+
+import android.content.Context;
+import android.os.Environment;
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+
+import com.android.frameworks.coretests.R;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.File;
+import java.io.FileInputStream;
+
+import junit.framework.AssertionFailedError;
+
+public class StorageManagerIntegrationTest extends StorageManagerBaseTest {
+
+    private static String LOG_TAG = "StorageManagerBaseTest.StorageManagerIntegrationTest";
+    protected File mFile = null;
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        mContext = getInstrumentation().getContext();
+        mFile = null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void tearDown() throws Exception {
+        if (mFile != null) {
+            mFile.delete();
+            mFile = null;
+        }
+        super.tearDown();
+    }
+
+    /**
+     * Tests mounting a single OBB file and verifies its contents.
+     */
+    @LargeTest
+    public void testMountSingleObb() {
+        mFile = createObbFile(OBB_FILE_1, R.raw.obb_file1);
+        String filePath = mFile.getAbsolutePath();
+        mountObb(filePath);
+        verifyObb1Contents(filePath);
+        unmountObb(filePath, DONT_FORCE);
+    }
+
+    /**
+     * Tests mounting several OBB files and verifies its contents.
+     */
+    @LargeTest
+    public void testMountMultipleObb() {
+        File file1 = null;
+        File file2 = null;
+        File file3 = null;
+        try {
+            file1 = createObbFile(OBB_FILE_1, R.raw.obb_file1);
+            String filePath1 = file1.getAbsolutePath();
+            mountObb(filePath1);
+            verifyObb1Contents(filePath1);
+
+            file2 = createObbFile(OBB_FILE_2, R.raw.obb_file2);
+            String filePath2 = file2.getAbsolutePath();
+            mountObb(filePath2);
+            verifyObb2Contents(filePath2);
+
+            file3 = createObbFile(OBB_FILE_3, R.raw.obb_file3);
+            String filePath3 = file3.getAbsolutePath();
+            mountObb(filePath3);
+            verifyObb3Contents(filePath3);
+
+            unmountObb(filePath1, DONT_FORCE);
+            unmountObb(filePath2, DONT_FORCE);
+            unmountObb(filePath3, DONT_FORCE);
+        } finally {
+            if (file1 != null) {
+                file1.delete();
+            }
+            if (file2 != null) {
+                file2.delete();
+            }
+            if (file3 != null) {
+                file3.delete();
+            }
+        }
+    }
+
+    /**
+     * Tests mounting a single encrypted OBB file and verifies its contents.
+     */
+    @LargeTest
+    public void testMountSingleEncryptedObb() {
+        mFile = createObbFile(OBB_FILE_3_ENCRYPTED, R.raw.obb_enc_file100_orig3);
+        String filePath = mFile.getAbsolutePath();
+        mountObb(filePath, OBB_FILE_3_PASSWORD, OnObbStateChangeListener.MOUNTED);
+        verifyObb3Contents(filePath);
+        unmountObb(filePath, DONT_FORCE);
+    }
+
+    /**
+     * Tests mounting a single encrypted OBB file using an invalid password.
+     */
+    @LargeTest
+    public void testMountSingleEncryptedObbInvalidPassword() {
+        mFile = createObbFile("bad password@$%#@^*(!&)", R.raw.obb_enc_file100_orig3);
+        String filePath = mFile.getAbsolutePath();
+        mountObb(filePath, OBB_FILE_3_PASSWORD, OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT);
+        unmountObb(filePath, DONT_FORCE);
+    }
+
+    /**
+     * Tests simultaneously mounting 2 encrypted OBBs with different keys and verifies contents.
+     */
+    @LargeTest
+    public void testMountTwoEncryptedObb() {
+        File file3 = null;
+        File file1 = null;
+        try {
+            file3 = createObbFile(OBB_FILE_3_ENCRYPTED, R.raw.obb_enc_file100_orig3);
+            String filePath3 = file3.getAbsolutePath();
+            mountObb(filePath3, OBB_FILE_3_PASSWORD, OnObbStateChangeListener.MOUNTED);
+            verifyObb3Contents(filePath3);
+
+            file1 = createObbFile(OBB_FILE_1_ENCRYPTED, R.raw.obb_enc_file100_orig1);
+            String filePath1 = file1.getAbsolutePath();
+            mountObb(filePath1, OBB_FILE_1_PASSWORD, OnObbStateChangeListener.MOUNTED);
+            verifyObb1Contents(filePath1);
+
+            unmountObb(filePath3, DONT_FORCE);
+            unmountObb(filePath1, DONT_FORCE);
+        } finally {
+            if (file3 != null) {
+                file3.delete();
+            }
+            if (file1 != null) {
+                file1.delete();
+            }
+        }
+    }
+
+    /**
+     * Tests that we can not force unmount when a file is currently open on the OBB.
+     */
+    @LargeTest
+    public void testUnmount_DontForce() {
+        mFile = createObbFile(OBB_FILE_1, R.raw.obb_file1);
+        String obbFilePath = mFile.getAbsolutePath();
+
+        MountingObbThread mountingThread = new MountingObbThread(obbFilePath,
+                OBB_FILE_1_CONTENTS_1);
+
+        try {
+            mountingThread.start();
+
+            long waitTime = 0;
+            while (!mountingThread.isFileOpenOnObb()) {
+                synchronized (mountingThread) {
+                    Log.i(LOG_TAG, "Waiting for file to be opened on OBB...");
+                    mountingThread.wait(WAIT_TIME_INCR);
+                    waitTime += WAIT_TIME_INCR;
+                    if (waitTime > MAX_WAIT_TIME) {
+                        fail("Timed out waiting for file file to be opened on OBB!");
+                    }
+                }
+            }
+
+            unmountObb(obbFilePath, DONT_FORCE);
+
+            // verify still mounted
+            assertTrue("mounted path should not be null!", obbFilePath != null);
+            assertTrue("mounted path should still be mounted!", mSm.isObbMounted(obbFilePath));
+
+            // close the opened file
+            mountingThread.doStop();
+
+            // try unmounting again (should succeed this time)
+            unmountObb(obbFilePath, DONT_FORCE);
+            assertFalse("mounted path should no longer be mounted!",
+                    mSm.isObbMounted(obbFilePath));
+        } catch (InterruptedException e) {
+            fail("Timed out waiting for file on OBB to be opened...");
+        }
+    }
+
+    /**
+     * Tests mounting a single OBB that isn't signed.
+     */
+    @LargeTest
+    public void testMountUnsignedObb() {
+        mFile = createObbFile(OBB_FILE_2_UNSIGNED, R.raw.obb_file2_nosign);
+        String filePath = mFile.getAbsolutePath();
+        mountObb(filePath, OBB_FILE_2_UNSIGNED, OnObbStateChangeListener.ERROR_INTERNAL);
+    }
+
+    /**
+     * Tests mounting a single OBB that is signed with a different package.
+     */
+    @LargeTest
+    public void testMountBadPackageNameObb() {
+        mFile = createObbFile(OBB_FILE_3_BAD_PACKAGENAME, R.raw.obb_file3_bad_packagename);
+        String filePath = mFile.getAbsolutePath();
+        mountObb(filePath, OBB_FILE_3_BAD_PACKAGENAME,
+                OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
+    }
+
+    /**
+     * Tests remounting a single OBB that has already been mounted.
+     */
+    @LargeTest
+    public void testRemountObb() {
+        mFile = createObbFile(OBB_FILE_1, R.raw.obb_file1);
+        String filePath = mFile.getAbsolutePath();
+        mountObb(filePath);
+        verifyObb1Contents(filePath);
+        mountObb(filePath, null, OnObbStateChangeListener.ERROR_ALREADY_MOUNTED);
+        verifyObb1Contents(filePath);
+        unmountObb(filePath, DONT_FORCE);
+    }
+}
\ No newline at end of file
diff --git a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestApp.java b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestApp.java
index c0f670b..e1d7b4c 100644
--- a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestApp.java
+++ b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/DownloadManagerTestApp.java
@@ -53,6 +53,8 @@
     protected static long DOWNLOAD_500K_FILESIZE = 570927;
     protected static String DOWNLOAD_1MB_FILENAME = "External1mb.apk";
     protected static long DOWNLOAD_1MB_FILESIZE = 1041262;
+    protected static String DOWNLOAD_5MB_FILENAME = "External5mb.apk";
+    protected static long DOWNLOAD_5MB_FILESIZE = 5138700;
     protected static String DOWNLOAD_10MB_FILENAME = "External10mb.apk";
     protected static long DOWNLOAD_10MB_FILESIZE = 10258741;
 
@@ -135,7 +137,7 @@
      * @throws Exception if unsuccessful
      */
     public void initiateDownload() throws Exception {
-        String filename = DOWNLOAD_1MB_FILENAME;
+        String filename = DOWNLOAD_5MB_FILENAME;
         mContext.deleteFile(DOWNLOAD_STARTED_FLAG);
         FileOutputStream fileOutput = mContext.openFileOutput(DOWNLOAD_STARTED_FLAG, 0);
         DataOutputStream outputFile = null;
@@ -171,8 +173,8 @@
      * @throws Exception if unsuccessful
      */
     public void verifyFileDownloadSucceeded() throws Exception {
-        String filename = DOWNLOAD_1MB_FILENAME;
-        long filesize = DOWNLOAD_1MB_FILESIZE;
+        String filename = DOWNLOAD_5MB_FILENAME;
+        long filesize = DOWNLOAD_5MB_FILESIZE;
         long dlRequest = -1;
         boolean rebootMarkerValid = false;
         DataInputStream dataInputFile = null;
@@ -205,7 +207,8 @@
             int status = cursor.getInt(columnIndex);
             int currentWaitTime = 0;
 
-            // Wait until the download finishes
+            // Wait until the download finishes; don't wait for a notification b/c
+            // the download may well have been completed before the last reboot.
             waitForDownloadOrTimeout(dlRequest);
 
             Log.i(LOG_TAG, "Verifying download information...");
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 439fc90..f458576 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -58,6 +58,10 @@
         <group gid="sdcard_rw" />
     </permission>
 
+    <permission name="android.permission.WRITE_MEDIA_STORAGE" >
+        <group gid="media_rw" />
+    </permission>
+
     <permission name="android.permission.ACCESS_USB" >
         <group gid="usb" />
     </permission>
diff --git a/docs/html/guide/developing/tools/MonkeyDevice.jd b/docs/html/guide/developing/tools/MonkeyDevice.jd
new file mode 100644
index 0000000..34bbba9
--- /dev/null
+++ b/docs/html/guide/developing/tools/MonkeyDevice.jd
@@ -0,0 +1,1353 @@
+page.title=MonkeyDevice
+@jd:body
+<style>
+    h4.jd-details-title {background-color: #DEE8F1;}
+</style>
+<p>
+    A monkeyrunner class that represents a device or emulator accessible by the workstation running
+<code><a href="{@docRoot}guide/developing/tools/monkeyrunner_concepts.html">monkeyrunner</a></code>.
+</p>
+<p>
+    This class is used to control an Android device or emulator. The methods send UI events,
+    retrieve information, install and remove applications, and run applications.
+</p>
+<p>
+    You normally do not have to create an instance of <code>MonkeyDevice</code>. Instead, you
+    use
+<code><a href="{@docRoot}guide/developing/tools/MonkeyRunner.html#waitForConnection">
+MonkeyRunner.waitForConnection()</a></code> to create a new object from a connection to a device or
+emulator. For example, instead of
+using:</p>
+<pre>
+newdevice = MonkeyDevice()
+</pre>
+<p>
+    you would use:
+</p>
+<pre>
+newdevice = MonkeyRunner.waitForConnection()
+</pre>
+<h2>Summary</h2>
+    <table id="constants" class="jd-sumtable" style="background-color: white;">
+       <tr>
+            <th colspan="12" style="background-color: #E2E2E2">Constants</th>
+       </tr>
+        <tr class="api" style="background-color: white;">
+            <td class="jd-typecol"><em>string</em></td>
+            <td class="jd-linkcol"><a href="#ACTION_DOWN">DOWN</a></td>
+            <td class="jd-descrcol" width="100%">
+                Use this with the <code>type</code> argument of
+                <code><a href="#press">press()</a></code> or <code><a href="#touch">touch()</a>
+                </code>
+                to send a DOWN event.
+            </td>
+        </tr>
+        <tr class="api" style="background-color: white;">
+            <td class="jd-typecol"><em>string</em></td>
+            <td class="jd-linkcol"><a href="#ACTION_UP">UP</a></td>
+            <td class="jd-descrcol" width="100%">
+                Use this with the <code>type</code> argument of
+                <code><a href="#press">press()</a></code> or <code><a href="#touch">touch()</a>
+                </code>
+                to send an UP event.
+            </td>
+        </tr>
+        <tr class="api" style="background-color: white;">
+            <td class="jd-typecol"><em>string</em></td>
+            <td class="jd-linkcol"><a href="#ACTION_DOWN_AND_UP">DOWN_AND_UP</a></td>
+            <td class="jd-descrcol" width="100%">
+                Use this with the <code>type</code> argument of
+                <code><a href="#press">press()</a></code> or <code><a href="#touch">touch()</a>
+                </code>
+                to send a DOWN event immediately followed by an UP event.
+            </td>
+        </tr>
+    </table>
+<table id="pubmethods" class="jd-sumtable">
+    <tr>
+        <th colspan="12" style="background-color: #E2E2E2">Methods</th>
+    </tr>
+    <tr class="api" >
+        <td class="jd-typecol">
+            <nobr>
+                void
+            </nobr>
+        </td>
+        <td class="jd-linkcol" width="100%">
+            <nobr>
+                <span class="sympad">
+                    <a href="#broadcastIntent">broadcastIntent</a>
+                </span>
+                (<em>string</em> uri,
+                <em>string</em> action,
+                <em>string</em> data,
+                <em>string</em> mimetype,
+                <em>iterable</em> categories
+                <em>dictionary</em> extras,
+                <em>component</em> component,
+                <em>iterable</em> flags)
+            </nobr>
+            <div class="jd-descrdiv">
+                Broadcasts an Intent to this device, as if the Intent were coming from an
+                application.
+            </div>
+        </td>
+    </tr>
+    <tr class="api" >
+        <td class="jd-typecol">
+            <nobr>
+                void
+            </nobr>
+        </td>
+        <td class="jd-linkcol" width="100%">
+            <nobr>
+                <span class="sympad">
+                    <a href="#drag">drag</a>
+                </span>
+                (<em>tuple</em> start,
+                <em>tuple</em> end,
+                <em>float</em> duration,
+                <em>integer</em> steps)
+            </nobr>
+            <div class="jd-descrdiv">
+                Simulates a drag gesture (touch, hold, and move) on this device's screen.
+            </div>
+        </td>
+    </tr>
+    <tr class="api" >
+        <td class="jd-typecol">
+            <nobr>
+                <em>object</em>
+            </nobr>
+        </td>
+        <td class="jd-linkcol" width="100%">
+            <nobr>
+                <span class="sympad">
+                    <a href="#getProperty">getProperty</a>
+                </span>
+                (<em>string</em> key)
+            </nobr>
+            <div class="jd-descrdiv">
+                Given the name of a system environment variable, returns its value for this device.
+                The available variable names are listed in the <a href="#getProperty">
+                detailed description</a> of this method.
+            </div>
+        </td>
+    </tr>
+    <tr class="api" >
+        <td class="jd-typecol">
+            <nobr>
+                <em>object</em>
+            </nobr>
+        </td>
+        <td class="jd-linkcol" width="100%">
+            <nobr>
+                <span class="sympad">
+                    <a href="#getSystemProperty">getSystemProperty</a>
+                </span>
+                (<em>string</em> key)
+            </nobr>
+            <div class="jd-descrdiv">
+.               The API equivalent of <code>adb shell getprop &lt;key&gt;. This is provided for use
+                by platform developers.
+            </div>
+        </td>
+    </tr>
+    <tr class="api" >
+        <td class="jd-typecol">
+            <nobr>
+                void
+            </nobr>
+        </td>
+        <td class="jd-linkcol" width="100%">
+            <nobr>
+                <span class="sympad">
+                    <a href="#installPackage">installPackage</a>
+                </span>
+                (<em>string</em> path)
+            </nobr>
+            <div class="jd-descrdiv">
+                Installs the Android application or test package contained in packageFile onto this
+                device. If the application or test package is already installed, it is replaced.
+            </div>
+        </td>
+    </tr>
+    <tr class="api" >
+        <td class="jd-typecol">
+            <nobr>
+                <em>dictionary</em>
+            </nobr>
+        </td>
+        <td class="jd-linkcol" width="100%">
+            <nobr>
+                <span class="sympad">
+                    <a href="#instrument">instrument</a>
+                </span>
+                (<em>string</em> className,
+                <em>dictionary</em> args)
+            </nobr>
+            <div class="jd-descrdiv">
+                Runs the specified component under Android instrumentation, and returns the results
+                in a dictionary whose exact format is dictated by the component being run. The
+                component must already be present on this device.
+            </div>
+        </td>
+    </tr>
+    <tr class="api">
+        <td class="jd-typecol">
+            <nobr>
+                void
+            </nobr>
+        </td>
+        <td class="jd-linkcol" width="100%">
+            <nobr>
+                <span class="sympad">
+                    <a href="#press">press</a>
+                </span>
+                (<em>string</em> name,
+                <em>dictionary</em> type)
+            </nobr>
+            <div class="jd-descrdiv">
+                Sends the key event specified by type to the key specified by
+                keycode.
+            </div>
+        </td>
+    </tr>
+    <tr class="api" >
+        <td class="jd-typecol">
+            <nobr>
+                void
+            </nobr>
+        </td>
+        <td class="jd-linkcol" width="100%">
+            <nobr>
+                <span class="sympad">
+                    <a href="#reboot">reboot</a>
+                </span>
+                (<em>string</em> into)
+            </nobr>
+            <div class="jd-descrdiv">
+                Reboots this device into the bootloader specified by bootloadType.
+            </div>
+        </td>
+    </tr>
+    <tr class="api" >
+        <td class="jd-typecol">
+            <nobr>
+                void
+            </nobr>
+        </td>
+        <td class="jd-linkcol" width="100%">
+            <nobr>
+                <span class="sympad">
+                    <a href="#removePackage">removePackage</a>
+                </span>
+                (<em>string</em> package)
+            </nobr>
+            <div class="jd-descrdiv">
+                Deletes the specified package from this device, including its data and cache.
+            </div>
+        </td>
+    </tr>
+    <tr class="api" >
+        <td class="jd-typecol">
+            <nobr>
+                <em>object</em>
+            </nobr>
+        </td>
+        <td class="jd-linkcol" width="100%">
+            <nobr>
+                <span class="sympad">
+                    <a href="#shell">shell</a>
+                </span>
+                (<em>string</em> cmd)
+            </nobr>
+            <div class="jd-descrdiv">
+                Executes an <code>adb</code> shell command and returns the result, if any.
+            </div>
+        </td>
+    </tr>
+    <tr class="api" >
+        <td class="jd-typecol">
+            <nobr>
+                void
+            </nobr>
+        </td>
+        <td class="jd-linkcol" width="100%">
+            <nobr>
+                <span class="sympad">
+                    <a href="#startActivity">startActivity</a>
+                </span>
+                (<em>string</em> uri,
+                <em>string</em> action,
+                <em>string</em> data,
+                <em>string</em> mimetype,
+                <em>iterable</em> categories
+                <em>dictionary</em> extras,
+                <em>component</em> component,
+                <em>flags</em>)
+            </nobr>
+            <div class="jd-descrdiv">
+                Starts an Activity on this device by sending an Intent constructed from the
+                supplied arguments.
+            </div>
+        </td>
+    </tr>
+    <tr class="api" >
+        <td class="jd-typecol">
+            <nobr>
+                <code>
+                <a href="{@docRoot}guide/developing/tools/MonkeyImage.html">
+                        MonkeyImage
+                    </a>
+                </code>
+            </nobr>
+        </td>
+        <td class="jd-linkcol" width="100%">
+            <nobr>
+                <span class="sympad">
+                    <a href="#takeSnapshot">takeSnapshot</a>()
+                </span>
+            </nobr>
+            <div class="jd-descrdiv">
+                Captures the entire screen buffer of this device, yielding a
+                <code>
+                <a href="{@docRoot}guide/developing/tools/MonkeyImage.html">
+                        MonkeyImage
+                </a>
+                </code> object containing a screen capture of the current display.
+            </div>
+        </td>
+    </tr>
+    <tr class="api" >
+        <td class="jd-typecol">
+            <nobr>
+                void
+            </nobr>
+        </td>
+        <td class="jd-linkcol" width="100%">
+            <nobr>
+                <span class="sympad">
+                    <a href="#touch">touch</a>
+                </span>
+               (<em>integer</em> x,
+                 <em>integer</em> y,
+                 <em>integer</em> type)
+            </nobr>
+            <div class="jd-descrdiv">
+                Sends a touch event specified by type to the screen location specified
+                by x and y.
+            </div>
+        </td>
+    </tr>
+    <tr class="api" >
+        <td class="jd-typecol">
+            <nobr>
+                void
+            </nobr>
+        </td>
+        <td class="jd-linkcol" width="100%">
+            <nobr>
+                <span class="sympad">
+                    <a href="#touch">type</a>
+                </span>
+                   (<em>string</em> message)
+            </nobr>
+            <div class="jd-descrdiv">
+                Sends the characters contained in message to this device, as if they
+                had been typed on the device's keyboard. This is equivalent to calling
+                <code><a href="#press">press()</a></code> for each keycode in <code>message</code>
+                using the key event type <code><a href="#ACTION_DOWN_AND_UP"></a>DOWN_AND_UP</code>.
+            </div>
+        </td>
+    </tr>
+    <tr class="api" >
+        <td class="jd-typecol">
+            <nobr>
+                void
+            </nobr>
+        </td>
+        <td class="jd-linkcol" width="100%">
+            <nobr>
+                <span class="sympad">
+                    <a href="#touch">wake</a>
+                </span>
+                   ()
+            </nobr>
+            <div class="jd-descrdiv">
+                Wakes the screen of this device.
+            </div>
+        </td>
+    </tr>
+</table>
+<!-- ========= ENUM CONSTANTS DETAIL ======== -->
+<h2>Constants</h2>
+<A NAME="ACTION_DOWN"></a>
+<div class="jd-details api">
+    <h4 class="jd-details-title">
+        <span class="normal">
+            <em>string</em>
+        </span>
+            DOWN
+    </h4>
+    <div class="jd-details-descr">
+        <div class="jd-tagdata jd-tagdescr">
+            <p>
+                <code><a href="#press">press()</a></code> or
+                <code><a href="#press">touch()</a></code> value.
+                Specifies that a DOWN event type should be sent to the device, corresponding to
+                pressing down on a key or touching the screen.
+            </p>
+        </div>
+    </div>
+</div>
+<A NAME="ACTION_UP"></A>
+<div class="jd-details api">
+    <h4 class="jd-details-title">
+        <span class="normal">
+            <em>string</em>
+        </span>
+            UP
+    </h4>
+    <div class="jd-details-descr">
+        <div class="jd-tagdata jd-tagdescr">
+            <p>
+                <code><a href="#press">press()</a></code> or
+                <code><a href="#press">touch()</a></code> value.
+                Specifies that an UP event type should be sent to the device, corresponding to
+                releasing a key or lifting up from the screen.
+            </p>
+        </div>
+    </div>
+</div>
+<A NAME="ACTION_DOWN_AND_UP"></A>
+
+<div class="jd-details api">
+    <h4 class="jd-details-title">
+        <span class="normal">
+            <em>string</em>
+        </span>
+            DOWN_AND_UP
+    </h4>
+    <div class="jd-details-descr">
+        <div class="jd-tagdata jd-tagdescr">
+            <p>
+                <code><a href="#press">press()</a></code>,
+                <code><a href="#press">touch()</a></code> or
+                <code><a href="#type">type()</a></code> value.
+                Specifies that a DOWN event type followed by an UP event type should be sent to the
+                device, corresponding to typing a key or clicking the screen.
+            </p>
+        </div>
+    </div>
+</div>
+<!-- ========= METHOD DETAIL ======== -->
+<!-- Public methods -->
+<h2>Public Methods</h2>
+<A NAME="broadcastIntent"></A>
+<div class="jd-details api ">
+    <h4 class="jd-details-title">
+      <span class="normal">
+        void
+      </span>
+      <span class="sympad">broadcastIntent</span>
+      <span class="normal">
+      (
+            <em>string</em> uri,
+            <em>string</em> action,
+            <em>string</em> data,
+            <em>string</em> mimetype,
+            <em>iterable</em> categories
+            <em>dictionary</em> extras,
+            <em>component</em> component,
+            <em>iterable</em> flags)
+      </span>
+    </h4>
+  <div class="jd-details-descr">
+
+    <div class="jd-tagdata jd-tagdescr">
+        <p>
+            Broadcasts an Intent to this device, as if the Intent were coming from an
+            application. See {@link android.content.Intent Intent} for more information about the
+            arguments.
+        </p>
+    </div>
+    <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Arguments</h5>
+      <table class="jd-tagtable">
+        <tr>
+          <th>uri</th>
+            <td>
+                The URI for the Intent.
+                (see {@link android.content.Intent#setData(android.net.Uri) Intent.setData()}).
+            </td>
+        </tr>
+        <tr>
+            <th>action</th>
+            <td>
+                The action for this Intent
+                (see {@link android.content.Intent#setAction(java.lang.String) Intent.setAction()}).
+            </td>
+        </tr>
+        <tr>
+            <th>data</th>
+            <td>
+                The data URI for this Intent
+                (see {@link android.content.Intent#setData(android.net.Uri) Intent.setData()}).
+            </td>
+        </tr>
+        <tr>
+            <th>mimetype</th>
+            <td>
+                The MIME type for the Intent
+                (see {@link android.content.Intent#setType(java.lang.String) Intent.setType()}).
+            </td>
+        </tr>
+        <tr>
+            <th>categories</th>
+            <td>
+                An iterable data structure containing strings that define categories for this
+                Intent
+                (see
+                {@link android.content.Intent#addCategory(java.lang.String) Intent.addCategory()}).
+            </td>
+        </tr>
+        <tr>
+            <th>extras</th>
+            <td>
+                A dictionary of extra data for this Intent
+                (see {@link android.content.Intent#putExtra(java.lang.String,java.lang.String)
+                Intent.putExtra()}
+                for an example).
+                <p>
+                    The key for each dictionary item should be a <em>string</em>. The item's value
+                    can be any simple or structured data type.
+                </p>
+            </td>
+        </tr>
+        <tr>
+            <th>component</th>
+            <td>
+                The component for this Intent (see {@link android.content.ComponentName}).
+                Using this argument will direct the Intent to a specific class within a specific
+                Android package.
+            </td>
+        </tr>
+        <tr>
+            <th>flags</th>
+            <td>
+                An iterable data structure containing flags that control how the Intent is handled
+                (see {@link android.content.Intent#setFlags(int) Intent.setFlags()}).
+            </td>
+        </tr>
+      </table>
+    </div>
+  </div>
+</div>
+<A NAME="drag"></A>
+<div class="jd-details api ">
+    <h4 class="jd-details-title">
+      <span class="normal">
+        void
+      </span>
+      <span class="sympad">drag</span>
+      <span class="normal">
+      (
+            <em>tuple</em> start,
+            <em>tuple</em> end,
+            <em>float</em> duration,
+            <em>integer</em> steps)
+      </span>
+    </h4>
+  <div class="jd-details-descr">
+
+    <div class="jd-tagdata jd-tagdescr">
+        <p>
+            Simulates a drag gesture (touch, hold, and move) on this device's screen.
+        </p>
+    </div>
+    <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Arguments</h5>
+      <table class="jd-tagtable">
+        <tr>
+          <th>start</th>
+          <td>
+            The starting point of the drag gesture, in the form of a <em>tuple</em>
+            (x,y) where x and y are <em>integers</em>.
+          </td>
+        </tr>
+        <tr>
+          <th>end</th>
+          <td>
+            The end point of the drag gesture, in the form of a <em>tuple</em> (x,y)
+            where x and y are <em>integers</em>.
+          </td>
+        </tr>
+        <tr>
+            <th>duration</th>
+            <td>The duration of the drag gesture in seconds. The default is 1.0 seconds.</td>
+        </tr>
+        <tr>
+            <th>steps</th>
+            <td>The number of steps to take when interpolating points. The default is 10.</td>
+        </tr>
+      </table>
+    </div>
+  </div>
+</div>
+<A NAME="getProperty"></A>
+<div class="jd-details api ">
+    <h4 class="jd-details-title">
+      <span class="normal">
+        <em>object</em>
+      </span>
+      <span class="sympad">getProperty</span>
+      <span class="normal">
+        (<em>string</em> key)
+      </span>
+    </h4>
+  <div class="jd-details-descr">
+
+    <div class="jd-tagdata jd-tagdescr">
+        <p>
+            Given the name of a system environment variable, returns its value for this device.
+        </p>
+    </div>
+    <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Arguments</h5>
+      <table class="jd-tagtable">
+        <tr>
+          <th>key</th>
+          <td>
+            The name of the system environment variable. The available variable names are listed in
+            <a href="#table1">Table 1. Property variable names</a> at the end of this topic.
+          </td>
+        </tr>
+      </table>
+    </div>
+    <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Returns</h5>
+      <ul class="nolist">
+        <li>
+            The value of the variable. The data format varies according to the variable requested.
+        </li>
+      </ul>
+    </div>
+  </div>
+</div>
+<A NAME="getSystemProperty"></A>
+<div class="jd-details api ">
+    <h4 class="jd-details-title">
+      <span class="normal">
+        <em>object</em>
+      </span>
+      <span class="sympad">getSystemProperty</span>
+      <span class="normal">
+      (<em>string</em> key)
+      </span>
+    </h4>
+  <div class="jd-details-descr">
+
+    <div class="jd-tagdata jd-tagdescr">
+        <p>
+            Synonym for <code><a href="#getProperty">getProperty()</a></code>.
+        </p>
+    </div>
+    <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Arguments</h5>
+      <table class="jd-tagtable">
+        <tr>
+          <th>key</th>
+          <td>
+            The name of the system environment variable. The available variable names are listed in
+            <a href="#table1">Table 1. Property Variable Names</a>.
+          </td>
+        </tr>
+      </table>
+    </div>
+    <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Returns</h5>
+      <ul class="nolist">
+        <li>
+            The value of the variable. The data format varies according to the variable requested.
+        </li>
+      </ul>
+    </div>
+  </div>
+</div>
+<A NAME="installPackage"></A>
+<div class="jd-details api ">
+    <h4 class="jd-details-title">
+      <span class="normal">
+        void
+      </span>
+      <span class="sympad">installPackage</span>
+      <span class="normal">
+      (<em>string</em> path)
+      </span>
+    </h4>
+  <div class="jd-details-descr">
+
+    <div class="jd-tagdata jd-tagdescr">
+        <p>
+            Installs the Android application or test package contained in packageFile
+            onto this device. If the application or test package is already installed, it is
+            replaced.
+        </p>
+    </div>
+    <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Arguments</h5>
+      <table class="jd-tagtable">
+        <tr>
+          <th>path</th>
+          <td>
+            The fully-qualified path and filename of the <code>.apk</code> file to install.
+          </td>
+        </tr>
+      </table>
+    </div>
+  </div>
+</div>
+<A NAME="instrument"></A>
+<div class="jd-details api ">
+    <h4 class="jd-details-title">
+      <span class="normal">
+        <em>dictionary</em>
+      </span>
+      <span class="sympad">instrument</span>
+      <span class="normal">
+      (
+            <em>string</em> className,
+            <em>dictionary</em> args)
+      </span>
+    </h4>
+  <div class="jd-details-descr">
+
+    <div class="jd-tagdata jd-tagdescr">
+        <p>
+            Runs the specified component with Android instrumentation, and returns the results
+            in a dictionary whose exact format is dictated by the component being run. The
+            component must already be present on this device.
+        </p>
+        <p>
+            Use this method to start a test case that uses one of Android's test case classes.
+            See <a href="{@docRoot}guide/topics/testing/testing_android.html">Testing
+            Fundamentals</a> to learn more about unit testing with the Android testing
+            framework.
+        </p>
+    </div>
+    <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Arguments</h5>
+      <table class="jd-tagtable">
+        <tr>
+          <th>className</th>
+          <td>
+            The name of an Android component that is already installed on this device, in the
+            standard form packagename/classname, where packagename is the
+            Android package name of a <code>.apk</code> file on this device, and
+            classname is the class name of an Android component (Activity,
+            ContentProvider, Service, or BroadcastReceiver) in that file. Both
+            packagename and classname must be fully qualified. See
+            {@link android.content.ComponentName} for more details.
+          </td>
+        </tr>
+        <tr>
+          <th>args</th>
+          <td>
+            A dictionary containing flags and their values. These are passed to the component as it
+            is started. If the flag does not take a value, set its dictionary value to an empty
+            string.
+          </td>
+        </tr>
+      </table>
+    <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Returns</h5>
+        <ul class="nolist">
+            <li>
+                <p>
+                    A dictionary containing the component's output. The contents of the dictionary
+                    are defined by the component itself.
+                </p>
+                <p>
+                    If you use {@link android.test.InstrumentationTestRunner} as the class name in
+                    the componentName argument, then the result dictionary contains
+                    the single key "stream". The value of "stream" is a <em>string</em> containing
+                    the test output, as if <code>InstrumentationTestRunner</code> was run from the
+                    command line. The format of this output is described in
+                    <a href="{@docRoot}guide/developing/testing/testing_otheride.html">
+                    Testing in Other IDEs</a>.
+                </p>
+            </li>
+        </ul>
+    </div>
+    </div>
+  </div>
+</div>
+<A NAME="press"></A>
+<div class="jd-details api ">
+    <h4 class="jd-details-title">
+      <span class="normal">
+        void
+      </span>
+      <span class="sympad">press</span>
+      <span class="normal">
+      (<em>string</em> name,
+      <em>integer</em> type)
+      </span>
+    </h4>
+  <div class="jd-details-descr">
+    <div class="jd-tagdata jd-tagdescr">
+        <p>
+            Sends the key event specified by <code>type</code> to the key specified by
+            <code>keycode</code>.
+        </p>
+    </div>
+    <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Arguments</h5>
+      <table class="jd-tagtable">
+        <tr>
+          <th>name</th>
+          <td>
+            The name of the keycode to send. See {@link android.view.KeyEvent} for a list of
+            keycode names. Use the keycode name, not its integer value.
+          </td>
+        </tr>
+        <tr>
+          <th>type</th>
+          <td>
+            The type of key event to send. The allowed values are <code><a href="#ACTION_DOWN">
+            DOWN</a></code>, <code><a href="#ACTION_UP">UP</a></code>, and
+            <code><a href="#ACTION_DOWN_AND_UP">DOWN_AND_UP</a></code>.
+          </td>
+        </tr>
+      </table>
+    </div>
+  </div>
+</div>
+<A NAME="reboot"></A>
+<div class="jd-details api ">
+    <h4 class="jd-details-title">
+      <span class="normal">
+        void
+      </span>
+      <span class="sympad">reboot</span>
+      <span class="normal">
+      (<em>string</em> bootloadType)
+      </span>
+    </h4>
+  <div class="jd-details-descr">
+
+    <div class="jd-tagdata jd-tagdescr">
+        <p>
+                Reboots this device into the bootloader specified by <code>bootloadType</code>.
+        </p>
+    </div>
+    <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Arguments</h5>
+      <table class="jd-tagtable">
+        <tr>
+          <th>into</th>
+          <td>
+            The type of bootloader to reboot into. The allowed values are
+            "bootloader", "recovery", or "None".
+          </td>
+        </tr>
+      </table>
+    </div>
+  </div>
+</div>
+<A NAME="removePackage"></A>
+<div class="jd-details api ">
+    <h4 class="jd-details-title">
+      <span class="normal">
+        void
+      </span>
+      <span class="sympad">removePackage</span>
+      <span class="normal">
+      (<em>string</em> package)
+      </span>
+    </h4>
+  <div class="jd-details-descr">
+
+    <div class="jd-tagdata jd-tagdescr">
+        <p>
+            Deletes the specified package from this device, including its data and cache.
+        </p>
+    </div>
+    <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Arguments</h5>
+      <table class="jd-tagtable">
+        <tr>
+          <th>package</th>
+          <td>
+            The Android package name of an <code>.apk</code> file on this device.
+          </td>
+      </table>
+    </div>
+  </div>
+</div>
+<A NAME="shell"></A>
+<div class="jd-details api ">
+    <h4 class="jd-details-title">
+      <span class="normal">
+        <em>object</em>
+      </span>
+      <span class="sympad">shell</span>
+      <span class="normal">
+      (<em>string</em> cmd)
+      </span>
+    </h4>
+  <div class="jd-details-descr">
+    <div class="jd-tagdata jd-tagdescr">
+        <p>
+            Executes an <code>adb</code> shell command and returns the result, if any.
+        </p>
+    </div>
+    <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Arguments</h5>
+      <table class="jd-tagtable">
+        <tr>
+          <th>cmd</th>
+          <td>
+            The command to execute in the <code>adb</code> shell. The form of these commands is
+            described in the topic <a href="{@docRoot}guide/developing/tools/adb.html">Android
+            Debug Bridge</a>.
+          </td>
+        </tr>
+      </table>
+    </div>
+    <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Returns</h5>
+      <ul class="nolist">
+        <li>
+            The results of the command, if any. The format of the results is determined by the
+            command.
+        </li>
+      </ul>
+    </div>
+  </div>
+</div>
+<A NAME="startActivity"></A>
+<div class="jd-details api ">
+    <h4 class="jd-details-title">
+      <span class="normal">
+        void
+      </span>
+      <span class="sympad">startActivity</span>
+      <span class="normal">
+      (
+            <em>string</em> uri,
+            <em>string</em> action,
+            <em>string</em> data,
+            <em>string</em> mimetype,
+            <em>iterable</em> categories
+            <em>dictionary</em> extras,
+            <em>component</em> component,
+            <em>iterable</em> flags)
+      </span>
+    </h4>
+  <div class="jd-details-descr">
+    <div class="jd-tagdata jd-tagdescr">
+        <p>
+           Starts an Activity on this device by sending an Intent constructed from the
+           supplied arguments.
+        </p>
+    </div>
+    <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Arguments</h5>
+      <table class="jd-tagtable">
+        <tr>
+          <th>uri</th>
+          <td>
+            The URI for the Intent.
+            (see {@link android.content.Intent#setData(android.net.Uri) Intent.setData()}).
+          </td>
+        </tr>
+        <tr>
+            <th>action</th>
+            <td>
+                The action for the Intent
+                (see {@link android.content.Intent#setAction(java.lang.String) Intent.setAction()}).
+            </td>
+        </tr>
+        <tr>
+            <th>data</th>
+            <td>
+                The data URI for the Intent
+                (see {@link android.content.Intent#setData(android.net.Uri) Intent.setData()}).
+            </td>
+        </tr>
+        <tr>
+            <th>mimetype</th>
+            <td>
+                The MIME type for the Intent
+                (see {@link android.content.Intent#setType(java.lang.String) Intent.setType()}).
+            </td>
+        </tr>
+        <tr>
+            <th>categories</th>
+            <td>
+                An iterable data structure containing strings that define categories for the
+                Intent
+                (see
+                {@link android.content.Intent#addCategory(java.lang.String) Intent.addCategory()}).
+            </td>
+        </tr>
+        <tr>
+            <th>extras</th>
+            <td>
+                A dictionary of extra data for the Intent
+                (see
+                {@link android.content.Intent#putExtra(java.lang.String,java.lang.String)
+                Intent.putExtra()}
+                for an example).
+                <p>
+                    The key for each dictionary item should be a <em>string</em>. The item's value
+                    can be any simple or structured data type.
+                </p>
+            </td>
+        </tr>
+        <tr>
+            <th>component</th>
+            <td>
+                The component for the Intent
+                (see {@link android.content.ComponentName}). Using this argument will direct the
+                Intent to a specific class within a specific Android package.
+            </td>
+        </tr>
+        <tr>
+            <th>flags</th>
+            <td>
+                An iterable data structure containing flags that control how the Intent is handled
+                (see {@link android.content.Intent#setFlags(int) Intent.setFlags()}).
+            </td>
+        </tr>
+      </table>
+    </div>
+  </div>
+</div>
+<A NAME="takeSnapshot"></A>
+<div class="jd-details api ">
+    <h4 class="jd-details-title">
+      <span class="normal">
+        <code>
+            <a href="{@docRoot}guide/developing/tools/MonkeyImage.html">
+                MonkeyImage
+            </a>
+        </code>
+      </span>
+      <span class="sympad">takeSnapshot</span>
+      <span class="normal">
+      ()
+      </span>
+    </h4>
+  <div class="jd-details-descr">
+    <div class="jd-tagdata jd-tagdescr">
+        <p>
+            Captures the entire screen buffer of this device, yielding a
+            screen capture of the current display.
+        </p>
+    </div>
+    <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Returns</h5>
+      <ul class="nolist">
+        <li>
+            A <a href="{@docRoot}guide/developing/tools/MonkeyImage.html">
+            MonkeyImage</a> object containing the image of the current display.
+        </li>
+      </ul>
+    </div>
+  </div>
+</div>
+<A NAME="touch"></A>
+<div class="jd-details api ">
+    <h4 class="jd-details-title">
+      <span class="normal">
+        void
+      </span>
+      <span class="sympad">touch</span>
+      <span class="normal">
+      (
+            <em>integer</em> x,
+            <em>integer</em> y,
+            <em>string</em> type)
+      </span>
+    </h4>
+  <div class="jd-details-descr">
+    <div class="jd-tagdata jd-tagdescr">
+        <p>
+            Sends a touch event specified by type to the screen location specified
+            by x and y.
+        </p>
+    </div>
+    <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Arguments</h5>
+      <table class="jd-tagtable">
+        <tr>
+          <th>x</th>
+          <td>
+            The horizontal position of the touch in actual device pixels, starting from the left of
+            the screen in its current orientation.
+          </td>
+        </tr>
+        <tr>
+          <th>y</th>
+          <td>
+            The vertical position of the touch in actual device pixels, starting from the top of
+            the screen in its current orientation.
+          </td>
+        </tr>
+        <tr>
+            <th>type</th>
+            <td>
+                The type of key event to send. The allowed values are <code><a href="#ACTION_DOWN">
+                DOWN</a></code>, <code><a href="#ACTION_UP">UP</a></code>, and
+                <code><a href="#ACTION_DOWN_AND_UP">DOWN_AND_UP</a></code>.
+            </td>
+        </tr>
+      </table>
+    </div>
+  </div>
+</div>
+<A NAME="type"></A>
+<div class="jd-details api ">
+    <h4 class="jd-details-title">
+      <span class="normal">
+        void
+      </span>
+      <span class="sympad">type</span>
+      <span class="normal">
+      (<em>string</em> message)
+      </span>
+    </h4>
+  <div class="jd-details-descr">
+    <div class="jd-tagdata jd-tagdescr">
+        <p>
+            Sends the characters contained in message to this device, as if they
+            had been typed on the device's keyboard. This is equivalent to calling
+            <code><a href="#press">press()</a></code> for each keycode in <code>message</code>
+            using the key event type <code><a href="#ACTION_DOWN_AND_UP">DOWN_AND_UP</a></code>.
+        </p>
+    </div>
+    <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Arguments</h5>
+      <table class="jd-tagtable">
+        <tr>
+          <th>message</th>
+          <td>
+              A string containing the characters to send.
+          </td>
+        </tr>
+      </table>
+    </div>
+  </div>
+</div>
+<A NAME="wake"></A>
+<div class="jd-details api">
+    <h4 class="jd-details-title">
+      <span class="normal">
+        void
+      </span>
+      <span class="sympad">wake</span>
+      <span class="normal">
+      ()
+      </span>
+    </h4>
+  <div class="jd-details-descr">
+    <div class="jd-tagdata jd-tagdescr">
+        <p>
+            Wakes the screen of this device.
+        </p>
+    </div>
+  </div>
+</div>
+<hr></hr>
+<h2>Appendix</h2>
+    <p class="table-caption" id="table1">
+        <strong>Table 1.</strong>Property variable names used with
+        <span class="sympad"><a href="#getProperty">getProperty()</a></span> and
+        <span class="sympad"><a href="#getSystemProperty">getSystemProperty()</a></span>.
+    </p>
+    <table>
+        <tr>
+            <th>
+                Property Group
+            </th>
+            <th>
+                Property
+            </th>
+            <th>
+                Description
+            </th>
+            <th>
+                Notes
+            </th>
+        </tr>
+        <tr>
+            <td rowspan="17"><code>build</code></td>
+            <td><code>board</code></td>
+            <td>Code name for the device's system board</td>
+            <td rowspan="17">
+                See {@link android.os.Build}
+            </td>
+        </tr>
+        <tr>
+            <td><code>brand</code></td>
+            <td>The carrier or provider for which the OS is customized.</td>
+        </tr>
+            <tr>
+            <td><code>device</code></td>
+            <td>The device design name.</td>
+        </tr>
+            <tr>
+            <td><code>fingerprint</code></td>
+            <td>A unique identifier for the currently-running build.</td>
+        </tr>
+            <tr>
+            <td><code>host</code></td>
+            <td></td>
+        </tr>
+            <tr>
+            <td><code>ID</code></td>
+            <td>A changelist number or label.</td>
+        </tr>
+            <tr>
+            <td><code>model</code></td>
+            <td>The end-user-visible name for the device.</td>
+        </tr>
+            <tr>
+            <td><code>product</code></td>
+            <td>The overall product name.</td>
+        </tr>
+            <tr>
+            <td><code>tags</code></td>
+            <td>Comma-separated tags that describe the build, such as "unsigned" and "debug".</td>
+        </tr>
+            <tr>
+            <td><code>type</code></td>
+            <td>The build type, such as "user" or "eng".</td>
+        </tr>
+        <tr>
+            <td><code>user</code></td>
+            <td></td>
+        </tr>
+        <tr>
+            <td><code>CPU_ABI</code></td>
+            <td>
+                The name of the native code instruction set, in the form CPU type plus
+                ABI convention.
+            </td>
+        </tr>
+        <tr>
+            <td><code>manufacturer</code></td>
+            <td>The product/hardware manufacturer.</td>
+        </tr>
+        <tr>
+            <td><code>version.incremental</code></td>
+            <td>
+                The internal code used by the source control system to represent this version
+                of the software.
+            </td>
+        </tr>
+        <tr>
+            <td><code>version.release</code></td>
+            <td>The user-visible name of this version of the software.</td>
+        </tr>
+        <tr>
+            <td><code>version.sdk</code></td>
+            <td>The user-visible SDK version associated with this version of the OS.</td>
+        </tr>
+        <tr>
+            <td><code>version.codename</code></td>
+            <td>
+                The current development codename, or "REL" if this version of the software has been
+                released.
+            </td>
+        </tr>
+        <tr>
+            <td rowspan="3"><code>display</code></td>
+            <td><code>width</code></td>
+            <td>The device's display width in pixels.</td>
+            <td rowspan="3">
+                See
+                {@link android.util.DisplayMetrics} for details.
+            </td>
+        </tr>
+        <tr>
+            <td><code>height</code></td>
+            <td>The device's display height in pixels.</td>
+        </tr>
+        <tr>
+            <td><code>density</code></td>
+            <td>
+                The logical density of the display. This is a factor that scales
+                DIP (Density-Independent Pixel) units to the device's resolution. DIP is adjusted so
+                that 1 DIP is equivalent to one pixel on a 160 pixel-per-inch display. For example,
+                on a 160-dpi screen, density = 1.0, while on a 120-dpi screen, density = .75.
+                <p>
+                    The value does not exactly follow the real screen size, but is adjusted to
+                    conform to large changes in the display DPI. See
+                    {@link android.util.DisplayMetrics#density} for more details.
+                </p>
+            </td>
+        </tr>
+        <tr>
+            <td rowspan="6"><code>am.current</code></td>
+            <td><code>package</code></td>
+            <td>The Android package name of the currently running package.</td>
+            <td rowspan="6">
+                The <code>am.current</code> keys return information about the currently-running
+                Activity.
+            </td>
+        </tr>
+        <tr>
+            <td><code>action</code></td>
+            <td>
+                The current activity's action. This has the same format as the <code>name</code>
+                attribute of the <code>action</code> element in a package manifest.
+            </td>
+        </tr>
+        <tr>
+            <td><code>comp.class</code></td>
+            <td>
+                The class name of the component that started the current Activity. See
+                <code><a href="#comppackage">comp.package</a></code> for more details.</td>
+        </tr>
+        <tr>
+            <td><a name="comppackage"><code>comp.package</code></a></td>
+            <td>
+                The package name of the component that started the current Activity. A component
+                is specified by a package name and the name of class that the package contains.
+            </td>
+        </tr>
+        <tr>
+            <td><code>data</code></td>
+            <td>The data (if any) contained in the Intent that started the current Activity.</td>
+        </tr>
+        <tr>
+            <td><code>categories</code></td>
+            <td>The categories specified by the Intent that started the current Activity.</td>
+        </tr>
+        <tr>
+            <td rowspan="3"><code>clock</code></td>
+            <td><code>realtime</code></td>
+            <td>
+                The number of milliseconds since the device rebooted, including deep-sleep
+                time.
+            </td>
+            <td rowspan="3">
+                See {@link android.os.SystemClock} for more information.
+            </td>
+        </tr>
+        <tr>
+            <td><code>uptime</code></td>
+            <td>
+                The number of milliseconds since the device rebooted, <em>not</em> including
+                deep-sleep time
+            </td>
+        </tr>
+        <tr>
+            <td><code>millis</code></td>
+            <td>current time since the UNIX epoch, in milliseconds.</td>
+        </tr>
+    </table>
diff --git a/docs/html/guide/developing/tools/MonkeyImage.jd b/docs/html/guide/developing/tools/MonkeyImage.jd
new file mode 100644
index 0000000..ae85cb5
--- /dev/null
+++ b/docs/html/guide/developing/tools/MonkeyImage.jd
@@ -0,0 +1,435 @@
+page.title=MonkeyImage
+@jd:body
+<style>
+    h4.jd-details-title {background-color: #DEE8F1;}
+</style>
+
+<p>
+    A monkeyrunner class to hold an image of the device or emulator's screen. The image is
+    copied from the screen buffer during a screenshot. This object's methods allow you to
+    convert the image into various storage formats, write the image to a file, copy parts of
+    the image, and compare this object to other <code>MonkeyImage</code> objects.
+</p>
+<p>
+    You do not need to create new instances of <code>MonkeyImage</code>. Instead, use
+<code><a href="{@docRoot}guide/developing/tools/MonkeyDevice.html#takeSnapshot">
+MonkeyDevice.takeSnapshot()</a></code> to create a new instance from a screenshot. For example, use:
+</p>
+<pre>
+newimage = MonkeyDevice.takeSnapshot()
+</pre>
+<h2>Summary</h2>
+<table id="pubmethods" class="jd-sumtable">
+    <tr>
+        <th colspan="12" style="background-color: #E2E2E2">Methods</th>
+    </tr>
+    <tr class="api" >
+        <td class="jd-typecol">
+            <nobr>
+                <em>string</em>
+            </nobr>
+        </td>
+        <td class="jd-linkcol" width="100%">
+            <nobr>
+                <span class="sympad">
+                    <a href="#convertToBytes">convertToBytes</a>
+                </span>
+                (<em>string</em> format)
+            </nobr>
+            <div class="jd-descrdiv">
+                Converts the current image to a particular format and returns it as a
+                <em>string</em> that you can then access as an <em>iterable</em> of binary bytes.
+            </div>
+        </td>
+    </tr>
+    <tr class="api" >
+        <td class="jd-typecol">
+            <nobr>
+                <em>tuple</em>
+            </nobr>
+        </td>
+        <td class="jd-linkcol" width="100%">
+            <nobr>
+                <span class="sympad">
+                    <a href="#getRawPixel">getRawPixel</a>
+                </span>
+                (<em>integer</em> x,
+                <em>integer</em> y)
+            </nobr>
+            <div class="jd-descrdiv">
+                Returns the single pixel at the image location (x,y), as an
+                a <em>tuple</em> of <em>integer</em>, in the form (a,r,g,b).
+            </div>
+        </td>
+    </tr>
+    <tr class="api" >
+        <td class="jd-typecol">
+            <nobr>
+                <em>integer</em>
+            </nobr>
+        </td>
+        <td class="jd-linkcol" width="100%">
+            <nobr>
+                <span class="sympad">
+                    <a href="#getRawPixelInt">getRawPixelInt</a>
+                </span>
+                (<em>integer</em> x,
+                 <em>integer</em> y)
+            </nobr>
+            <div class="jd-descrdiv">
+                Returns the single pixel at the image location (x,y), as
+                a 32-bit <em>integer</em>.
+            </div>
+        </td>
+    </tr>
+    <tr class="api" >
+        <td class="jd-typecol">
+            <nobr>
+                <code>
+                    <a href="{@docRoot}guide/developing/tools/MonkeyImage.html">MonkeyImage</a>
+                </code>
+            </nobr>
+        </td>
+        <td class="jd-linkcol" width="100%">
+            <nobr>
+                <span class="sympad">
+                    <a href="#getSubImage">getSubImage</a>
+                </span>
+                (<em>tuple</em> rect)
+            </nobr>
+            <div class="jd-descrdiv">
+                Creates a new <code>MonkeyImage</code> object from a rectangular selection of the
+                current image.
+            </div>
+        </td>
+    </tr>
+    <tr class="api" >
+        <td class="jd-typecol">
+            <nobr>
+                <em>boolean</em>
+            </nobr>
+        </td>
+        <td class="jd-linkcol" width="100%">
+            <nobr>
+                <span class="sympad">
+                    <a href="#sameAs">sameAs</a>
+                </span>
+         (<code><a href="{@docRoot}guide/developing/tools/MonkeyImage.html">MonkeyImage</a></code>
+            other,
+            <em>float</em> percent)
+            </nobr>
+            <div class="jd-descrdiv">
+                Compares this <code>MonkeyImage</code> object to another and returns the result of
+                the comparison. The <code>percent</code> argument specifies the percentage
+                difference that is allowed for the two images to be "equal".
+            </div>
+        </td>
+    </tr>
+    <tr class="api" >
+        <td class="jd-typecol">
+            <nobr>
+                <em>void</em>
+            </nobr>
+        </td>
+        <td class="jd-linkcol" width="100%">
+            <nobr>
+                <span class="sympad">
+                    <a href="#writeToFile">writeToFile</a>
+                </span>
+                (<em>string</em> path,
+                <em>string</em> format)
+            </nobr>
+            <div class="jd-descrdiv">
+                Writes the current image to the file specified by <code>filename</code>, in the
+                format specified by <code>format</code>.
+            </div>
+        </td>
+    </tr>
+</table>
+<!-- ========= METHOD DETAIL ======== -->
+<!-- Public methods -->
+<h2>Public Methods</h2>
+<A NAME="convertToBytes"></A>
+<div class="jd-details api ">
+    <h4 class="jd-details-title">
+      <span class="normal">
+        <em>string</em>
+      </span>
+      <span class="sympad">convertToBytes</span>
+      <span class="normal">
+      (
+            <em>string</em> format)
+      </span>
+    </h4>
+  <div class="jd-details-descr">
+
+    <div class="jd-tagdata jd-tagdescr">
+        <p>
+            Converts the current image to a particular format and returns it as a <em>string</em>
+            that you can then access as an <em>iterable</em> of binary bytes.
+        </p>
+    </div>
+    <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Arguments</h5>
+      <table class="jd-tagtable">
+        <tr>
+          <th>format</th>
+            <td>
+                The desired output format. All of the common raster output formats are supported.
+                The default value is "png" (Portable Network Graphics).
+            </td>
+        </tr>
+        </table>
+    </div>
+</div>
+</div>
+<A NAME="getRawPixel"></A>
+<div class="jd-details api ">
+    <h4 class="jd-details-title">
+      <span class="normal">
+        <em>tuple</em>
+      </span>
+      <span class="sympad">getRawPixel</span>
+      <span class="normal">
+        (<em>integer</em> x,
+         <em>integer</em> y)
+      </span>
+    </h4>
+  <div class="jd-details-descr">
+
+    <div class="jd-tagdata jd-tagdescr">
+        <p>
+            Returns the single pixel at the image location (x,y), as an
+            a <em>tuple</em> of <em>integer</em>, in the form (a,r,g,b).
+        </p>
+    </div>
+    <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Arguments</h5>
+      <table class="jd-tagtable">
+        <tr>
+          <th>x</th>
+          <td>
+            The horizontal position of the pixel, starting with 0 at the left of the screen in the
+            orientation it had when the screenshot was taken.
+          </td>
+        </tr>
+        <tr>
+          <th>y</th>
+          <td>
+            The vertical position of the pixel, starting with 0 at the top of the screen in the
+            orientation it had when the screenshot was taken.
+          </td>
+        </tr>
+      </table>
+    </div>
+    <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Returns</h5>
+      <ul class="nolist">
+        <li>
+            A tuple of integers representing the pixel, in the form (a,r,g,b) where
+            a is the alpha channel value, and r, g, and b are the red, green, and blue values,
+            respectively.
+        </li>
+      </ul>
+    </div>
+  </div>
+</div>
+<A NAME="getRawPixelInt"></A>
+<div class="jd-details api ">
+    <h4 class="jd-details-title">
+      <span class="normal">
+        <em>tuple</em>
+      </span>
+      <span class="sympad">getRawPixelInt</span>
+      <span class="normal">
+        (<em>integer</em> x,
+         <em>integer</em> y)
+      </span>
+    </h4>
+  <div class="jd-details-descr">
+
+    <div class="jd-tagdata jd-tagdescr">
+        <p>
+            Returns the single pixel at the image location (x,y), as an
+            an <em>integer</em>. Use this method to economize on memory.
+        </p>
+    </div>
+    <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Arguments</h5>
+      <table class="jd-tagtable">
+        <tr>
+          <th>x</th>
+          <td>
+            The horizontal position of the pixel, starting with 0 at the left of the screen in the
+            orientation it had when the screenshot was taken.
+          </td>
+        </tr>
+        <tr>
+          <th>y</th>
+          <td>
+            The vertical position of the pixel, starting with 0 at the top of the screen in the
+            orientation it had when the screenshot was taken.
+          </td>
+        </tr>
+      </table>
+    </div>
+    <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Returns</h5>
+      <ul class="nolist">
+        <li>
+            The a,r,g, and b values of the pixel as 8-bit values combined into a 32-bit
+            integer, with a as the leftmost 8 bits, r the next rightmost, and so forth.
+        </li>
+      </ul>
+    </div>
+  </div>
+</div>
+<A NAME="getSubImage"></A>
+<div class="jd-details api ">
+    <h4 class="jd-details-title">
+      <span class="normal">
+          <code>
+              <a href="{@docRoot}guide/developing/tools/MonkeyImage.html">MonkeyImage</a>
+          </code>
+      </span>
+      <span class="sympad">getSubImage</span>
+      <span class="normal">
+        (<em>tuple</em> rect)
+      </span>
+    </h4>
+  <div class="jd-details-descr">
+
+    <div class="jd-tagdata jd-tagdescr">
+        <p>
+           Creates a new <code>MonkeyImage</code> object from a rectangular selection of the
+           current image.
+        </p>
+    </div>
+    <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Arguments</h5>
+      <table class="jd-tagtable">
+        <tr>
+          <th>rect</th>
+          <td>
+            A tuple (x, y, w, h) specifying the selection. x and y specify the 0-based pixel
+            position of the upper left-hand corner of the selection. w specifies the width of the
+            region, and h specifies its height, both in units of pixels.
+            <p>
+                The image's orientation is the same as the screen orientation at the time the
+                screenshot was made.
+            </p>
+          </td>
+        </tr>
+      </table>
+    </div>
+    <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Returns</h5>
+      <ul class="nolist">
+        <li>
+            A new <code>MonkeyImage</code> object containing the selection.
+        </li>
+      </ul>
+    </div>
+  </div>
+</div>
+<A NAME="sameAs"></A>
+<div class="jd-details api ">
+    <h4 class="jd-details-title">
+      <span class="normal">
+        <em>boolean</em>
+      </span>
+      <span class="sympad">sameAs</span>
+      <span class="normal">
+      (
+       <code>
+           <a href="{@docRoot}guide/developing/tools/MonkeyImage.html">MonkeyImage</a>
+       </code> otherImage,
+       <em>float</em> percent
+      )
+      </span>
+    </h4>
+  <div class="jd-details-descr">
+
+    <div class="jd-tagdata jd-tagdescr">
+        <p>
+           Compares this <code>MonkeyImage</code> object to another and returns the result of
+           the comparison. The <code>percent</code> argument specifies the percentage
+           difference that is allowed for the two images to be "equal".
+        </p>
+    </div>
+    <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Arguments</h5>
+      <table class="jd-tagtable">
+        <tr>
+          <th>other</th>
+          <td>
+            Another <code>MonkeyImage</code> object to compare to this one.
+          </td>
+        </tr>
+        <tr>
+          <th>
+            percent
+          </th>
+          <td>
+            A float in the range 0.0 to 1.0, inclusive, indicating
+            the percentage of pixels that need to be the same for the method to return
+            <code>true</code>. The default is 1.0, indicating that all the pixels
+            must match.
+          </td>
+        </tr>
+      </table>
+    </div>
+    <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Returns</h5>
+      <ul class="nolist">
+        <li>
+            Boolean <code>true</code> if the images match, or boolean <code>false</code> otherwise.
+        </li>
+      </ul>
+    </div>
+  </div>
+</div>
+<A NAME="writeToFile"></A>
+<div class="jd-details api ">
+    <h4 class="jd-details-title">
+      <span class="normal">
+        void
+      </span>
+      <span class="sympad">writeToFile</span>
+      <span class="normal">
+      (<em>string</em> filename,
+       <em>string</em> format)
+      </span>
+    </h4>
+  <div class="jd-details-descr">
+
+    <div class="jd-tagdata jd-tagdescr">
+        <p>
+           Writes the current image to the file specified by <code>filename</code>, in the
+           format specified by <code>format</code>.
+        </p>
+    </div>
+    <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Arguments</h5>
+      <table class="jd-tagtable">
+        <tr>
+          <th>path</th>
+          <td>
+            The fully-qualified filename and extension of the output file.
+          </td>
+        </tr>
+        <tr>
+            <th>
+                format
+            </th>
+            <td>
+                The output format to use for the file. If no format is provided, then the
+                method tries to guess the format from the filename's extension. If no
+                extension is provided and no format is specified, then the default format of
+                "png" (Portable Network Graphics) is used.
+            </td>
+        </tr>
+      </table>
+    </div>
+  </div>
+</div>
diff --git a/docs/html/guide/developing/tools/MonkeyRunner.jd b/docs/html/guide/developing/tools/MonkeyRunner.jd
new file mode 100644
index 0000000..871e06d
--- /dev/null
+++ b/docs/html/guide/developing/tools/MonkeyRunner.jd
@@ -0,0 +1,445 @@
+page.title=MonkeyRunner
+@jd:body
+<style>
+    h4.jd-details-title {background-color: #DEE8F1;}
+</style>
+<p>
+    A monkeyrunner class that contains static utility methods.
+</p>
+<h2>Summary</h2>
+<table id="pubmethods" class="jd-sumtable">
+    <tr>
+        <th colspan="12" style="background-color: #E2E2E2">Methods</th>
+    </tr>
+    <tr class="api" >
+        <td class="jd-typecol">
+            <nobr>
+                void
+            </nobr>
+        </td>
+        <td class="jd-linkcol" width="100%">
+            <nobr>
+                <span class="sympad">
+                    <a href="#alert">alert</a>
+                </span>
+                (<em>string</em> message,
+                 <em>string</em> title,
+                 <em>string</em> okTitle)
+            </nobr>
+            <div class="jd-descrdiv">
+                Displays an alert dialog to the process running the current
+                program.
+            </div>
+        </td>
+    </tr>
+    <tr class="api" >
+        <td class="jd-typecol">
+            <nobr>
+                <em>integer</em>
+            </nobr>
+        </td>
+        <td class="jd-linkcol" width="100%">
+            <nobr>
+                <span class="sympad">
+                    <a href="#choice">choice</a>
+                </span>
+                (<em>string</em> message,
+                 <em>iterable</em> choices,
+                 <em>string</em> title)
+            </nobr>
+            <div class="jd-descrdiv">
+                Displays a dialog with a list of choices to the process running the current program.
+            </div>
+        </td>
+    </tr>
+    <tr class="api" >
+        <td class="jd-typecol">
+            <nobr>
+                void
+            </nobr>
+        </td>
+        <td class="jd-linkcol" width="100%">
+            <nobr>
+                <span class="sympad">
+                    <a href="#help">help</a>
+                </span>
+                (<em>string</em> format)
+            </nobr>
+            <div class="jd-descrdiv">
+                Displays the monkeyrunner API reference in a style similar to that of Python's
+                <code>pydoc</code> tool, using the specified format.
+            </div>
+        </td>
+    </tr>
+    <tr class="api" >
+        <td class="jd-typecol">
+            <nobr>
+                <em>string</em>
+            </nobr>
+        </td>
+        <td class="jd-linkcol" width="100%">
+            <nobr>
+                <span class="sympad">
+                    <a href="#input">input</a>
+                </span>
+                (<em>string</em> message,
+                 <em>string</em> initialValue,
+                 <em>string</em> title,
+                 <em>string</em> okTitle,
+                 <em>string</em> cancelTitle)
+            </nobr>
+            <div class="jd-descrdiv">
+                Displays a dialog that accepts input.
+            </div>
+        </td>
+    </tr>
+    <tr class="api" >
+        <td class="jd-typecol">
+            <nobr>
+                void
+            </nobr>
+        </td>
+        <td class="jd-linkcol" width="100%">
+            <nobr>
+                <span class="sympad">
+                    <a href="#sleep">sleep</a>
+                </span>
+                (<em>float</em> seconds)
+            </nobr>
+            <div class="jd-descrdiv">
+                Pauses the current program for the specified number of seconds.
+            </div>
+        </td>
+    </tr>
+    <tr class="api" >
+        <td class="jd-typecol">
+            <nobr>
+                <code>
+                    <a href="{@docRoot}guide/developing/tools/MonkeyDevice.html">MonkeyDevice</a>
+                </code>
+            </nobr>
+        </td>
+        <td class="jd-linkcol" width="100%">
+            <nobr>
+                <span class="sympad">
+                    <a href="#waitForConnection">waitForConnection</a>
+                </span>
+                (<em>float</em> timeout,
+                <em>string</em> deviceId)
+            </nobr>
+            <div class="jd-descrdiv">
+                Tries to make a connection between the <code>monkeyrunner</code> backend and the
+                specified device or emulator.
+            </div>
+        </td>
+    </tr>
+</table>
+<!-- ========= METHOD DETAIL ======== -->
+<!-- Public methods -->
+<h2>Public Methods</h2>
+<A NAME="alert"></A>
+<div class="jd-details api ">
+    <h4 class="jd-details-title">
+      <span class="normal">
+        <em>string</em>
+      </span>
+      <span class="sympad">alert</span>
+      <span class="normal">
+      (
+            <em>string</em> message,
+            <em>string</em> title,
+            <em>string</em> okTitle)
+      </span>
+    </h4>
+  <div class="jd-details-descr">
+
+    <div class="jd-tagdata jd-tagdescr">
+        <p>
+            Displays an alert dialog to the process running the current
+            program. The dialog is modal, so the program pauses until the user clicks the dialog's
+            button.
+        </p>
+    </div>
+    <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Arguments</h5>
+      <table class="jd-tagtable">
+        <tr>
+          <th>message</th>
+            <td>
+                The message to display in the dialog.
+            </td>
+        </tr>
+        <tr>
+            <th>title</th>
+            <td>
+                The dialog's title. The default value is "Alert".
+            </td>
+        </tr>
+        <tr>
+            <th>okTitle</th>
+            <td>
+                The text displayed in the dialog button. The default value is "OK".
+            </td>
+        </tr>
+        </table>
+    </div>
+</div>
+</div>
+<A NAME="choice"></A>
+<div class="jd-details api ">
+    <h4 class="jd-details-title">
+      <span class="normal">
+        <em>integer</em>
+      </span>
+      <span class="sympad">choice</span>
+      <span class="normal">
+        (<em>string</em> message,
+         <em>iterable</em> choices,
+         <em>string</em> title)
+      </span>
+    </h4>
+  <div class="jd-details-descr">
+
+    <div class="jd-tagdata jd-tagdescr">
+        <p>
+            Displays a dialog with a list of choices to the process running the current program. The
+            dialog is modal, so the program pauses until the user clicks one of the dialog's
+            buttons.
+        </p>
+    </div>
+    <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Arguments</h5>
+      <table class="jd-tagtable">
+        <tr>
+          <th>message</th>
+          <td>
+            The prompt message displayed in the dialog.
+          </td>
+        </tr>
+        <tr>
+          <th>choices</th>
+          <td>
+            A Python iterable containing one or more objects that are displayed as strings. The
+            recommended form is an array of strings.
+          </td>
+        </tr>
+        <tr>
+            <th>
+                title
+            </th>
+            <td>
+               The dialog's title. The default is "Input".
+            </td>
+        </tr>
+      </table>
+    </div>
+    <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Returns</h5>
+      <ul class="nolist">
+        <li>
+            If the user makes a selection and clicks the "OK" button, the method returns
+            the 0-based index of the selection within the iterable.
+            If the user clicks the "Cancel" button, the method returns -1.
+        </li>
+      </ul>
+    </div>
+  </div>
+</div>
+<A NAME="help"></A>
+<div class="jd-details api ">
+    <h4 class="jd-details-title">
+      <span class="normal">
+        void
+      </span>
+      <span class="sympad">help</span>
+      <span class="normal">
+        (<em>string</em> format)
+      </span>
+    </h4>
+  <div class="jd-details-descr">
+
+    <div class="jd-tagdata jd-tagdescr">
+        <p>
+            Displays the monkeyrunner API reference in a style similar to that of Python's
+            <code>pydoc</code> tool, using the specified format.
+        </p>
+    </div>
+    <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Arguments</h5>
+      <table class="jd-tagtable">
+        <tr>
+          <th>format</th>
+          <td>
+            The markup format to use in the output. The possible values are "text" for plain text
+            or "html" for HTML.
+          </td>
+        </tr>
+      </table>
+    </div>
+  </div>
+</div>
+<A NAME="input"></A>
+<div class="jd-details api ">
+    <h4 class="jd-details-title">
+      <span class="normal">
+        <em>string</em>
+      </span>
+      <span class="sympad">input</span>
+      <span class="normal">
+        (<em>string</em> message
+         <em>string</em> initialValue,
+         <em>string</em> title,
+         <em>string</em> okTitle,
+         <em>string</em> cancelTitle)
+      </span>
+    </h4>
+  <div class="jd-details-descr">
+
+    <div class="jd-tagdata jd-tagdescr">
+        <p>
+            Displays a dialog that accepts input and returns it to the program. The dialog is
+            modal, so the program pauses until the user clicks one of the dialog's buttons.
+        </p>
+        <p>
+            The dialog contains two buttons, one of which displays the okTitle value
+            and the other the cancelTitle value. If the user clicks the okTitle button,
+            the current value of the input box is returned. If the user clicks the cancelTitle
+            button, an empty string is returned.
+        </p>
+    </div>
+    <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Arguments</h5>
+      <table class="jd-tagtable">
+        <tr>
+          <th>message</th>
+          <td>
+            The prompt message displayed in the dialog.
+          </td>
+        </tr>
+        <tr>
+          <th>initialValue</th>
+          <td>
+            The initial value to display in the dialog. The default is an empty string.
+          </td>
+        </tr>
+        <tr>
+          <th>title</th>
+          <td>
+            The dialog's title. The default is "Input".
+          </td>
+        </tr>
+        <tr>
+          <th>okTitle</th>
+          <td>
+            The text displayed in the okTitle button. The default is "OK".
+          </td>
+        </tr>
+        <tr>
+          <th>cancelTitle</th>
+          <td>
+            The text displayed in the cancelTitle button. The default is "Cancel".
+          </td>
+        </tr>
+      </table>
+    </div>
+    <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Returns</h5>
+      <ul class="nolist">
+        <li>
+            If the user clicks the okTitle button, then the method returns the current value of
+            the dialog's input box. If the user clicks the cancelTitle button, the method returns
+            an empty string.
+        </li>
+      </ul>
+    </div>
+  </div>
+</div>
+<A NAME="sleep"></A>
+<div class="jd-details api ">
+    <h4 class="jd-details-title">
+      <span class="normal">
+        void
+      </span>
+      <span class="sympad">sleep</span>
+      <span class="normal">
+      (
+       <em>float</em> seconds
+      )
+      </span>
+    </h4>
+  <div class="jd-details-descr">
+
+    <div class="jd-tagdata jd-tagdescr">
+        <p>
+            Pauses the current program for the specified number of seconds.
+        </p>
+    </div>
+    <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Arguments</h5>
+      <table class="jd-tagtable">
+        <tr>
+          <th>seconds</th>
+          <td>
+            The number of seconds to pause.
+          </td>
+        </tr>
+      </table>
+    </div>
+  </div>
+</div>
+<A NAME="waitForConnection"></A>
+<div class="jd-details api ">
+    <h4 class="jd-details-title">
+      <span class="normal">
+          <code>
+              <a href="{@docRoot}guide/developing/tools/MonkeyDevice.html">MonkeyDevice</a>
+          </code>
+      </span>
+      <span class="sympad">waitForConnection</span>
+      <span class="normal">
+      (<em>float</em> timeout,
+       <em>string</em> deviceId)
+      </span>
+    </h4>
+  <div class="jd-details-descr">
+
+    <div class="jd-tagdata jd-tagdescr">
+        <p>
+            Tries to make a connection between the <code>monkeyrunner</code> backend and the
+            specified device or emulator.
+        </p>
+    </div>
+    <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Arguments</h5>
+      <table class="jd-tagtable">
+        <tr>
+          <th>timeout</th>
+          <td>
+            The number of seconds to wait for a connection. The default is to wait forever.
+          </td>
+        </tr>
+        <tr>
+            <th>
+                deviceId
+            </th>
+            <td>
+                A regular expression that specifies the serial number of the device or emulator. See
+                the topic
+                <a href="{@docRoot}guide/developing/tools/adb.html">Android Debug Bridge</a>
+                for a description of device and emulator serial numbers.
+            </td>
+        </tr>
+      </table>
+    </div>
+        <div class="jd-tagdata">
+      <h5 class="jd-tagtitle">Returns</h5>
+      <ul class="nolist">
+        <li>
+          A <code><a href="{@docRoot}guide/developing/tools/MonkeyDevice.html">MonkeyDevice</a></code>
+          instance for the device or emulator. Use this object to control and communicate with the
+          device or emulator.
+        </li>
+      </ul>
+    </div>
+  </div>
+</div>
diff --git a/docs/html/guide/developing/tools/index.jd b/docs/html/guide/developing/tools/index.jd
index 6e9fde1..0e10377 100644
--- a/docs/html/guide/developing/tools/index.jd
+++ b/docs/html/guide/developing/tools/index.jd
@@ -3,27 +3,27 @@
 
 <img src="{@docRoot}assets/images/android_wrench.png" alt="" align="right">
 
-<p>The Android SDK includes a variety of custom tools that help you develop mobile 
-applications on the Android platform. The most important of these are the Android 
-Emulator and the Android Development Tools plugin for Eclipse, but the SDK also 
-includes a variety of other tools for debugging, packaging, and installing your 
+<p>The Android SDK includes a variety of custom tools that help you develop mobile
+applications on the Android platform. The most important of these are the Android
+Emulator and the Android Development Tools plugin for Eclipse, but the SDK also
+includes a variety of other tools for debugging, packaging, and installing your
 applications on the emulator. </p>
-    
+
  <dl>
   <dt><a href="adt.html">Android Development Tools Plugin</a> (for the Eclipse IDE)</dt>
-          <dd>The ADT plugin adds powerful extensions to the Eclipse integrated environment, 
-          making creating and debugging your Android applications easier and faster. If you 
-          use Eclipse, the ADT plugin gives you an incredible boost in developing Android 
+          <dd>The ADT plugin adds powerful extensions to the Eclipse integrated environment,
+          making creating and debugging your Android applications easier and faster. If you
+          use Eclipse, the ADT plugin gives you an incredible boost in developing Android
           applications.</dd>
   <dt><a href="emulator.html">Android Emulator</a></dt>
-    <dd>A QEMU-based device-emulation tool that you can use to design, 
+    <dd>A QEMU-based device-emulation tool that you can use to design,
     debug, and test your applications in an actual Android run-time environment. </dd>
 
   <dt><a href="avd.html">Android Virtual Devices (AVDs)</a></dt>
     <dd>Virtual device configurations that you create, to model device
         characteristics in the Android Emulator. In each configuration, you can
         specify the Android platform to run, the hardware options, and the
-        emulator skin to use. Each AVD functions as an independent device with 
+        emulator skin to use. Each AVD functions as an independent device with
         it's own storage for user data, SD card, and so on. </dd>
 
  <dt><a href="hierarchy-viewer.html">Hierarchy Viewer</a></dt>
@@ -37,53 +37,53 @@
 efficiency.
     </dd>
 
-	  <dt><a href="draw9patch.html">Draw 9-patch</a></dt>
-	    <dd>The Draw 9-patch tool allows you to easily create a 
-	    {@link android.graphics.NinePatch} graphic using a WYSIWYG editor. It also previews stretched 
-	     versions of the image, and highlights the area in which content is allowed.
-	    </dd>
+      <dt><a href="draw9patch.html">Draw 9-patch</a></dt>
+        <dd>The Draw 9-patch tool allows you to easily create a
+        {@link android.graphics.NinePatch} graphic using a WYSIWYG editor. It also previews stretched
+         versions of the image, and highlights the area in which content is allowed.
+        </dd>
 
-  <dt><a href="ddms.html" >Dalvik Debug Monitor 
+  <dt><a href="ddms.html" >Dalvik Debug Monitor
       Service</a> (ddms)</dt>
-	    <dd>Integrated with Dalvik, the Android platform's custom VM, this tool 
-	    lets you manage processes on an emulator or device and assists in debugging. 
-	    You can use it to kill processes, select a specific process to debug, 
-	    generate trace data, view heap and thread information, take screenshots 
-	    of the emulator or device, and more. </dd>
-			
+        <dd>Integrated with Dalvik, the Android platform's custom VM, this tool
+        lets you manage processes on an emulator or device and assists in debugging.
+        You can use it to kill processes, select a specific process to debug,
+        generate trace data, view heap and thread information, take screenshots
+        of the emulator or device, and more. </dd>
+
   <dt><a href="adb.html" >Android Debug Bridge</a> (adb)</dt>
-                  <dd>The adb tool lets you install your application's .apk files on an 
-                  emulator or device and access the emulator or device from a command line. 
-                  You can also use it to link a standard debugger to application code running 
+                  <dd>The adb tool lets you install your application's .apk files on an
+                  emulator or device and access the emulator or device from a command line.
+                  You can also use it to link a standard debugger to application code running
                   on an Android emulator or device.</dd>
 
-  <dt><a href="aapt.html">Android Asset 
+  <dt><a href="aapt.html">Android Asset
           Packaging Tool</a> (aapt)</dt>
-                  <dd>The aapt tool lets you create .apk files containing the binaries and 
+                  <dd>The aapt tool lets you create .apk files containing the binaries and
                   resources of Android applications.</dd>
 
-  <dt><a href="aidl.html" >Android Interface 
+  <dt><a href="aidl.html" >Android Interface
   Description Language</a> (aidl)</dt>
             <dd>Lets you generate code for an interprocess interface, such as what
             a service might use.</dd>
 
   <dt><a href="adb.html#sqlite">sqlite3</a></dt>
-      <dd>Included as a convenience, this tool lets you access the SQLite data 
+      <dd>Included as a convenience, this tool lets you access the SQLite data
       files created and used by Android applications.</dd>
 
   <dt><a href="traceview.html" >Traceview</a></dt>
-            <dd> This tool produces graphical analysis views of trace log data that you 
+            <dd> This tool produces graphical analysis views of trace log data that you
             can generate from your Android application. </dd>
 
   <dt><a href="othertools.html#mksdcard">mksdcard</a></dt>
-            <dd>Helps you create a disk image that you can use with the emulator, 
+            <dd>Helps you create a disk image that you can use with the emulator,
                       to simulate the presence of an external storage card (such as an SD card).</dd>
 
   <dt><a href="othertools.html#dx">dx</a></dt>
-                  <dd>The dx tool rewrites .class bytecode into Android bytecode 
+                  <dd>The dx tool rewrites .class bytecode into Android bytecode
                                           (stored in .dex files.)</dd>
 
-  <dt><a href="monkey.html">UI/Application 
+  <dt><a href="monkey.html">UI/Application
   Exerciser Monkey</a></dt>
       <dd>The Monkey is a program that runs on your emulator or device and generates pseudo-random
       streams of user events such as clicks, touches, or gestures, as well as a number of system-
@@ -92,9 +92,9 @@
 
   <dt><a  href="othertools.html#android">android</a></dt>
             <dd>A script that lets you manage AVDs and generate <a
-                        href="http://ant.apache.org/" title="Ant">Ant</a> build files that 
+                        href="http://ant.apache.org/" title="Ant">Ant</a> build files that
                         you can use to compile your Android applications. </dd>
-                        
+
   <dt><a  href="zipalign.html">zipalign</a></dt>
             <dd>An important .apk optimization tool. This tool ensures that all uncompressed data starts
             with a particular alignment relative to the start of the file. This should always be used
diff --git a/docs/html/guide/developing/tools/monkeyrunner_concepts.jd b/docs/html/guide/developing/tools/monkeyrunner_concepts.jd
new file mode 100644
index 0000000..1838905
--- /dev/null
+++ b/docs/html/guide/developing/tools/monkeyrunner_concepts.jd
@@ -0,0 +1,308 @@
+page.title=monkeyrunner
+@jd:body
+
+<div id="qv-wrapper">
+  <div id="qv">
+  <h2>In this document</h2>
+  <ol>
+    <li>
+        <a href="#SampleProgram">A Simple monkeyrunner Program</a>
+    </li>
+    <li>
+        <a href="#APIClasses">The monkeyrunner API</a>
+    </li>
+    <li>
+        <a href="#RunningMonkeyRunner">Running monkeyrunner</a>
+    </li>
+    <li>
+        <a href="#Help">monkeyrunner Built-in Help</a>
+    </li>
+    <li>
+        <a href="#Plugins">Extending monkeyrunner with Plugins</a>
+    </li>
+  </ol>
+  <h2>See Also</h2>
+      <ol>
+        <li>
+            <a href="{@docRoot}guide/topics/testing/testing_android.html">Testing Fundamentals</a>
+        </li>
+      </ol>
+  </div>
+</div>
+<p>
+    The monkeyrunner tool provides an API for writing programs that control an Android device
+    or emulator from outside of Android code. With monkeyrunner, you can write a Python program
+    that installs an Android application or test package, runs it, sends keystrokes to it,
+    takes screenshots of its user interface, and stores screenshots on the workstation. The
+    monkeyrunner tool is primarily designed to test applications and devices at the
+    functional/framework level and for running unit test suites, but you are free to use it for
+    other purposes.
+</p>
+<p>
+    The monkeyrunner tool is not related to the
+    <a href="{@docRoot}guide/developing/tools/monkey.html">UI/Application Exerciser Monkey</a>,
+    also known as the <code>monkey</code> tool. The <code>monkey</code> tool runs in an
+    <code><a href="{@docRoot}guide/developing/tools/adb.html">adb</a></code> shell directly on the
+    device or emulator and generates pseudo-random streams of user and system events. In comparison,
+    the monkeyrunner tool controls devices and emulators from a workstation by sending specific
+    commands and events from an API.
+</p>
+<p>
+    The monkeyrunner tool provides these unique features for Android testing:
+</p>
+<ul>
+    <li>
+        Multiple device control: The monkeyrunner API can apply one or more
+        test suites across multiple devices or emulators. You can physically attach all the devices
+        or start up all the emulators (or both) at once, connect to each one in turn
+        programmatically, and then run one or more tests. You can also start up an emulator
+        configuration programmatically, run one or more tests, and then shut down the emulator.
+    </li>
+    <li>
+        Functional testing: monkeyrunner can run an automated start-to-finish test of an Android
+        application. You provide input values with keystrokes or touch events, and view the results
+        as screenshots.
+    </li>
+    <li>
+        Regression testing - monkeyrunner can test application stability by running an application
+        and comparing its output screenshots to a set of screenshots that are known to be correct.
+    </li>
+    <li>
+        Extensible automation - Since monkeyrunner is an API toolkit, you can develop an entire
+        system of Python-based modules and programs for controlling Android devices. Besides using
+        the monkeyrunner API itself, you can use the standard Python
+        <code><a href="http://docs.python.org/library/os.html">os</a></code> and
+        <code><a href="http://docs.python.org/library/subprocess.html">subprocess</a></code>
+        modules to call Android tools such as
+        <a href="{@docRoot}guide/developing/tools/adb.html">Android Debug Bridge</a>.
+        <p>
+            You can also add your own classes to the monkeyrunner API. This is described
+            in more detail in the section
+            <a href="#Plugins">Extending monkeyrunner with plugins</a>.
+        </p>
+    </li>
+</ul>
+<p>
+    The monkeyrunner tool uses <a href="http://www.jython.org/">Jython</a>, a
+    implementation of Python that uses the Java programming language. Jython allows the
+    monkeyrunner API to interact easily with the Android framework. With Jython you can
+    use Python syntax to access the constants, classes, and methods of the API.
+</p>
+
+<h2 id="SampleProgram">A Simple monkeyrunner Program</h2>
+<p>
+    Here is a simple monkeyrunner program that connects to a device, creating a
+    <code><a href="{@docRoot}guide/developing/tools/MonkeyDevice.html">MonkeyDevice</a></code>
+    object. Using the <code>MonkeyDevice</code> object, the program installs an Android application
+    package, runs one of its activities, and sends key events to the activity.
+    The program then takes a screenshot of the result, creating a
+    <code><a href="{@docRoot}guide/developing/tools/MonkeyImage.html">MonkeyImage</a></code> object.
+    From this object, the program writes out a <code>.png</code> file containing the screenshot.
+</p>
+<pre>
+# Imports the monkeyrunner modules used by this program
+from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice
+
+# Connects to the current device, returning a MonkeyDevice object
+device = MonkeyRunner.waitForConnection()
+
+# Installs the Android package. Notice that this method returns a boolean, so you can test
+# to see if the installation worked.
+device.installPackage('myproject/bin/MyApplication.apk')
+
+# Runs an activity in the application
+device.startActivity(component='com.example.android.myapplication.MainActivity')
+
+# Presses the Menu button
+device.press('KEYCODE_MENU','DOWN_AND_UP')
+
+# Takes a screenshot
+result = device.takeSnapShot
+
+# Writes the screenshot to a file
+result.writeToFile('myproject/shot1.png','png')
+</pre>
+
+<h2 id="APIClasses">The monkeyrunner API</h2>
+<p>
+    The monkeyrunner API is contained in three modules in the package
+    <code>com.android.monkeyrunner</code>:
+</p>
+<ul>
+    <li>
+        <code><a href="{@docRoot}guide/developing/tools/MonkeyRunner.html">MonkeyRunner</a></code>:
+        A class of utility methods for monkeyrunner programs. This class provides a method for
+        connecting monkeyrunner to a device or emulator. It also provides methods for
+        creating UIs for a monkeyrunner program and for displaying the built-in help.
+    </li>
+    <li>
+        <code><a href="{@docRoot}guide/developing/tools/MonkeyDevice.html">MonkeyDevice</a></code>:
+        Represents a device or emulator. This class provides methods for installing and
+        uninstalling packages, starting an Activity, and sending keyboard or touch events to an
+        application. You also use this class to run test packages.
+    </li>
+    <li>
+        <code><a href="{@docRoot}guide/developing/tools/MonkeyImage.html">MonkeyImage</a></code>:
+        Represents a screen capture image. This class provides methods for capturing screens,
+        converting bitmap images to various formats, comparing two MonkeyImage objects, and
+        writing an image to a file.
+    </li>
+</ul>
+<p>
+    In a Python program, you access each class as a Python module. The monkeyrunner tool
+    does not import these modules automatically. To import a module, use the
+    Python <code>from</code> statement:
+</p>
+<pre>
+from com.android.monkeyrunner import &lt;module&gt;
+</pre>
+<p>
+    where <code>&lt;module&gt;</code> is the class name you want to import. You can import more
+    than one module in the same <code>from</code> statement by separating the module names with
+    commas.
+</p>
+<h2 id="RunningMonkeyRunner">Running monkeyrunner</h2>
+<p>
+    You can either run monkeyrunner programs from a file, or enter monkeyrunner statements in
+    an interactive session. You do both by invoking the <code>monkeyrunner</code> command
+    which is found in the <code>tools/</code> subdirectory of your SDK directory.
+    If you provide a filename as an argument, the <code>monkeyrunner</code> command
+    runs the file's contents as a Python program; otherwise, it starts an interactive session.
+</p>
+<p>
+    The syntax of the <code>monkeyrunner</code> command is
+</p>
+<pre>
+monkeyrunner -plugin &lt;plugin_jar&gt; &lt;program_filename&gt; &lt;program_options&gt;
+</pre>
+<p>
+Table 1 explains the flags and arguments.
+</p>
+<p class="table-caption" id="table1">
+  <strong>Table 1.</strong> <code>monkeyrunner</code> flags and arguments.</p>
+
+<table>
+    <tr>
+        <th>Argument</th>
+        <th>Description</th>
+    </tr>
+    <tr>
+        <td>
+            <nobr>
+                <code>-plugin &lt;plugin_jar&gt;</code>
+            </nobr>
+        </td>
+        <td>
+            (Optional) Specifies a <code>.jar</code> file containing a plugin for monkeyrunner.
+            To learn more about monkeyrunner plugins, see
+            <a href="#Plugins">Extending monkeyrunner with plugins</a>. To specify more than one
+            file, include the argument multiple times.
+        </td>
+    </tr>
+    <tr>
+        <td>
+            <nobr>
+                <code>&lt;program_filename&gt;</code>
+            </nobr>
+        </td>
+        <td>
+            If you provide this argument, the <code>monkeyrunner</code> command runs the contents
+            of the file as a Python program. If the argument is not provided, the command starts an
+            interactive session.
+        </td>
+    </tr>
+    <tr>
+        <td>
+            <code>&lt;program_options&gt;</code>
+        </td>
+        <td>
+            (Optional) Flags and arguments for the program in &lt;program_file&gt;.
+        </td>
+    </tr>
+</table>
+<h2 id="Help">monkeyrunner Built-in Help</h2>
+<p>
+    You can generate an API reference for monkeyrunner by running:
+</p>
+<pre>
+monkeyrunner &lt;format&gt; help.py &lt;outfile&gt;
+</pre>
+<p>
+The arguments are:
+</p>
+    <ul>
+        <li>
+            <code>&lt;format&gt;</code> is either <code>text</code> for plain text output
+            or <code>html</code> for HTML output.
+        </li>
+        <li>
+            <code>&lt;outfile&gt;</code> is a path-qualified name for the output file.
+        </li>
+    </ul>
+<h2 id="Plugins">Extending monkeyrunner with Plugins</h2>
+<p>
+    You can extend the monkeyrunner API with classes you write in the Java programming language
+    and build into one or more <code>.jar</code> files. You can use this feature to extend the
+    monkeyrunner API with your own classes or to extend the existing classes. You can also use this
+    feature to initialize the monkeyrunner environment.
+</p>
+<p>
+    To provide a plugin to monkeyrunner, invoke the <code>monkeyrunner</code> command with the
+    <code>-plugin &lt;plugin_jar&gt;</code> argument described in
+    <a href="#table1">table 1</a>.
+</p>
+<p>
+    In your plugin code, you can import and extend the the main monkeyrunner classes
+    <code>MonkeyDevice</code>, <code>MonkeyImage</code>, and <code>MonkeyRunner</code> in
+    <code>com.android.monkeyrunner</code> (see <a href="#APIClasses">The monkeyrunner API</a>).
+</p>
+<p>
+    Note that plugins do not give you access to the Android SDK. You can't import packages
+    such as <code>com.android.app</code>. This is because monkeyrunner interacts with the
+    device or emulator below the level of the framework APIs.
+</p>
+<h3>The plugin startup class</h3>
+<p>
+    The <code>.jar</code> file for a plugin can specify a class that is instantiated before
+    script processing starts. To specify this class, add the key
+    <code>MonkeyRunnerStartupRunner</code> to the <code>.jar</code> file's
+    manifest. The value should be the name of the class to run at startup. The following
+    snippet shows how you would do this within an <code>ant</code> build script:
+</p>
+<pre>
+&lt;jar jarfile=&quot;myplugin&quot; basedir="&#36;&#123;build.dir&#125;&quot;&gt;
+&lt;manifest&gt;
+&lt;attribute name=&quot;MonkeyRunnerStartupRunner&quot; value=&quot;com.myapp.myplugin&quot;/&gt;
+&lt;/manifest&gt;
+&lt;/jar&gt;
+
+
+</pre>
+<p>
+    To get access to monkeyrunner's runtime environment, the startup class can implement
+    <code>com.google.common.base.Predicate&lt;PythonInterpreter&gt;</code>. For example, this
+    class sets up some variables in the default namespace:
+</p>
+<pre>
+package com.android.example;
+
+import com.google.common.base.Predicate;
+import org.python.util.PythonInterpreter;
+
+public class Main implements Predicate&lt;PythonInterpreter&gt; {
+    &#64;Override
+    public boolean apply(PythonInterpreter anInterpreter) {
+
+        /*
+        * Examples of creating and initializing variables in the monkeyrunner environment's
+        * namespace. During execution, the monkeyrunner program can refer to the variables "newtest"
+        * and "use_emulator"
+        *
+        */
+        anInterpreter.set("newtest", "enabled");
+        anInterpreter.set("use_emulator", 1);
+
+        return true;
+    }
+}
+</pre>
diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs
index 2b803424..a43e334 100644
--- a/docs/html/guide/guide_toc.cs
+++ b/docs/html/guide/guide_toc.cs
@@ -254,34 +254,45 @@
             <li><a href="<?cs var:toroot?>guide/topics/search/searchable-config.html">Searchable Configuration</a></li>
           </ul>
       </li>
-      <li class="toggle-list">
-           <div>
-                <a href="<?cs var:toroot ?>guide/topics/testing/index.html">
-                   <span class="en">Testing</span>
-               </a> <span class="new">new!</span>
-           </div>
-           <ul>
-              <li><a href="<?cs var:toroot?>guide/topics/testing/testing_android.html">
-                <span class="en">Testing Fundamentals</span></a>
-              </li>
-              <li><a href="<?cs var:toroot?>guide/topics/testing/activity_testing.html">
-                <span class="en">Activity Testing</span></a>
-              </li>
-              <li><a href="<?cs var:toroot ?>guide/topics/testing/contentprovider_testing.html">
-                <span class="en">Content Provider Testing</span></a>
-              </li>
-              <li><a href="<?cs var:toroot ?>guide/topics/testing/service_testing.html">
-                <span class="en">Service Testing</span></a>
-              </li>
-              <li><a href="<?cs var:toroot ?>guide/topics/testing/what_to_test.html">
-                <span class="en">What To Test</span></a>
-              </li>
-           </ul>
-      </li>
-     <li><a href="<?cs var:toroot?>guide/topics/admin/device-admin.html">
+      <li><a href="<?cs var:toroot?>guide/topics/admin/device-admin.html">
             <span class="en">Device Administration</span>
          </a> <span class="new">new!</span>
-    </li>
+      </li>
+      <li class="toggle-list">
+           <div>
+                <a href="<?cs var:toroot?>guide/topics/testing/index.html">
+                   <span class="en">Testing</span>
+               </a>
+           </div>
+           <ul>
+              <li>
+                <a href="<?cs var:toroot?>guide/topics/testing/testing_android.html">
+                <span class="en">Testing Fundamentals</span></a>
+                <span class="new">new!</span>
+              </li>
+              <li>
+                <a href="<?cs var:toroot?>guide/topics/testing/activity_testing.html">
+                <span class="en">Activity Testing</span></a>
+                <span class="new">new!</span>
+              </li>
+              <li>
+                <a href="<?cs var:toroot?>guide/topics/testing/contentprovider_testing.html">
+                <span class="en">Content Provider Testing</span></a>
+                <span class="new">new!</span>
+              </li>
+              <li>
+                <a href="<?cs var:toroot?>guide/topics/testing/service_testing.html">
+                <span class="en">Service Testing</span></a>
+                <span class="new">new!</span>
+              </li>
+              <li>
+                <a href="<?cs var:toroot ?>guide/topics/testing/what_to_test.html">
+                <span class="en">What To Test</span></a>
+                <span class="new">new!</span>
+              </li>
+
+           </ul>
+      </li>
     </ul>
   </li>
 
@@ -336,6 +347,7 @@
                   <span class="en">Testing in Eclipse, with ADT</span>
                 </a>
               </li>
+
               <li>
                 <a href="<?cs var:toroot ?>guide/developing/testing/testing_otheride.html">
                   <span class="en">Testing in Other IDEs</span>
@@ -363,6 +375,34 @@
               <li><a href="<?cs var:toroot ?>guide/developing/tools/layoutopt.html">layoutopt</a></li>
               <li><a href="<?cs var:toroot ?>guide/developing/tools/othertools.html#mksdcard">mksdcard</a></li>
               <li><a href="<?cs var:toroot ?>guide/developing/tools/monkey.html">Monkey</a></li>
+                            <li class="toggle-list">
+                 <div>
+                     <a href="<?cs var:toroot?>guide/developing/tools/monkeyrunner_concepts.html">
+                     <span class="en">monkeyrunner</span>
+                  </a>
+                      <span class="new">new!</span>
+                  </div>
+                  <ul>
+                      <li>
+                          <a href="<?cs var:toroot?>guide/developing/tools/MonkeyDevice.html">
+                                <span class="en">MonkeyDevice</span>
+                        </a>
+                        <span class="new">new!</span>
+                    </li>
+                    <li>
+                        <a href="<?cs var:toroot?>guide/developing/tools/MonkeyImage.html">
+                            <span class="en">MonkeyImage</span>
+                        </a>
+                        <span class="new">new!</span>
+                    </li>
+                    <li>
+                        <a href="<?cs var:toroot?>guide/developing/tools/MonkeyRunner.html">
+                            <span class="en">MonkeyRunner</span>
+                        </a>
+                        <span class="new">new!</span>
+                    </li>
+                  </ul>
+              </li>
               <li><a href="<?cs var:toroot ?>guide/developing/tools/adb.html#sqlite">sqlite3</a></li>
               <li><a href="<?cs var:toroot ?>guide/developing/tools/traceview.html" >Traceview</a></li>
               <li><a href="<?cs var:toroot ?>guide/developing/tools/zipalign.html" >zipalign</a></li>
diff --git a/docs/html/guide/topics/resources/providing-resources.jd b/docs/html/guide/topics/resources/providing-resources.jd
index 1d6ab25..d868599 100644
--- a/docs/html/guide/topics/resources/providing-resources.jd
+++ b/docs/html/guide/topics/resources/providing-resources.jd
@@ -129,9 +129,8 @@
 
   <tr>
     <td><code>raw/</code></td>
-    <td><p>Arbitrary files to save in their raw form. Files in here are not compressed by the
-system. To open these resources with a raw {@link java.io.InputStream}, call {@link
-android.content.res.Resources#openRawResource(int)
+    <td><p>Arbitrary files to save in their raw form. To open these resources with a raw
+{@link java.io.InputStream}, call {@link android.content.res.Resources#openRawResource(int)
 Resources.openRawResource()} with the resource ID, which is {@code R.raw.<em>filename</em>}.</p>
       <p>However, if you need access to original file names and file hierarchy, you might consider
 saving some resources in the {@code
diff --git a/docs/html/guide/topics/testing/index.jd b/docs/html/guide/topics/testing/index.jd
index b75656f..762a897 100644
--- a/docs/html/guide/topics/testing/index.jd
+++ b/docs/html/guide/topics/testing/index.jd
@@ -59,6 +59,20 @@
         which guides you through a more complex testing scenario.
     </li>
 </ul>
+<h4>Tools</h4>
+<ul>
+    <li>
+        The
+        <a href="{@docRoot}guide/developing/tools/monkey.html">UI/Application Exerciser Monkey</a>,
+        usually called Monkey, is a command-line tool that sends pseudo-random
+        streams of keystrokes, touches, and gestures to a device.
+    </li>
+    <li>
+     The <a href="{@docRoot}guide/developing/tools/monkeyrunner_concepts.html">monkeyrunner</a> tool
+        is an API and execution environment. You use monkeyrunner with Python programs
+        to test applications and devices.
+    </li>
+</ul>
 <h4>Samples</h4>
 <ul>
     <li>
diff --git a/docs/html/guide/topics/testing/testing_android.jd b/docs/html/guide/topics/testing/testing_android.jd
index 2a4c949..d4b0dcc 100755
--- a/docs/html/guide/topics/testing/testing_android.jd
+++ b/docs/html/guide/topics/testing/testing_android.jd
@@ -38,7 +38,7 @@
         <a href="#TestResults">Seeing Test Results</a>
     </li>
     <li>
-        <a href="#Monkeys">Monkey and MonkeyRunner</a>
+        <a href="#Monkeys">monkey and monkeyrunner</a>
     </li>
     <li>
        <a href="#PackageNames">Working With Package Names</a>
@@ -77,6 +77,13 @@
           <a href="{@docRoot}guide/developing/testing/testing_otheride.html">
           Testing in Other IDEs</a>
         </li>
+        <li>
+          <a href="{@docRoot}guide/developing/tools/monkeyrunner_concepts.html">
+          monkeyrunner</a>
+        </li>
+        <li>
+     <a href="{@docRoot}guide/developing/tools/monkey.html">UI/Application Exerciser Monkey</a>
+        </li>
       </ol>
   </div>
 </div>
@@ -112,10 +119,10 @@
     </li>
     <li>
         The SDK also provides
-        <a href="{@docRoot}guide/topics/testing/monkeyrunner.html">MonkeyRunner</a>, an API for
-        testing devices with Jython scripts, and <a
-        href="{@docRoot}guide/developing/tools/monkey.html">Monkey</a>, a command-line tool for
-        stress-testing UIs by sending pseudo-random events to a device.
+  <a href="{@docRoot}guide/developing/tools/monkeyrunner_concepts.html">monkeyrunner</a>, an API
+        testing devices with Python programs, and <a
+        href="{@docRoot}guide/developing/tools/monkey.html">UI/Application Exerciser Monkey</a>,
+        a command-line tool for stress-testing UIs by sending pseudo-random events to a device.
     </li>
 </ul>
 <p>
@@ -540,25 +547,28 @@
     <a href="{@docRoot}guide/developing/testing/testing_otheride.html#RunTestsCommand">
     Testing in Other IDEs</a>.
 </p>
-<h2 id="Monkeys">Monkey and MonkeyRunner</h2>
+<h2 id="Monkeys">monkey and monkeyrunner</h2>
 <p>
     The SDK provides two tools for functional-level application testing:
 </p>
     <ul>
         <li>
-            <a href="{@docRoot}guide/developing/tools/monkey.html">Monkey</a> is a command-line
-            tool that sends pseudo-random streams of keystrokes, touches, and gestures to a
-            device. You run it with the <a href="{@docRoot}guide/developing/tools/adb.html">
-            Android Debug Bridge</a> (adb) tool. You use it to stress-test your application and
-            report back errors that are encountered. You can repeat a stream of events by
-            running the tool each time with the same random number seed.
+The <a href="{@docRoot}guide/developing/tools/monkey.html">UI/Application Exerciser Monkey</a>,
+            usually called "monkey", is a command-line tool that sends pseudo-random streams of
+            keystrokes, touches, and gestures to a device. You run it with the
+            <a href="{@docRoot}guide/developing/tools/adb.html">Android Debug Bridge</a> (adb) tool.
+            You use it to stress-test your application and report back errors that are encountered.
+            You can repeat a stream of events by running the tool each time with the same random
+            number seed.
         </li>
         <li>
-            <a href="{@docRoot}guide/topics/testing/monkeyrunner.html">MonkeyRunner</a> is a
-            Jython API that you use in test programs written in Python. The API includes functions
-            for connecting to a device, installing and uninstalling packages, taking screenshots,
-            comparing two images, and running a test package against an application. Using the API
-            with Python, you can write a wide range of large, powerful, and complex tests.
+    The <a href="{@docRoot}guide/developing/tools/monkeyrunner_concepts.html">monkeyrunner</a> tool
+            is an API and execution environment for test programs written in Python. The API
+            includes functions for connecting to a device, installing and uninstalling packages,
+            taking screenshots, comparing two images, and running a test package against an
+            application. Using the API, you can write a wide range of large, powerful, and complex
+            tests. You run programs that use the API with the <code>monkeyrunner</code> command-line
+            tool.
         </li>
     </ul>
 <h2 id="PackageNames">Working With Package names</h2>
diff --git a/docs/html/resources/dashboard/platform-versions.jd b/docs/html/resources/dashboard/platform-versions.jd
index 3b4ccb0e..cef057e 100644
--- a/docs/html/resources/dashboard/platform-versions.jd
+++ b/docs/html/resources/dashboard/platform-versions.jd
@@ -52,7 +52,7 @@
 <div class="dashboard-panel">
 
 <img alt="" height="250" width="460"
-src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:9.7,16.4,0.1,40.4,33.4&chl=
+src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:7.9,15.0,0.1,40.8,36.2&chl=
 Android%201.5|Android%201.6|Other*|Android%202.1|Android%202.2&chco=c4df9b,
 6fad0c" />
 
@@ -62,13 +62,13 @@
   <th>API Level</th>
   <th>Distribution</th>
 </tr>
-<tr><td>Android 1.5</td><td>3</td><td>9.7%</td></tr>
-<tr><td>Android 1.6</td><td>4</td><td>16.4%</td></tr>
-<tr><td>Android 2.1</td><td>7</td><td>40.4%</td></tr>
-<tr><td>Android 2.2</td><td>8</td><td>33.4%</td></tr>
+<tr><td>Android 1.5</td><td>3</td><td>7.9%</td></tr>
+<tr><td>Android 1.6</td><td>4</td><td>15.0%</td></tr>
+<tr><td>Android 2.1</td><td>7</td><td>40.8%</td></tr>
+<tr><td>Android 2.2</td><td>8</td><td>36.2%</td></tr>
 </table>
 
-<p><em>Data collected during two weeks ending on October 1, 2010</em></p>
+<p><em>Data collected during two weeks ending on November 1, 2010</em></p>
 <p style="font-size:.9em">* <em>Other: 0.1% of devices running obsolete versions</em></p>
 
 </div><!-- end dashboard-panel -->
@@ -96,19 +96,18 @@
 <div class="dashboard-panel">
 
 <img alt="" height="250" width="660" style="padding:5px;background:#fff"
-src="http://chart.apis.google.com/chart?cht=lc&chs=660x250&chxt=x,y,r&chxr=0,0,12|1,0,100|2,0,100&
-chxl=0:|2010/04/01|04/15|05/01|05/15|06/01|06/15|07/01|07/15|08/01|08/15|09/01|09/15|2010/10/01|1:|0
-%25|25%25|50%25|75%25|100%25|2:|0%25|25%25|50%25|75%25|100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10,11,12&
-chxtc=0,5&chd=t:99.6,99.6,99.6,99.7,100.6,101.1,99.9,100.0,100.0,99.8,99.9,100.0,100.0|61.5,61.7,62.
-3,63.5,73.0,76.4,78.6,81.1,84.5,86.6,88.0,89.3,90.3|29.4,30.2,32.7,35.3,46.2,51.3,55.1,59.0,64.1,68.
-2,70.4,72.2,73.9|4.0,28.3,32.0,34.9,45.9,51.0,54.9,58.8,64.0,68.1,70.3,72.1,73.8|0.0,0.0,0.0,0.0,0.8
-,1.2,1.8,3.3,4.3,11.3,27.8,32.1,33.4&chm=tAndroid+1.5,7caa36,0,0,15,,t::-5|b,c3df9b,0,1,0|tAndroid+1
-.6,638d23,1,0,15,,t::-5|b,b0db6e,1,2,0|tAndroid+2.0.1,496c13,2,0,15,,t::-5|b,9ddb3d,2,3,0|tAndroid+2
-.1,2f4708,3,1,15,,t:-30:-40|b,89cf19,3,4,0|tAndroid+2.2,131d02,4,9,15,,t::-5|B,6fad0c,4,5,0&chg=7,25
-&chdl=Android+1.5|Android+1.6|Android+2.0.1|Android+2.1|Android+2.2&chco=add274,9ad145,84c323,6ba213
-,507d08" />
+src="http://chart.apis.google.com/chart?&cht=lc&chs=660x250&chxt=x,y,r&chxr=0,0,12|1,0,100|2,0,100&
+chxl=0%3A%7C2010/05/01%7C05/15%7C06/01%7C06/15%7C07/01%7C07/15%7C08/01%7C08/15%7C09/01%7C09/15%7C10/
+01%7C10/15%7C2010/11/01%7C1%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25%7C2%3A%7C0%25%7C25%25%7C50%25
+%7C75%25%7C100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10,11,12&chxtc=0,5&chd=t:98.9,99.3,100.3,100.8,99.7,99.
+8,99.8,99.7,99.8,99.9,99.9,99.9,99.9|61.6,63.1,72.7,76.1,78.4,80.9,84.3,86.5,87.9,89.2,90.2,91.1,92.
+0|32.0,34.9,45.9,51.0,54.9,58.8,64.0,68.1,70.3,72.1,73.8,75.3,77.0|0.0,0.0,0.8,1.2,1.8,3.3,4.3,11.3,
+27.8,32.1,33.4,34.5,36.2&chm=tAndroid%201.5,7caa36,0,0,15,,t::-5|b,c3df9b,0,1,0|tAndroid%201.6,
+5b831d,1,0,15,,t::-5|b,aadb5e,1,2,0|tAndroid%202.1,38540b,2,0,15,,t::-5|b,91da1e,2,3,0|tAndroid%202.
+2,131d02,3,7,15,,t::-5|B,6fad0c,3,4,0&chg=7,25&chdl=Android%201.5|Android%201.6|Android%202.1|
+Android%202.2&chco=add274,94d134,73ad18,507d08" />
 
-<p><em>Last historical dataset collected during two weeks ending on October 1, 2010</em></p>
+<p><em>Last historical dataset collected during two weeks ending on November 1, 2010</em></p>
 
 
 </div><!-- end dashboard-panel -->
diff --git a/docs/html/resources/faq/framework.jd b/docs/html/resources/faq/framework.jd
index f4b8db0..4a7a3fc 100644
--- a/docs/html/resources/faq/framework.jd
+++ b/docs/html/resources/faq/framework.jd
@@ -68,12 +68,17 @@
 <p>For sharing complex non-persistent user-defined objects for short
 duration, the following approaches are recommended:
 </p>
-  <h4>The android.app.Application class</h4>
-  <p>The android.app.Application is a base class for those who need to
-maintain global application state. It can be accessed via
-getApplication() from any Activity or Service. It has a couple of
-life-cycle methods and will be instantiated by Android automatically if
-your register it in AndroidManifest.xml.</p>
+  <h4>Singleton class</h4>
+  <p>You can take advantage of the fact that your application
+components run in the same process through the use of a singleton.
+This is a class that is designed to have only one instance.  It
+has a static method with a name such as <code>getInstance()</code>
+that returns the instance; the first time this method is called,
+it creates the global instance.  Because all callers get the same
+instance, they can use this as a point of interaction.  For
+example activity A may retrieve the instance and call setValue(3);
+later activity B may retrieve the instance and call getValue() to
+retrieve the last set value.</p>
 
   <h4>A public static field/method</h4>
   <p>An alternate way to make data accessible across Activities/Services is to use <em>public static</em>
@@ -90,18 +95,6 @@
 intent extras. The recipient activity retrieves the object using this
 key.</p>
 
-  <h4>A Singleton class</h4>
-  <p>There are advantages to using a static Singleton, such as you can
-refer to them without casting getApplication() to an
-application-specific class, or going to the trouble of hanging an
-interface on all your Application subclasses so that your various
-modules can refer to that interface instead. </p>
-<p>But, the life cycle of a static is not well under your control; so
-to abide by the life-cycle model, the application class should initiate and
-tear down these static objects in the onCreate() and onTerminate() methods
-of the Application Class</p>
-</p>
-
 <h3>Persistent Objects</h3>
 
 <p>Even while an application appears to continue running, the system
@@ -146,15 +139,11 @@
 <h2>If an Activity starts a remote service, is there any way for the
 Service to pass a message back to the Activity?</h2>
 
-<p>The remote service can define a callback interface and register it with the
-clients to callback into the clients. The 
-{@link android.os.RemoteCallbackList RemoteCallbackList} class provides methods to
-register and unregister clients with the service, and send and receive
-messages.</p>
-
-<p>The sample code for remote service callbacks is given in <a
-href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.html">ApiDemos/RemoteService</a></p>
-
+<p>See the {@link android.app.Service} documentation's for examples of
+how clients can interact with a service.  You can take advantage of the
+fact that your components run in the same process to greatly simplify
+service interaction from the generic remote case, as shown by the "Local
+Service Sample".  In some cases techniques like singletons may also make sense.
 
 
 <a name="6" id="6"></a>
diff --git a/docs/html/sdk/adding-components.jd b/docs/html/sdk/adding-components.jd
index 63c577e..755f200 100644
--- a/docs/html/sdk/adding-components.jd
+++ b/docs/html/sdk/adding-components.jd
@@ -6,7 +6,7 @@
 <div id="qv">
 <h2>Quickview</h2>
 <ul>
-  <li>Use the Android SDK and AVD Manager to 
+  <li>Use the Android SDK and AVD Manager to
    set up your SDK and keep it up-to-date.</li>
 </ul>
 
@@ -25,7 +25,7 @@
 <p>Adding and updating components in your Android SDK is fast and easy. To
 perform an update, use the <strong>Android SDK and AVD Manager</strong> to
 install or update the individual SDK components that you need. The Android SDK
-and AVD Manager tool is included in the <a href="index.html">Android SDK 
+and AVD Manager tool is included in the <a href="index.html">Android SDK
 download</a>.</p>
 
 <p>It only takes a couple of clicks to install individual versions of the
@@ -53,19 +53,19 @@
 href="{@docRoot}sdk/tools-notes.html">SDK Tools</a> document for ADT
 Plugin compatibility.</p>
 
-<div style="TEXT-ALIGN:left; width:600px;"> 
-<img src="{@docRoot}images/sdk_manager_packages.png" 
-style="padding-bottom:0;margin-bottom:0;" /> 
+<div style="TEXT-ALIGN:left; width:600px;">
+<img src="{@docRoot}images/sdk_manager_packages.png"
+style="padding-bottom:0;margin-bottom:0;" />
 <p class="caption" style="margin:0 0 1.5em 1em;padding:0 0 0
-1em;"><strong>Figure 1.</strong> The Android SDK and AVD Manager's 
+1em;"><strong>Figure 1.</strong> The Android SDK and AVD Manager's
 <strong>Available Packages</strong>
 panel, which shows the SDK components that are
 available for you to download into your environment. </p>
-</div> 
+</div>
 
 <h2 id="launching">Launching the Android SDK and AVD Manager</h2>
 
-<p>The Android SDK and AVD Manager is the tool that you use to install and 
+<p>The Android SDK and AVD Manager is the tool that you use to install and
 upgrade SDK components in your development environment. </p>
 
 <p>You can access the tool in any of three ways:</p>
@@ -83,15 +83,15 @@
 
 <ol>
 <li>Open Eclipse</li>
-<li>Select <strong>Window</strong> &gt; <strong>Android SDK and AVD 
+<li>Select <strong>Window</strong> &gt; <strong>Android SDK and AVD
 Manager</strong>.</li>
 </ol>
 
-<h4>Launching from the setup script (Windows only)</h4>
+<h4>Launching from the SDK Manager script (Windows only)</h4>
 
 <p>For Windows only, the SDK includes a script that invokes the Android SDK and
-AVD Manager. To launch the tool using the script, double-click "SDK
-Setup.exe" at the root of the the SDK directory.</p>
+AVD Manager. To launch the tool using the script, double-click {@code SDK
+Manager.exe} at the root of the the SDK directory.</p>
 
 <h4>Launching from a command line</h4>
 
@@ -100,37 +100,39 @@
 
 <ol>
 <li>Navigate to the <code>&lt;<em>sdk</em>&gt;/tools/</code> directory.</li>
-<li>Execute the {@code android} tool command with no options. 
+<li>Execute the {@code android} tool command with no options.
   <pre style="width:400px">$ android</pre></li>
 </ol>
 
 
 <h2 id="InstallingComponents">Installing SDK Components</h2>
 
-<p class="caution"><strong>Important:</strong> Before you install SDK components, 
-we recommend that you disable any antivirus programs that may be running on
-your computer.</p>
+<p class="caution"><strong>Caution:</strong> Before you install SDK components,
+we recommend that you disable any antivirus software that may be running on
+your computer. There are cases in which antivirus software on Windows is known to interfere with the
+installation process, so we suggest you disable your antivirus until installation is
+complete.</p>
 
 <p>Follow these steps to install new SDK components in your environment:</p>
 
 <ol>
   <li>Launch the Android SDK and AVD Manager as described in the section above.</li>
   <li>Select <strong>Available Packages</strong> in the left panel.
-  This will reveal all of the components that are currently available for download 
+  This will reveal all of the components that are currently available for download
   from the SDK repository.</li>
   <li>Select the component(s) you'd like to install and click <strong>Install
-  Selected</strong>. If you aren't sure which packages to select, read <a 
+  Selected</strong>. If you aren't sure which packages to select, read <a
   href="installing.html#which">Which components do I need?</a>.</li>
   <li>Verify and accept the components you want and click <strong>Install
   Accepted</strong>. The components will now be installed into your existing
   Android SDK directories.</li>
 </ol>
 
-<p>New platforms are automatically saved into the 
+<p>New platforms are automatically saved into the
 <code>&lt;<em>sdk</em>&gt;/platforms/</code> directory of your SDK;
 new add-ons are saved in the <code>&lt;<em>sdk</em>&gt;/add-ons/</code>
-directory; samples are saved in the 
-<code>&lt;<em>sdk</em>&gt;/samples/android-&lt;<em>level</em>&gt;/</code>; 
+directory; samples are saved in the
+<code>&lt;<em>sdk</em>&gt;/samples/android-&lt;<em>level</em>&gt;/</code>;
 and new documentation is saved in the existing
 <code>&lt;<em>sdk</em>&gt;/docs/</code> directory (old docs are replaced).</p>
 
@@ -184,10 +186,10 @@
 <h2 id="AddingSites">Adding New Sites</h2>
 
 <p>By default, <strong>Available Packages</strong> only shows the default
-repository site, which offers platforms, SDK tools, documentation, the 
-Google APIs Add-on, and other components. You can add other sites that host 
+repository site, which offers platforms, SDK tools, documentation, the
+Google APIs Add-on, and other components. You can add other sites that host
 their own Android SDK add-ons, then download the SDK add-ons
-from those sites.</p>	
+from those sites.</p>
 
 <p>For example, a mobile carrier or device manufacturer might offer additional
 API libraries that are supported by their own Android-powered devices. In order
@@ -199,7 +201,7 @@
 
 <ol>
   <li>Select <strong>Available Packages</strong> in the left panel.</li>
-  <li>Click <strong>Add Site</strong> and enter the URL of the 
+  <li>Click <strong>Add Site</strong> and enter the URL of the
 {@code repository.xml} file. Click <strong>OK</strong>.</li>
 </ol>
 <p>Any SDK components available from the site will now be listed under
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index 7016eee..2e59801 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -1,27 +1,27 @@
 page.title=Android SDK
 sdk.redirect=0
 
-sdk.win_download=android-sdk_r07-windows.zip
-sdk.win_bytes=23669664
-sdk.win_checksum=69c40c2d2e408b623156934f9ae574f0
+sdk.win_installer=installer_r08-windows.exe
+sdk.win_installer_bytes=TODO
+sdk.win_installer_checksum=TODO
 
-sdk.mac_download=android-sdk_r07-mac_x86.zip
-sdk.mac_bytes=19229546
-sdk.mac_checksum=0f330ed3ebb36786faf6dc72b8acf819
+sdk.win_download=android-sdk_r08-windows.zip
+sdk.win_bytes=TODO
+sdk.win_checksum=TODO
 
-sdk.linux_download=android-sdk_r07-linux_x86.tgz
-sdk.linux_bytes=17114517
-sdk.linux_checksum=e10c75da3d1aa147ddd4a5c58bfc3646
+sdk.mac_download=android-sdk_r08-mac_x86.zip
+sdk.mac_bytes=TODO
+sdk.mac_checksum=TODO
+
+sdk.linux_download=android-sdk_r08-linux_x86.tgz
+sdk.linux_bytes=TODO
+sdk.linux_checksum=TODO
 
 @jd:body
 
 
 <h2 id="quickstart">Quick Start</h2>
 
-<p>The steps below provide an overview of how to get started with the Android
-SDK. For detailed instructions, start with the <a
-href="{@docRoot}sdk/installing.html">Installing the SDK</a> guide. </p>
-
 <p><strong>1. Prepare your development computer</strong></p>
 
 <p>Read the <a href="{@docRoot}sdk/requirements.html">System Requirements</a>
@@ -34,38 +34,37 @@
 
 <p><strong>2. Download and install the SDK starter package</strong></p>
 
-<p>Select a starter package from the table at the top of this page and download
-it to your development computer. To install the SDK, simply unpack the starter
-package to a safe location and then add the location to your PATH. </p>
+<p>Download a starter package from the table above onto your development computer.
+If you're using Windows, we recommend that you download the installer (the {@code .exe} file),
+which will launch a Wizard to guide you through the installation and check your computer for
+required software. Otherwise, download the SDK starter package ({@code .zip} or {@code .tgz})
+appropriate for your system, unpack it to a safe location, then add the location to your PATH
+environment variable. </p>
 
 <p><strong>3. Install the ADT Plugin for Eclipse</strong></p>
 
-<p>If you are developing in Eclipse, set up a remote update site at
-<code>https://dl-ssl.google.com/android/eclipse/</code>. Install the Android 
-Development Tools (ADT) Plugin, restart Eclipse, and set the "Android" 
-preferences in Eclipse to point to the SDK install location. For detailed
-instructions, see <a href="{@docRoot}sdk/eclipse-adt.html">ADT Plugin 
+<p>If you are developing in Eclipse, add a new remote update site with the URL
+<code>https://dl-ssl.google.com/android/eclipse/</code>. Install the Android
+Development Tools (ADT) Plugin from that site, restart Eclipse, and set the "Android"
+preferences in Eclipse to point to the Android SDK directory (installed in the previous step). For
+detailed instructions to setup Eclipse, see <a href="{@docRoot}sdk/eclipse-adt.html">ADT Plugin
 for Eclipse</a>.</p>
 
 <p><strong>4. Add Android platforms and other components to your SDK</strong></p>
 
-<p>Use the Android SDK and AVD Manager, included in the SDK starter package, to
-add one or more Android platforms (for example, Android 1.6 or Android 2.2) and
-other components to your SDK. If you aren't sure what to add, see <a
+<p>Launch the <em>Android SDK and AVD Manager</em> by executing {@code SDK Manager.exe} (Windows) or
+{@code android} (Mac/Linux) from the SDK's {@code tools/} directory (if you used the Windows
+installer, this is launched for you when the Wizard is complete). Add some Android platforms
+(such as Android 1.6 and Android 2.3) and other components (such as documentation) to your SDK. If
+you aren't sure what to add, see <a
 href="installing.html#which">Which components do I need?</a></p>
 
-<p>To launch the Android SDK and AVD Manager on Windows, execute <code>SDK
-Setup.exe</code>, at the root of the SDK directory. On Mac OS X or Linux,
-execute the <code>android</code> tool in the <code>&lt;sdk&gt;/tools/</code>
-folder. For detailed instructions, see <a
-href="{@docRoot}sdk/adding-components.html">Adding SDK Components</a>.</p>
-
 <p><strong>Done!</strong></p>
 
-<p>If you are new to Android, you can use the <a
-href="{@docRoot}resources/tutorials/hello-world.html">Hello World</a> tutorial to
-get started quickly. <a href="{@docRoot}sdk/installing.html#NextSteps">Next
-Steps</a> offers other suggestions of how to begin.</p>
+<p>To write your first Android application, see the <a
+href="{@docRoot}resources/tutorials/hello-world.html">Hello World</a> tutorial. Also see <a
+href="{@docRoot}sdk/installing.html#NextSteps">Next
+Steps</a> for other suggestions about how to get started.</p>
 
-<p>For a more detailed guide to installing and setting up the SDK, read <a 
+<p>For a more detailed guide to installing and setting up the SDK, read <a
 href="installing.html">Installing the SDK</a>.</p>
diff --git a/docs/html/sdk/installing.jd b/docs/html/sdk/installing.jd
index 73190a0..8484bea 100644
--- a/docs/html/sdk/installing.jd
+++ b/docs/html/sdk/installing.jd
@@ -29,20 +29,20 @@
 </div>
 </div>
 
-<p>This page describes how to install the Android SDK 
+<p>This page describes how to install the Android SDK
 and set up your development environment for the first time.</p>
 
-<p>If you encounter any problems during installation, see the 
+<p>If you encounter any problems during installation, see the
 <a href="#troubleshooting">Troubleshooting</a> section at the bottom of
 this page.</p>
 
 <h4>Updating?</h4>
 
-<p>If you are currently using the Android 1.6 SDK or later and want to update 
-to the latest tools or platforms, you do not need to install a new SDK. Instead, 
-you can simply update the individual components in your SDK using the 
-Android SDK and AVD Manager tool. For information about how to do that, see <a 
-href="{@docRoot}sdk/adding-components.html#UpdatingComponents">Updating SDK 
+<p>If you are currently using the Android 1.6 SDK or later and want to update
+to the latest tools or platforms, you do not need to install a new SDK. Instead,
+you can simply update the individual components in your SDK using the
+Android SDK and AVD Manager tool. For information about how to do that, see <a
+href="{@docRoot}sdk/adding-components.html#UpdatingComponents">Updating SDK
 Components</a></p>
 
 <p>If you are using Android 1.5 SDK or earlier, you should install a new SDK as
@@ -54,65 +54,71 @@
 
 <p>Before getting started with the Android SDK, take a moment to confirm that
 your development computer meets the <a href="requirements.html">System
-Requirements</a>. In particular, you may need to install the <a 
-href="http://java.sun.com/javase/downloads/index.jsp">JDK</a> before 
+Requirements</a>. In particular, you may need to install the <a
+href="http://java.sun.com/javase/downloads/index.jsp">JDK</a> before
 continuing, if it's not already installed on your computer. </p>
 
 <p>If you will be developing in Eclipse with the Android Development
 Tools (ADT) Plugin &mdash; the recommended path if you are new to
 Android &mdash; make sure that you have a suitable version of Eclipse
-installed on your computer (3.4 or newer is recommended). If you need 
-to install Eclipse, you can download it from this location: </p> 
- 
+installed on your computer (3.4 or newer is recommended). If you need
+to install Eclipse, you can download it from this location: </p>
+
 <p style="margin-left:2em;"><a href=
-"http://www.eclipse.org/downloads/">http://www.eclipse.org/downloads/</a></p> 
- 
-<p>A Java or RCP version of Eclipse is recommended. For Eclipse 3.5, the 
-"Eclipse Classic" version is recommended.</p> 
+"http://www.eclipse.org/downloads/">http://www.eclipse.org/downloads/</a></p>
+
+<p>A Java or RCP version of Eclipse is recommended. For Eclipse 3.5, the
+"Eclipse Classic" version is recommended.</p>
 
 
 <h2 id="Installing">Step 2. Downloading the SDK Starter Package</h2>
 
 <p>The first step in setting up your environment for developing Android applications
 is downloading the Android SDK starter package. The starter package is not a full
-development environment &mdash; it includes only the core SDK Tools, which you can 
-use to download the rest of the SDK components. </p>
+development environment &mdash; it includes only the core SDK Tools, which you can
+use to download the rest of the SDK components (such as the platform system images). </p>
 
 <p>You can get the latest version of the SDK starter package from the <a
 href="{@docRoot}sdk/index.html">SDK download page</a>. Make sure to download the
 package that is appropriate for your development computer.</p>
 
-<p>After downloading, unpack the Android SDK archive to a safe location on your
-machine. By default, the SDK files are unpacked into a directory named
-<code>android-sdk-&lt;machine-platform&gt;</code>. Make a note of the name and
-location of the unpacked SDK directory on your system &mdash; you will need to
-refer to the SDK directory later, when setting up the ADT plugin or when using
-the SDK tools.</p>
+<p class="note"><strong>Note:</strong> If you're using Windows, we recommend that you download
+the SDK installer (the {@code .exe} file from the download table). It will guide you through the
+installation process and check your computer for the required software.</p>
 
-<p>Optionally, you may want to add the location of the SDK's primary
-<code>tools</code> directory to your system <code>PATH</code>. The primary
-<code>tools/</code> directory is located at the root of the SDK folder. Adding
-<code>tools</code> to your path lets you run Android Debug Bridge (adb) and the
-other command line <a
+<p>If you downloaded a {@code .zip} of {@code .tgz} (instead of using the SDK installer), unpack the
+Android SDK archive to a safe location on your machine. By default, the SDK files are unpacked into
+a directory named <code>android-sdk-&lt;machine-platform&gt;</code>.</p>
+
+<p>Make a note of the name and
+location of the unpacked SDK directory on your system &mdash; you will need to
+refer to the SDK directory later, when setting up the ADT plugin and when using
+the SDK tools from command line.</p>
+
+<p>Optionally, you might want to add the location of the SDK's primary
+<code>tools</code> directory and the additional {@code platform-tools/} directory  to your system
+<code>PATH</code>. Both tool directories are located at the root of the SDK folder. Adding
+<code>tools/</code> and {@code platform-tools/} to your path lets you run Android Debug Bridge (adb)
+and the other command line <a
 href="{@docRoot}guide/developing/tools/index.html">tools</a> without needing to
-supply the full path to the tools directory. </p> 
+supply the full path to the tool directories. </p>
 
 <ul>
     <li>On Linux, edit your <code>~/.bash_profile</code> or <code>~/.bashrc</code> file. Look
     for a line that sets the PATH environment variable and add the
-    full path to the <code>tools/</code> directory to it. If you don't 
+    full path to the <code>tools/</code> and {@code platform-tools/} directories to it. If you don't
     see a line setting the path, you can add one:</li>
 
-    <ul><code>export PATH=${PATH}:<em>&lt;your_sdk_dir&gt;</em>/tools</code></ul>
+    <ul><code>export PATH=${PATH}:&lt;your_sdk_dir&gt;/tools:&lt;your_sdk_dir&gt;/platform-tools</code></ul>
 
     <li>On a Mac OS X, look in your home directory for <code>.bash_profile</code> and
-    proceed as for Linux. You can create the <code>.bash_profile</code> if 
+    proceed as for Linux. You can create the <code>.bash_profile</code> if
     you haven't already set one up on your machine. </li>
 
-    <li>On Windows, right-click on My Computer, and select Properties.  
+    <li>On Windows, right-click on My Computer, and select Properties.
   Under the Advanced tab, hit the Environment Variables button, and in the
-  dialog that comes up, double-click on Path (under System Variables). Add the full path to the 
-  <code>tools/</code> directory to the path. </li>
+  dialog that comes up, double-click on Path (under System Variables). Add the full path to the
+  <code>tools/</code> and {@code platform-tools/} directories to the path. </li>
   </ul>
 
 <p>If you will be using the Eclipse IDE as your development environment, the
@@ -203,11 +209,11 @@
 <code>com.google.android.maps</code> library. You can also add additional
 repositories, so that you can download other SDK add-ons, where available. </li>
 
-<li><strong>USB Driver for Windows</strong> &mdash; Contains driver files 
+<li><strong>USB Driver for Windows</strong> &mdash; Contains driver files
 that you can install on your Windows computer, so that you can run and debug
 your applications on an actual device. You <em>do not</em> need the USB driver unless
 you plan to debug your application on an actual Android-powered device. If you
-develop on Mac OS X or Linux, you do not need a special driver to debug 
+develop on Mac OS X or Linux, you do not need a special driver to debug
 your application on an Android-powered device.</li>
 
 <li><strong>Samples</strong> &mdash; Contains the sample code and apps available
@@ -226,15 +232,15 @@
 components for download, and then install the selected components in your SDK
 environment. </p>
 
-<div style="TEXT-ALIGN:left;width:600px;"> 
-<img src="/images/sdk_manager_packages.png" 
-style="padding-bottom:0;margin-bottom:0;" /> 
+<div style="TEXT-ALIGN:left;width:600px;">
+<img src="/images/sdk_manager_packages.png"
+style="padding-bottom:0;margin-bottom:0;" />
 <p class="caption" style="margin:0 0 1.5em 1em;padding:0 0 0
-1em;"><strong>Figure 1.</strong> The Android SDK and AVD Manager's 
+1em;"><strong>Figure 1.</strong> The Android SDK and AVD Manager's
 <strong>Available Packages</strong>
 panel, which shows the SDK components that are
 available for you to download into your environment. </p>
-</div> 
+</div>
 
 
 <h3 id="which">Which components do I need?</h3>
@@ -257,8 +263,8 @@
 <td style="font-size:.9em;background-color:#FFE;color:gray">SDK Tools</td>
 <td style="font-size:.9em;background-color:#FFE;color:gray">If you've installed
 the SDK starter package, then you already have this component preinstalled. The
-SDK Tools component is required &mdash; you can't develop or build an application 
-without it. </td>
+SDK Tools and the SDK Platform-tools components are required &mdash; you can't develop or build an
+application without these. Make sure you keep these up to date.</td>
 </tr>
 
 <tr>
@@ -324,8 +330,8 @@
 to add components, see the <a href="{@docRoot}sdk/adding-components.html">Adding
 SDK Components</a> document. </p>
 
-<p>For revision notes and other detailed information about individual SDK 
-components, see the documents listed under "Downloadable SDK Components" in 
+<p>For revision notes and other detailed information about individual SDK
+components, see the documents listed under "Downloadable SDK Components" in
 the navigation at left.</p>
 
 
@@ -335,7 +341,7 @@
 and add-ons that you need, open the SDK directory and take a look at what's
 inside.</p>
 
-<p>The table below describes the full SDK directory contents, with components 
+<p>The table below describes the full SDK directory contents, with components
 installed. </p>
 
 <table>
@@ -351,10 +357,19 @@
 <tr>
 <td colspan="3"><code>docs/</code></td>
 <td>A full set of documentation in HTML format, including the Developer's Guide,
-API Reference, and other information. To read the documentation, load the 
+API Reference, and other information. To read the documentation, load the
 file <code>offline.html</code> in a web browser.</td>
 </tr>
 <tr>
+<td colspan="3"><code>platform-tools/</code></td>
+<td>Contains development tools that may be updated with each platform release (from the <em>Android
+SDK Platform-tools</em> component). Tools in here include {@code adb}, {@code dexdump}, and others
+others that you don't typically use directly. These tools are separate from the generic development
+tools in the {@code tools/} directory, because these tools may be updated in order to support new
+features in the latest Android platform, whereas the other tools have no dependencies on the
+platform version.</td>
+</tr>
+<tr>
 <td colspan="3"><code>platforms/</code></td>
 <td>Contains a set of Android platform versions that you can develop
 applications against, each in a separate directory.  </td>
@@ -362,7 +377,7 @@
 <tr>
 <td style="width:2em;border-bottom-color:white;"></td>
 <td colspan="2"><code><em>&lt;platform&gt;</em>/</code></td>
-<td>Platform version directory, for example "android-1.6". All platform version 
+<td>Platform version directory, for example "android-1.6". All platform version
 directories contain a similar set of files and subdirectory structure.</td>
 </tr>
 
@@ -376,8 +391,8 @@
 <td style="width:2em;border-bottom-color:white;"></td>
 <td style="width:2em;border-bottom-color:white;"></td>
 <td><code>images/</code></td>
-<td>Storage area for default disk images, including the Android system image, 
-the default userdata image, the default ramdisk image, and more. The images 
+<td>Storage area for default disk images, including the Android system image,
+the default userdata image, the default ramdisk image, and more. The images
 are used in emulator sessions.</td>
 </tr>
 <tr>
@@ -397,7 +412,8 @@
 <td style="width:2em;border-bottom-color:white;"></td>
 <td style="width:2em;border-bottom-color:white;"></td>
 <td><code>tools/</code></td>
-<td>Any development tools that are specific to the platform version.</td>
+<td>This directory is used only by SDK Tools r7 and below for development tools that are specific to
+this platform version&mdash;it's not used by SDK Tools r8 and above.</td>
 </tr>
 <tr>
 <td style="width:2em;"></td>
@@ -411,18 +427,21 @@
 <td>Sample code and apps that are specific to platform version.</td>
 </tr>
 <td colspan="3"><code>tools/</code></td>
-<td>Contains the set of development and profiling tools available to you, such
-as the emulator, the <code>android</code> tool, adb, ddms, and more.</td>
+<td>Contains the set of development and profiling tools that are platform-independent, such
+as the emulator, the AVD and SDK Manager, adb, ddms, hierarchyviewer and more. The tools in
+this directory may be updated at any time (from the <em>Android SDK Tools</em> component),
+independent of platform releases, whereas the tools in {@code platform-tools/} may be updated based
+on the latest platform release.</td>
 </tr>
 <tr>
 <td colspan="3"><code>SDK Readme.txt</code></td>
-<td>A file that explains how to perform the initial setup of your SDK, 
-including how to launch the Android SDK and AVD Manager tool on all 
+<td>A file that explains how to perform the initial setup of your SDK,
+including how to launch the Android SDK and AVD Manager tool on all
 platforms</td>
 </tr>
 <tr>
-<td colspan="3"><code>SDK Setup.exe</code></td>
-<td>Windows SDK only. A shortcut that launches the Android SDK and AVD 
+<td colspan="3"><code>SDK Manager.exe</code></td>
+<td>Windows SDK only. A shortcut that launches the Android SDK and AVD
 Manager tool, which you use to add components to your SDK. </td>
 </tr>
 <!--<tr>
@@ -447,7 +466,7 @@
 </li>
 </ul>
 
-<p class="caution">Following the Hello World tutorial is an essential 
+<p class="caution">Following the Hello World tutorial is an essential
 first step in getting started with Android development. </p>
 
 <p><strong>Learn about Android</strong></p>
@@ -481,20 +500,20 @@
 
 <ul>
   <li>The <a href="{@docRoot}resources/tutorials/notepad/index.html">
-  Notepad Tutorial</a> shows you how to build a full Android application 
-  and provides  helpful commentary on the Android system and API. The 
+  Notepad Tutorial</a> shows you how to build a full Android application
+  and provides  helpful commentary on the Android system and API. The
   Notepad tutorial helps you bring together the important design
-  and architectural concepts in a moderately complex application. 
+  and architectural concepts in a moderately complex application.
   </li>
 </ul>
-<p class="caution">Following the Notepad tutorial is an excellent 
+<p class="caution">Following the Notepad tutorial is an excellent
 second step in getting started with Android development. </p>
 
 <p><strong>Explore some code</strong></p>
 
 <ul>
   <li>The Android SDK includes sample code and applications for each platform
-version. You can browse the samples in the <a 
+version. You can browse the samples in the <a
 href="{@docRoot}resources/index.html">Resources</a> tab or download them
 into your SDK using the Android SDK and AVD Manager. Once you've downloaded the
 samples, you'll find them in
@@ -517,7 +536,7 @@
 
 <ul>
   <li>If you need help installing and configuring Java on your
-    development machine, you might find these resources helpful: 
+    development machine, you might find these resources helpful:
     <ul>
       <li><a href="https://help.ubuntu.com/community/Java">https://help.ubuntu.com/community/Java </a></li>
       <li><a href="https://help.ubuntu.com/community/Java">https://help.ubuntu.com/community/JavaInstallation</a></li>
@@ -537,7 +556,7 @@
       eclipse.org (<a
       href="http://www.eclipse.org/downloads/">http://www.eclipse.org/
       downloads/</a>). A Java or RCP version of Eclipse is recommended.</li>
-      <li>Follow the steps given in previous sections to install the SDK 
+      <li>Follow the steps given in previous sections to install the SDK
       and the ADT plugin. </li>
     </ol>
   </li>
diff --git a/docs/html/sdk/sdk_toc.cs b/docs/html/sdk/sdk_toc.cs
index d202b50..7b9a5a2 100644
--- a/docs/html/sdk/sdk_toc.cs
+++ b/docs/html/sdk/sdk_toc.cs
@@ -101,7 +101,7 @@
       <span style="display:none" class="ja"></span>
       <span style="display:none" class="zh-CN"></span>
       <span style="display:none" class="zh-TW"></span></a>
-      <span class="new">new!</span></li>
+      </li>
     </ul>
   </li>
   <li>
diff --git a/drm/libdrmframework/plugins/widevine/Android.mk b/drm/libdrmframework/plugins/widevine/Android.mk
new file mode 100644
index 0000000..2c388da
--- /dev/null
+++ b/drm/libdrmframework/plugins/widevine/Android.mk
@@ -0,0 +1,27 @@
+#
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libdrmwvmplugin
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/drm/plugins/native
+
+LOCAL_PRELINK_MODULE := false
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java
index a25fad4..289348a 100644
--- a/graphics/java/android/graphics/drawable/ColorDrawable.java
+++ b/graphics/java/android/graphics/drawable/ColorDrawable.java
@@ -51,7 +51,7 @@
      */
     public ColorDrawable(int color) {
         this(null);
-        mState.mBaseColor = mState.mUseColor = color;
+        setColor(color);
     }
 
     private ColorDrawable(ColorState state) {
@@ -72,6 +72,25 @@
     }
 
     /**
+     * Gets the drawable's color value.
+     *
+     * @return int The color to draw.
+     */
+    public int getColor() {
+        return mState.mUseColor;
+    }
+
+    /**
+     * Sets the drawable's color value. This action will clobber the results of prior calls to
+     * {@link #setAlpha(int)} on this object, which side-affected the underlying color.
+     *
+     * @param color The color to draw.
+     */
+    public void setColor(int color) {
+        mState.mBaseColor = mState.mUseColor = color;
+    }
+
+    /**
      * Returns the alpha value of this drawable's color.
      *
      * @return A value between 0 and 255.
@@ -131,7 +150,7 @@
     }
 
     final static class ColorState extends ConstantState {
-        int mBaseColor; // initial color. never changes
+        int mBaseColor; // base color, independent of setAlpha()
         int mUseColor;  // basecolor modulated by setAlpha()
         int mChangingConfigurations;
 
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index f8ad5cc..dfd6ac8 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -199,6 +199,7 @@
             throw new IllegalStateException("Resize only support for 1D allocations at this time.");
         }
         mRS.nAllocationResize1D(mID, dimX);
+        mRS.finish();  // Necessary because resize is fifoed and update is async.
 
         int typeID = mRS.nAllocationGetType(mID);
         mType = new Type(typeID, mRS);
diff --git a/include/drm/drm_framework_common.h b/include/drm/drm_framework_common.h
index c5765a9..1758cdd 100644
--- a/include/drm/drm_framework_common.h
+++ b/include/drm/drm_framework_common.h
@@ -217,6 +217,10 @@
      * POSIX based Decrypt API set for container based DRM
      */
     static const int CONTAINER_BASED = 0x02;
+    /**
+     * Decrypt API for Widevine streams
+     */
+    static const int WV_BASED = 0x3;
 };
 
 /**
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 9fd905f..1081c35 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -262,11 +262,15 @@
         DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100,
         DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200,
         DEVICE_OUT_AUX_DIGITAL = 0x400,
+        DEVICE_OUT_ANLG_DOCK_HEADSET = 0x800,
+        DEVICE_OUT_DGTL_DOCK_HEADSET = 0x1000,
         DEVICE_OUT_DEFAULT = 0x8000,
         DEVICE_OUT_ALL = (DEVICE_OUT_EARPIECE | DEVICE_OUT_SPEAKER | DEVICE_OUT_WIRED_HEADSET |
                 DEVICE_OUT_WIRED_HEADPHONE | DEVICE_OUT_BLUETOOTH_SCO | DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
                 DEVICE_OUT_BLUETOOTH_SCO_CARKIT | DEVICE_OUT_BLUETOOTH_A2DP | DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
-                DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER | DEVICE_OUT_AUX_DIGITAL | DEVICE_OUT_DEFAULT),
+                DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER | DEVICE_OUT_AUX_DIGITAL |
+                DEVICE_OUT_ANLG_DOCK_HEADSET | DEVICE_OUT_DGTL_DOCK_HEADSET |
+                DEVICE_OUT_DEFAULT),
         DEVICE_OUT_ALL_A2DP = (DEVICE_OUT_BLUETOOTH_A2DP | DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
                 DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER),
 
@@ -309,6 +313,8 @@
         FORCE_WIRED_ACCESSORY,
         FORCE_BT_CAR_DOCK,
         FORCE_BT_DESK_DOCK,
+        FORCE_ANALOG_DOCK,
+        FORCE_DIGITAL_DOCK,
         NUM_FORCE_CONFIG,
         FORCE_DEFAULT = FORCE_NONE
     };
diff --git a/include/media/stagefright/HardwareAPI.h b/include/media/stagefright/HardwareAPI.h
index b009e1b..4fd281b 100644
--- a/include/media/stagefright/HardwareAPI.h
+++ b/include/media/stagefright/HardwareAPI.h
@@ -37,11 +37,11 @@
 // buffers.  This is the mode that will be used when CPU access to the buffer is
 // required.
 //
-// When Android native buffer use has been enabled, the OMX node must support
-// only color formats in the range [OMX_COLOR_FormatAndroidPrivateStart,
-// OMX_COLOR_FormatAndroidPrivateEnd).  The node should then expect to receive
+// When Android native buffer use has been enabled for a given port, the video
+// color format for the port is to be interpreted as an Android pixel format
+// rather than an OMX color format.  The node should then expect to receive
 // UseAndroidNativeBuffer calls (via OMX_SetParameter) rather than UseBuffer
-// calls.
+// calls for that port.
 struct EnableAndroidNativeBuffersParams {
     OMX_U32 nSize;
     OMX_VERSIONTYPE nVersion;
@@ -75,16 +75,6 @@
     OMX_BOOL bStoreMetaData;
 };
 
-// Color formats in the range [OMX_COLOR_FormatAndroidPrivateStart,
-// OMX_COLOR_FormatAndroidPrivateEnd) will be converted to a gralloc pixel
-// format when used to allocate Android native buffers via gralloc.  The
-// conversion is done by subtracting OMX_COLOR_FormatAndroidPrivateStart from
-// the color format reported by the codec.
-enum {
-    OMX_COLOR_FormatAndroidPrivateStart = 0xA0000000,
-    OMX_COLOR_FormatAndroidPrivateEnd = 0xB0000000,
-};
-
 // A pointer to this struct is passed to OMX_SetParameter when the extension
 // index for the 'OMX.google.android.index.useAndroidNativeBuffer' extension is
 // given.  This call will only be performed if a prior call was made with the
diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp
index 1f5ed7c..c692bc1 100644
--- a/libs/rs/rsScriptC.cpp
+++ b/libs/rs/rsScriptC.cpp
@@ -78,10 +78,6 @@
 
         if (dest) {
             *dest = ptr;
-        } else {
-            if (rsc->props.mLogScripts) {
-                LOGV("ScriptC::setupScript, NULL var binding address.");
-            }
         }
     }
 }
@@ -404,16 +400,14 @@
     const ScriptCState::SymbolTable_t *sym;
     ScriptC *s = (ScriptC *)pContext;
     sym = ScriptCState::lookupSymbol(name);
-    if (sym) {
-        return sym->mPtr;
+    if (!sym) {
+        sym = ScriptCState::lookupSymbolCL(name);
     }
-    sym = ScriptCState::lookupSymbolCL(name);
-    if (sym) {
-        return sym->mPtr;
+    if (!sym) {
+        sym = ScriptCState::lookupSymbolGL(name);
     }
-    s->mEnviroment.mIsThreadable = false;
-    sym = ScriptCState::lookupSymbolGL(name);
     if (sym) {
+        s->mEnviroment.mIsThreadable &= sym->threadable;
         return sym->mPtr;
     }
     LOGE("ScriptC sym lookup failed for %s", name);
@@ -425,7 +419,6 @@
 
 void ScriptCState::runCompiler(Context *rsc, ScriptC *s)
 {
-    LOGV("%p ScriptCState::runCompiler ", rsc);
     {
         StopWatch compileTimer("RenderScript compile time");
         s->mBccScript = bccCreateScript();
diff --git a/libs/rs/rsScriptC.h b/libs/rs/rsScriptC.h
index e5b5ba9..86a7ad3 100644
--- a/libs/rs/rsScriptC.h
+++ b/libs/rs/rsScriptC.h
@@ -89,6 +89,7 @@
     struct SymbolTable_t {
         const char * mName;
         void * mPtr;
+        bool threadable;
     };
     //static SymbolTable_t gSyms[];
     static const SymbolTable_t * lookupSymbol(const char *);
diff --git a/libs/rs/rsScriptC_Lib.cpp b/libs/rs/rsScriptC_Lib.cpp
index 9fadee0..ecae306 100644
--- a/libs/rs/rsScriptC_Lib.cpp
+++ b/libs/rs/rsScriptC_Lib.cpp
@@ -436,120 +436,120 @@
 //                 ::= d  # double
 
 static ScriptCState::SymbolTable_t gSyms[] = {
-    { "__divsi3", (void *)&SC_divsi3 },
+    { "__divsi3", (void *)&SC_divsi3, true },
 
     // allocation
-    { "_Z19rsAllocationGetDimX13rs_allocation", (void *)&SC_allocGetDimX },
-    { "_Z19rsAllocationGetDimY13rs_allocation", (void *)&SC_allocGetDimY },
-    { "_Z19rsAllocationGetDimZ13rs_allocation", (void *)&SC_allocGetDimZ },
-    { "_Z21rsAllocationGetDimLOD13rs_allocation", (void *)&SC_allocGetDimLOD },
-    { "_Z23rsAllocationGetDimFaces13rs_allocation", (void *)&SC_allocGetDimFaces },
-    { "_Z15rsGetAllocationPKv", (void *)&SC_getAllocation },
+    { "_Z19rsAllocationGetDimX13rs_allocation", (void *)&SC_allocGetDimX, true },
+    { "_Z19rsAllocationGetDimY13rs_allocation", (void *)&SC_allocGetDimY, true },
+    { "_Z19rsAllocationGetDimZ13rs_allocation", (void *)&SC_allocGetDimZ, true },
+    { "_Z21rsAllocationGetDimLOD13rs_allocation", (void *)&SC_allocGetDimLOD, true },
+    { "_Z23rsAllocationGetDimFaces13rs_allocation", (void *)&SC_allocGetDimFaces, true },
+    { "_Z15rsGetAllocationPKv", (void *)&SC_getAllocation, true },
 
-    { "_Z14rsGetElementAt13rs_allocationj", (void *)&SC_getElementAtX },
-    { "_Z14rsGetElementAt13rs_allocationjj", (void *)&SC_getElementAtXY },
-    { "_Z14rsGetElementAt13rs_allocationjjj", (void *)&SC_getElementAtXYZ },
+    { "_Z14rsGetElementAt13rs_allocationj", (void *)&SC_getElementAtX, true },
+    { "_Z14rsGetElementAt13rs_allocationjj", (void *)&SC_getElementAtXY, true },
+    { "_Z14rsGetElementAt13rs_allocationjjj", (void *)&SC_getElementAtXYZ, true },
 
-    { "_Z11rsSetObjectP10rs_elementS_", (void *)&SC_setObject },
-    { "_Z13rsClearObjectP10rs_element", (void *)&SC_clearObject },
-    { "_Z10rsIsObject10rs_element", (void *)&SC_isObject },
+    { "_Z11rsSetObjectP10rs_elementS_", (void *)&SC_setObject, true },
+    { "_Z13rsClearObjectP10rs_element", (void *)&SC_clearObject, true },
+    { "_Z10rsIsObject10rs_element", (void *)&SC_isObject, true },
 
-    { "_Z11rsSetObjectP7rs_typeS_", (void *)&SC_setObject },
-    { "_Z13rsClearObjectP7rs_type", (void *)&SC_clearObject },
-    { "_Z10rsIsObject7rs_type", (void *)&SC_isObject },
+    { "_Z11rsSetObjectP7rs_typeS_", (void *)&SC_setObject, true },
+    { "_Z13rsClearObjectP7rs_type", (void *)&SC_clearObject, true },
+    { "_Z10rsIsObject7rs_type", (void *)&SC_isObject, true },
 
-    { "_Z11rsSetObjectP13rs_allocationS_", (void *)&SC_setObject },
-    { "_Z13rsClearObjectP13rs_allocation", (void *)&SC_clearObject },
-    { "_Z10rsIsObject13rs_allocation", (void *)&SC_isObject },
+    { "_Z11rsSetObjectP13rs_allocationS_", (void *)&SC_setObject, true },
+    { "_Z13rsClearObjectP13rs_allocation", (void *)&SC_clearObject, true },
+    { "_Z10rsIsObject13rs_allocation", (void *)&SC_isObject, true },
 
-    { "_Z11rsSetObjectP10rs_samplerS_", (void *)&SC_setObject },
-    { "_Z13rsClearObjectP10rs_sampler", (void *)&SC_clearObject },
-    { "_Z10rsIsObject10rs_sampler", (void *)&SC_isObject },
+    { "_Z11rsSetObjectP10rs_samplerS_", (void *)&SC_setObject, true },
+    { "_Z13rsClearObjectP10rs_sampler", (void *)&SC_clearObject, true },
+    { "_Z10rsIsObject10rs_sampler", (void *)&SC_isObject, true },
 
-    { "_Z11rsSetObjectP9rs_scriptS_", (void *)&SC_setObject },
-    { "_Z13rsClearObjectP9rs_script", (void *)&SC_clearObject },
-    { "_Z10rsIsObject9rs_script", (void *)&SC_isObject },
+    { "_Z11rsSetObjectP9rs_scriptS_", (void *)&SC_setObject, true },
+    { "_Z13rsClearObjectP9rs_script", (void *)&SC_clearObject, true },
+    { "_Z10rsIsObject9rs_script", (void *)&SC_isObject, true },
 
-    { "_Z11rsSetObjectP7rs_meshS_", (void *)&SC_setObject },
-    { "_Z13rsClearObjectP7rs_mesh", (void *)&SC_clearObject },
-    { "_Z10rsIsObject7rs_mesh", (void *)&SC_isObject },
+    { "_Z11rsSetObjectP7rs_meshS_", (void *)&SC_setObject, true },
+    { "_Z13rsClearObjectP7rs_mesh", (void *)&SC_clearObject, true },
+    { "_Z10rsIsObject7rs_mesh", (void *)&SC_isObject, true },
 
-    { "_Z11rsSetObjectP19rs_program_fragmentS_", (void *)&SC_setObject },
-    { "_Z13rsClearObjectP19rs_program_fragment", (void *)&SC_clearObject },
-    { "_Z10rsIsObject19rs_program_fragment", (void *)&SC_isObject },
+    { "_Z11rsSetObjectP19rs_program_fragmentS_", (void *)&SC_setObject, true },
+    { "_Z13rsClearObjectP19rs_program_fragment", (void *)&SC_clearObject, true },
+    { "_Z10rsIsObject19rs_program_fragment", (void *)&SC_isObject, true },
 
-    { "_Z11rsSetObjectP17rs_program_vertexS_", (void *)&SC_setObject },
-    { "_Z13rsClearObjectP17rs_program_vertex", (void *)&SC_clearObject },
-    { "_Z10rsIsObject17rs_program_vertex", (void *)&SC_isObject },
+    { "_Z11rsSetObjectP17rs_program_vertexS_", (void *)&SC_setObject, true },
+    { "_Z13rsClearObjectP17rs_program_vertex", (void *)&SC_clearObject, true },
+    { "_Z10rsIsObject17rs_program_vertex", (void *)&SC_isObject, true },
 
-    { "_Z11rsSetObjectP17rs_program_rasterS_", (void *)&SC_setObject },
-    { "_Z13rsClearObjectP17rs_program_raster", (void *)&SC_clearObject },
-    { "_Z10rsIsObject17rs_program_raster", (void *)&SC_isObject },
+    { "_Z11rsSetObjectP17rs_program_rasterS_", (void *)&SC_setObject, true },
+    { "_Z13rsClearObjectP17rs_program_raster", (void *)&SC_clearObject, true },
+    { "_Z10rsIsObject17rs_program_raster", (void *)&SC_isObject, true },
 
-    { "_Z11rsSetObjectP16rs_program_storeS_", (void *)&SC_setObject },
-    { "_Z13rsClearObjectP16rs_program_store", (void *)&SC_clearObject },
-    { "_Z10rsIsObject16rs_program_store", (void *)&SC_isObject },
+    { "_Z11rsSetObjectP16rs_program_storeS_", (void *)&SC_setObject, true },
+    { "_Z13rsClearObjectP16rs_program_store", (void *)&SC_clearObject, true },
+    { "_Z10rsIsObject16rs_program_store", (void *)&SC_isObject, true },
 
-    { "_Z11rsSetObjectP7rs_fontS_", (void *)&SC_setObject },
-    { "_Z13rsClearObjectP7rs_font", (void *)&SC_clearObject },
-    { "_Z10rsIsObject7rs_font", (void *)&SC_isObject },
+    { "_Z11rsSetObjectP7rs_fontS_", (void *)&SC_setObject, true },
+    { "_Z13rsClearObjectP7rs_font", (void *)&SC_clearObject, true },
+    { "_Z10rsIsObject7rs_font", (void *)&SC_isObject, true },
 
 
-    { "_Z21rsAllocationMarkDirty13rs_allocation", (void *)&SC_allocationMarkDirty },
+    { "_Z21rsAllocationMarkDirty13rs_allocation", (void *)&SC_allocationMarkDirty, true },
 
 
     // Debug
-    { "_Z7rsDebugPKcf", (void *)&SC_debugF },
-    { "_Z7rsDebugPKcff", (void *)&SC_debugFv2 },
-    { "_Z7rsDebugPKcfff", (void *)&SC_debugFv3 },
-    { "_Z7rsDebugPKcffff", (void *)&SC_debugFv4 },
-    { "_Z7rsDebugPKcd", (void *)&SC_debugD },
-    { "_Z7rsDebugPKcPK12rs_matrix4x4", (void *)&SC_debugFM4v4 },
-    { "_Z7rsDebugPKcPK12rs_matrix3x3", (void *)&SC_debugFM3v3 },
-    { "_Z7rsDebugPKcPK12rs_matrix2x2", (void *)&SC_debugFM2v2 },
-    { "_Z7rsDebugPKci", (void *)&SC_debugI32 },
-    { "_Z7rsDebugPKcj", (void *)&SC_debugU32 },
+    { "_Z7rsDebugPKcf", (void *)&SC_debugF, true },
+    { "_Z7rsDebugPKcff", (void *)&SC_debugFv2, true },
+    { "_Z7rsDebugPKcfff", (void *)&SC_debugFv3, true },
+    { "_Z7rsDebugPKcffff", (void *)&SC_debugFv4, true },
+    { "_Z7rsDebugPKcd", (void *)&SC_debugD, true },
+    { "_Z7rsDebugPKcPK12rs_matrix4x4", (void *)&SC_debugFM4v4, true },
+    { "_Z7rsDebugPKcPK12rs_matrix3x3", (void *)&SC_debugFM3v3, true },
+    { "_Z7rsDebugPKcPK12rs_matrix2x2", (void *)&SC_debugFM2v2, true },
+    { "_Z7rsDebugPKci", (void *)&SC_debugI32, true },
+    { "_Z7rsDebugPKcj", (void *)&SC_debugU32, true },
     // Both "long" and "unsigned long" need to be redirected to their
     // 64-bit counterparts, since we have hacked Slang to use 64-bit
     // for "long" on Arm (to be similar to Java).
-    { "_Z7rsDebugPKcl", (void *)&SC_debugLL64 },
-    { "_Z7rsDebugPKcm", (void *)&SC_debugULL64 },
-    { "_Z7rsDebugPKcx", (void *)&SC_debugLL64 },
-    { "_Z7rsDebugPKcy", (void *)&SC_debugULL64 },
-    { "_Z7rsDebugPKcPKv", (void *)&SC_debugP },
+    { "_Z7rsDebugPKcl", (void *)&SC_debugLL64, true },
+    { "_Z7rsDebugPKcm", (void *)&SC_debugULL64, true },
+    { "_Z7rsDebugPKcx", (void *)&SC_debugLL64, true },
+    { "_Z7rsDebugPKcy", (void *)&SC_debugULL64, true },
+    { "_Z7rsDebugPKcPKv", (void *)&SC_debugP, true },
 
     // RS Math
-    { "_Z6rsRandi", (void *)&SC_randi },
-    { "_Z6rsRandii", (void *)&SC_randi2 },
-    { "_Z6rsRandf", (void *)&SC_randf },
-    { "_Z6rsRandff", (void *)&SC_randf2 },
-    { "_Z6rsFracf", (void *)&SC_frac },
+    { "_Z6rsRandi", (void *)&SC_randi, true },
+    { "_Z6rsRandii", (void *)&SC_randi2, true },
+    { "_Z6rsRandf", (void *)&SC_randf, true },
+    { "_Z6rsRandff", (void *)&SC_randf2, true },
+    { "_Z6rsFracf", (void *)&SC_frac, true },
 
     // time
-    { "_Z8rsSecondv", (void *)&SC_second },
-    { "_Z8rsMinutev", (void *)&SC_minute },
-    { "_Z6rsHourv", (void *)&SC_hour },
-    { "_Z5rsDayv", (void *)&SC_day },
-    { "_Z7rsMonthv", (void *)&SC_month },
-    { "_Z6rsYearv", (void *)&SC_year },
-    { "_Z14rsUptimeMillisv", (void*)&SC_uptimeMillis },
-    { "_Z13rsUptimeNanosv", (void*)&SC_uptimeNanos },
-    { "_Z7rsGetDtv", (void*)&SC_getDt },
+    { "_Z8rsSecondv", (void *)&SC_second, true },
+    { "_Z8rsMinutev", (void *)&SC_minute, true },
+    { "_Z6rsHourv", (void *)&SC_hour, true },
+    { "_Z5rsDayv", (void *)&SC_day, true },
+    { "_Z7rsMonthv", (void *)&SC_month, true },
+    { "_Z6rsYearv", (void *)&SC_year, true },
+    { "_Z14rsUptimeMillisv", (void*)&SC_uptimeMillis, true },
+    { "_Z13rsUptimeNanosv", (void*)&SC_uptimeNanos, true },
+    { "_Z7rsGetDtv", (void*)&SC_getDt, false },
 
-    { "_Z14rsSendToClienti", (void *)&SC_toClient },
-    { "_Z14rsSendToClientiPKvj", (void *)&SC_toClient2 },
-    { "_Z22rsSendToClientBlockingi", (void *)&SC_toClientBlocking },
-    { "_Z22rsSendToClientBlockingiPKvj", (void *)&SC_toClientBlocking2 },
+    { "_Z14rsSendToClienti", (void *)&SC_toClient, false },
+    { "_Z14rsSendToClientiPKvj", (void *)&SC_toClient2, false },
+    { "_Z22rsSendToClientBlockingi", (void *)&SC_toClientBlocking, false },
+    { "_Z22rsSendToClientBlockingiPKvj", (void *)&SC_toClientBlocking2, false },
 
-    { "_Z9rsForEach9rs_script13rs_allocationS0_PKv", (void *)&SC_ForEach },
-    //{ "_Z9rsForEach9rs_script13rs_allocationS0_PKv", (void *)&SC_ForEach2 },
+    { "_Z9rsForEach9rs_script13rs_allocationS0_PKv", (void *)&SC_ForEach, false },
+    //{ "_Z9rsForEach9rs_script13rs_allocationS0_PKv", (void *)&SC_ForEach2, true },
 
 ////////////////////////////////////////////////////////////////////
 
-    //{ "sinf_fast", (void *)&SC_sinf_fast },
-    //{ "cosf_fast", (void *)&SC_cosf_fast },
+    //{ "sinf_fast", (void *)&SC_sinf_fast, true },
+    //{ "cosf_fast", (void *)&SC_cosf_fast, true },
 
-    { NULL, NULL }
+    { NULL, NULL, false }
 };
 
 const ScriptCState::SymbolTable_t * ScriptCState::lookupSymbol(const char *sym)
diff --git a/libs/rs/rsScriptC_LibCL.cpp b/libs/rs/rsScriptC_LibCL.cpp
index 1b1a752..7031f84 100644
--- a/libs/rs/rsScriptC_LibCL.cpp
+++ b/libs/rs/rsScriptC_LibCL.cpp
@@ -88,11 +88,6 @@
     return tanf(v * M_PI);
 }
 
-    //{ "logb", (void *)& },
-    //{ "mad", (void *)& },
-    //{ "nan", (void *)& },
-    //{ "tgamma", (void *)& },
-
 //////////////////////////////////////////////////////////////////////////////
 // Integer
 //////////////////////////////////////////////////////////////////////////////
@@ -198,105 +193,105 @@
 
 static ScriptCState::SymbolTable_t gSyms[] = {
     // OpenCL math
-    { "_Z4acosf", (void *)&acosf },
-    { "_Z5acoshf", (void *)&acoshf },
-    { "_Z6acospif", (void *)&SC_acospi },
-    { "_Z4asinf", (void *)&asinf },
-    { "_Z5asinhf", (void *)&asinhf },
-    { "_Z6asinpif", (void *)&SC_asinpi },
-    { "_Z4atanf", (void *)&atanf },
-    { "_Z5atan2ff", (void *)&atan2f },
-    { "_Z6atanpif", (void *)&SC_atanpi },
-    { "_Z7atan2piff", (void *)&SC_atan2pi },
-    { "_Z4cbrtf", (void *)&cbrtf },
-    { "_Z4ceilf", (void *)&ceilf },
-    { "_Z8copysignff", (void *)&copysignf },
-    { "_Z3cosf", (void *)&cosf },
-    { "_Z4coshf", (void *)&coshf },
-    { "_Z5cospif", (void *)&SC_cospi },
-    { "_Z4erfcf", (void *)&erfcf },
-    { "_Z3erff", (void *)&erff },
-    { "_Z3expf", (void *)&expf },
-    { "_Z4exp2f", (void *)&exp2f },
-    { "_Z5exp10f", (void *)&SC_exp10 },
-    { "_Z5expm1f", (void *)&expm1f },
-    { "_Z4fabsf", (void *)&fabsf },
-    { "_Z4fdimff", (void *)&fdimf },
-    { "_Z5floorf", (void *)&floorf },
-    { "_Z3fmafff", (void *)&fmaf },
-    { "_Z4fmaxff", (void *)&fmaxf },
-    { "_Z4fminff", (void *)&fminf },  // float fmin(float, float)
-    { "_Z4fmodff", (void *)&fmodf },
-    { "_Z5fractfPf", (void *)&SC_fract },
-    { "_Z5frexpfPi", (void *)&frexpf },
-    { "_Z5hypotff", (void *)&hypotf },
-    { "_Z5ilogbf", (void *)&ilogbf },
-    { "_Z5ldexpfi", (void *)&ldexpf },
-    { "_Z6lgammaf", (void *)&lgammaf },
-    { "_Z3logf", (void *)&logf },
-    { "_Z4log2f", (void *)&SC_log2 },
-    { "_Z5log10f", (void *)&log10f },
-    { "_Z5log1pf", (void *)&log1pf },
-    //{ "logb", (void *)& },
-    //{ "mad", (void *)& },
-    { "modf", (void *)&modff },
-    //{ "nan", (void *)& },
-    { "_Z9nextafterff", (void *)&nextafterf },
-    { "_Z3powff", (void *)&powf },
-    { "_Z4pownfi", (void *)&SC_pown },
-    { "_Z4powrff", (void *)&SC_powr },
-    { "_Z9remainderff", (void *)&remainderf },
-    { "remquo", (void *)&remquof },
-    { "_Z4rintf", (void *)&rintf },
-    { "_Z5rootnfi", (void *)&SC_rootn },
-    { "_Z5roundf", (void *)&roundf },
-    { "_Z5rsqrtf", (void *)&SC_rsqrt },
-    { "_Z3sinf", (void *)&sinf },
-    { "sincos", (void *)&SC_sincos },
-    { "_Z4sinhf", (void *)&sinhf },
-    { "_Z5sinpif", (void *)&SC_sinpi },
-    { "_Z4sqrtf", (void *)&sqrtf },
-    { "_Z3tanf", (void *)&tanf },
-    { "_Z4tanhf", (void *)&tanhf },
-    { "_Z5tanpif", (void *)&SC_tanpi },
-    //{ "tgamma", (void *)& },
-    { "_Z5truncf", (void *)&truncf },
+    { "_Z4acosf", (void *)&acosf, true },
+    { "_Z5acoshf", (void *)&acoshf, true },
+    { "_Z6acospif", (void *)&SC_acospi, true },
+    { "_Z4asinf", (void *)&asinf, true },
+    { "_Z5asinhf", (void *)&asinhf, true },
+    { "_Z6asinpif", (void *)&SC_asinpi, true },
+    { "_Z4atanf", (void *)&atanf, true },
+    { "_Z5atan2ff", (void *)&atan2f, true },
+    { "_Z6atanpif", (void *)&SC_atanpi, true },
+    { "_Z7atan2piff", (void *)&SC_atan2pi, true },
+    { "_Z4cbrtf", (void *)&cbrtf, true },
+    { "_Z4ceilf", (void *)&ceilf, true },
+    { "_Z8copysignff", (void *)&copysignf, true },
+    { "_Z3cosf", (void *)&cosf, true },
+    { "_Z4coshf", (void *)&coshf, true },
+    { "_Z5cospif", (void *)&SC_cospi, true },
+    { "_Z4erfcf", (void *)&erfcf, true },
+    { "_Z3erff", (void *)&erff, true },
+    { "_Z3expf", (void *)&expf, true },
+    { "_Z4exp2f", (void *)&exp2f, true },
+    { "_Z5exp10f", (void *)&SC_exp10, true },
+    { "_Z5expm1f", (void *)&expm1f, true },
+    { "_Z4fabsf", (void *)&fabsf, true },
+    { "_Z4fdimff", (void *)&fdimf, true },
+    { "_Z5floorf", (void *)&floorf, true },
+    { "_Z3fmafff", (void *)&fmaf, true },
+    { "_Z4fmaxff", (void *)&fmaxf, true },
+    { "_Z4fminff", (void *)&fminf, true },  // float fmin(float, float)
+    { "_Z4fmodff", (void *)&fmodf, true },
+    { "_Z5fractfPf", (void *)&SC_fract, true },
+    { "_Z5frexpfPi", (void *)&frexpf, true },
+    { "_Z5hypotff", (void *)&hypotf, true },
+    { "_Z5ilogbf", (void *)&ilogbf, true },
+    { "_Z5ldexpfi", (void *)&ldexpf, true },
+    { "_Z6lgammaf", (void *)&lgammaf, true },
+    { "_Z3logf", (void *)&logf, true },
+    { "_Z4log2f", (void *)&SC_log2, true },
+    { "_Z5log10f", (void *)&log10f, true },
+    { "_Z5log1pf", (void *)&log1pf, true },
+    //{ "logb", (void *)&, true },
+    //{ "mad", (void *)&, true },
+    { "modf", (void *)&modff, true },
+    //{ "nan", (void *)&, true },
+    { "_Z9nextafterff", (void *)&nextafterf, true },
+    { "_Z3powff", (void *)&powf, true },
+    { "_Z4pownfi", (void *)&SC_pown, true },
+    { "_Z4powrff", (void *)&SC_powr, true },
+    { "_Z9remainderff", (void *)&remainderf, true },
+    { "remquo", (void *)&remquof, true },
+    { "_Z4rintf", (void *)&rintf, true },
+    { "_Z5rootnfi", (void *)&SC_rootn, true },
+    { "_Z5roundf", (void *)&roundf, true },
+    { "_Z5rsqrtf", (void *)&SC_rsqrt, true },
+    { "_Z3sinf", (void *)&sinf, true },
+    { "sincos", (void *)&SC_sincos, true },
+    { "_Z4sinhf", (void *)&sinhf, true },
+    { "_Z5sinpif", (void *)&SC_sinpi, true },
+    { "_Z4sqrtf", (void *)&sqrtf, true },
+    { "_Z3tanf", (void *)&tanf, true },
+    { "_Z4tanhf", (void *)&tanhf, true },
+    { "_Z5tanpif", (void *)&SC_tanpi, true },
+    //{ "tgamma", (void *)&, true },
+    { "_Z5truncf", (void *)&truncf, true },
 
     // OpenCL Int
-    { "_Z3absi", (void *)&SC_abs_i32 },
-    { "_Z3abss", (void *)&SC_abs_i16 },
-    { "_Z3absc", (void *)&SC_abs_i8 },
-    { "_Z3clzj", (void *)&SC_clz_u32 },
-    { "_Z3clzt", (void *)&SC_clz_u16 },
-    { "_Z3clzh", (void *)&SC_clz_u8 },
-    { "_Z3clzi", (void *)&SC_clz_i32 },
-    { "_Z3clzs", (void *)&SC_clz_i16 },
-    { "_Z3clzc", (void *)&SC_clz_i8 },
-    { "_Z3maxjj", (void *)&SC_max_u32 },
-    { "_Z3maxtt", (void *)&SC_max_u16 },
-    { "_Z3maxhh", (void *)&SC_max_u8 },
-    { "_Z3maxii", (void *)&SC_max_i32 },
-    { "_Z3maxss", (void *)&SC_max_i16 },
-    { "_Z3maxcc", (void *)&SC_max_i8 },
-    { "_Z3minjj", (void *)&SC_min_u32 },
-    { "_Z3mintt", (void *)&SC_min_u16 },
-    { "_Z3minhh", (void *)&SC_min_u8 },
-    { "_Z3minii", (void *)&SC_min_i32 },
-    { "_Z3minss", (void *)&SC_min_i16 },
-    { "_Z3mincc", (void *)&SC_min_i8 },
+    { "_Z3absi", (void *)&SC_abs_i32, true },
+    { "_Z3abss", (void *)&SC_abs_i16, true },
+    { "_Z3absc", (void *)&SC_abs_i8, true },
+    { "_Z3clzj", (void *)&SC_clz_u32, true },
+    { "_Z3clzt", (void *)&SC_clz_u16, true },
+    { "_Z3clzh", (void *)&SC_clz_u8, true },
+    { "_Z3clzi", (void *)&SC_clz_i32, true },
+    { "_Z3clzs", (void *)&SC_clz_i16, true },
+    { "_Z3clzc", (void *)&SC_clz_i8, true },
+    { "_Z3maxjj", (void *)&SC_max_u32, true },
+    { "_Z3maxtt", (void *)&SC_max_u16, true },
+    { "_Z3maxhh", (void *)&SC_max_u8, true },
+    { "_Z3maxii", (void *)&SC_max_i32, true },
+    { "_Z3maxss", (void *)&SC_max_i16, true },
+    { "_Z3maxcc", (void *)&SC_max_i8, true },
+    { "_Z3minjj", (void *)&SC_min_u32, true },
+    { "_Z3mintt", (void *)&SC_min_u16, true },
+    { "_Z3minhh", (void *)&SC_min_u8, true },
+    { "_Z3minii", (void *)&SC_min_i32, true },
+    { "_Z3minss", (void *)&SC_min_i16, true },
+    { "_Z3mincc", (void *)&SC_min_i8, true },
 
     // OpenCL 6.11.4
-    { "_Z5clampfff", (void *)&SC_clamp_f32 },
-    { "_Z7degreesf", (void *)&SC_degrees },
-    { "_Z3maxff", (void *)&SC_max_f32 },
-    { "_Z3minff", (void *)&SC_min_f32 },
-    { "_Z3mixfff", (void *)&SC_mix_f32 },
-    { "_Z7radiansf", (void *)&SC_radians },
-    { "_Z4stepff", (void *)&SC_step_f32 },
-    //{ "smoothstep", (void *)& },
-    { "_Z4signf", (void *)&SC_sign_f32 },
+    { "_Z5clampfff", (void *)&SC_clamp_f32, true },
+    { "_Z7degreesf", (void *)&SC_degrees, true },
+    { "_Z3maxff", (void *)&SC_max_f32, true },
+    { "_Z3minff", (void *)&SC_min_f32, true },
+    { "_Z3mixfff", (void *)&SC_mix_f32, true },
+    { "_Z7radiansf", (void *)&SC_radians, true },
+    { "_Z4stepff", (void *)&SC_step_f32, true },
+    //{ "smoothstep", (void *)&, true },
+    { "_Z4signf", (void *)&SC_sign_f32, true },
 
-    { NULL, NULL }
+    { NULL, NULL, false }
 };
 
 const ScriptCState::SymbolTable_t * ScriptCState::lookupSymbolCL(const char *sym)
diff --git a/libs/rs/rsScriptC_LibGL.cpp b/libs/rs/rsScriptC_LibGL.cpp
index b991cab..5b07e7b 100644
--- a/libs/rs/rsScriptC_LibGL.cpp
+++ b/libs/rs/rsScriptC_LibGL.cpp
@@ -441,53 +441,53 @@
 //                 ::= d  # double
 
 static ScriptCState::SymbolTable_t gSyms[] = {
-    { "_Z22rsgBindProgramFragment19rs_program_fragment", (void *)&SC_bindProgramFragment },
-    { "_Z19rsgBindProgramStore16rs_program_store", (void *)&SC_bindProgramStore },
-    { "_Z20rsgBindProgramVertex17rs_program_vertex", (void *)&SC_bindProgramVertex },
-    { "_Z20rsgBindProgramRaster17rs_program_raster", (void *)&SC_bindProgramRaster },
-    { "_Z14rsgBindSampler19rs_program_fragmentj10rs_sampler", (void *)&SC_bindSampler },
-    { "_Z14rsgBindTexture19rs_program_fragmentj13rs_allocation", (void *)&SC_bindTexture },
+    { "_Z22rsgBindProgramFragment19rs_program_fragment", (void *)&SC_bindProgramFragment, false },
+    { "_Z19rsgBindProgramStore16rs_program_store", (void *)&SC_bindProgramStore, false },
+    { "_Z20rsgBindProgramVertex17rs_program_vertex", (void *)&SC_bindProgramVertex, false },
+    { "_Z20rsgBindProgramRaster17rs_program_raster", (void *)&SC_bindProgramRaster, false },
+    { "_Z14rsgBindSampler19rs_program_fragmentj10rs_sampler", (void *)&SC_bindSampler, false },
+    { "_Z14rsgBindTexture19rs_program_fragmentj13rs_allocation", (void *)&SC_bindTexture, false },
 
-    { "_Z36rsgProgramVertexLoadProjectionMatrixPK12rs_matrix4x4", (void *)&SC_vpLoadProjectionMatrix },
-    { "_Z31rsgProgramVertexLoadModelMatrixPK12rs_matrix4x4", (void *)&SC_vpLoadModelMatrix },
-    { "_Z33rsgProgramVertexLoadTextureMatrixPK12rs_matrix4x4", (void *)&SC_vpLoadTextureMatrix },
+    { "_Z36rsgProgramVertexLoadProjectionMatrixPK12rs_matrix4x4", (void *)&SC_vpLoadProjectionMatrix, false },
+    { "_Z31rsgProgramVertexLoadModelMatrixPK12rs_matrix4x4", (void *)&SC_vpLoadModelMatrix, false },
+    { "_Z33rsgProgramVertexLoadTextureMatrixPK12rs_matrix4x4", (void *)&SC_vpLoadTextureMatrix, false },
 
-    { "_Z35rsgProgramVertexGetProjectionMatrixP12rs_matrix4x4", (void *)&SC_vpGetProjectionMatrix },
+    { "_Z35rsgProgramVertexGetProjectionMatrixP12rs_matrix4x4", (void *)&SC_vpGetProjectionMatrix, false },
 
-    { "_Z31rsgProgramFragmentConstantColor19rs_program_fragmentffff", (void *)&SC_pfConstantColor },
+    { "_Z31rsgProgramFragmentConstantColor19rs_program_fragmentffff", (void *)&SC_pfConstantColor, false },
 
-    { "_Z11rsgGetWidthv", (void *)&SC_getWidth },
-    { "_Z12rsgGetHeightv", (void *)&SC_getHeight },
+    { "_Z11rsgGetWidthv", (void *)&SC_getWidth, false },
+    { "_Z12rsgGetHeightv", (void *)&SC_getHeight, false },
 
-    { "_Z18rsgUploadToTexture13rs_allocationj", (void *)&SC_uploadToTexture2 },
-    { "_Z18rsgUploadToTexture13rs_allocation", (void *)&SC_uploadToTexture },
-    { "_Z23rsgUploadToBufferObject13rs_allocation", (void *)&SC_uploadToBufferObject },
+    { "_Z18rsgUploadToTexture13rs_allocationj", (void *)&SC_uploadToTexture2, false },
+    { "_Z18rsgUploadToTexture13rs_allocation", (void *)&SC_uploadToTexture, false },
+    { "_Z23rsgUploadToBufferObject13rs_allocation", (void *)&SC_uploadToBufferObject, false },
 
-    { "_Z11rsgDrawRectfffff", (void *)&SC_drawRect },
-    { "_Z11rsgDrawQuadffffffffffff", (void *)&SC_drawQuad },
-    { "_Z20rsgDrawQuadTexCoordsffffffffffffffffffff", (void *)&SC_drawQuadTexCoords },
-    { "_Z24rsgDrawSpriteScreenspacefffff", (void *)&SC_drawSpriteScreenspace },
+    { "_Z11rsgDrawRectfffff", (void *)&SC_drawRect, false },
+    { "_Z11rsgDrawQuadffffffffffff", (void *)&SC_drawQuad, false },
+    { "_Z20rsgDrawQuadTexCoordsffffffffffffffffffff", (void *)&SC_drawQuadTexCoords, false },
+    { "_Z24rsgDrawSpriteScreenspacefffff", (void *)&SC_drawSpriteScreenspace, false },
 
-    { "_Z11rsgDrawMesh7rs_mesh", (void *)&SC_drawMesh },
-    { "_Z11rsgDrawMesh7rs_meshj", (void *)&SC_drawMeshPrimitive },
-    { "_Z11rsgDrawMesh7rs_meshjjj", (void *)&SC_drawMeshPrimitiveRange },
-    { "_Z25rsgMeshComputeBoundingBox7rs_meshPfS0_S0_S0_S0_S0_", (void *)&SC_meshComputeBoundingBox },
+    { "_Z11rsgDrawMesh7rs_mesh", (void *)&SC_drawMesh, false },
+    { "_Z11rsgDrawMesh7rs_meshj", (void *)&SC_drawMeshPrimitive, false },
+    { "_Z11rsgDrawMesh7rs_meshjjj", (void *)&SC_drawMeshPrimitiveRange, false },
+    { "_Z25rsgMeshComputeBoundingBox7rs_meshPfS0_S0_S0_S0_S0_", (void *)&SC_meshComputeBoundingBox, false },
 
-    { "_Z13rsgClearColorffff", (void *)&SC_ClearColor },
-    { "_Z13rsgClearDepthf", (void *)&SC_ClearDepth },
+    { "_Z13rsgClearColorffff", (void *)&SC_ClearColor, false },
+    { "_Z13rsgClearDepthf", (void *)&SC_ClearDepth, false },
 
-    { "_Z11rsgDrawTextPKcii", (void *)&SC_DrawText },
-    { "_Z11rsgDrawText13rs_allocationii", (void *)&SC_DrawTextAlloc },
-    { "_Z14rsgMeasureTextPKcPiS1_S1_S1_", (void *)&SC_MeasureText },
-    { "_Z14rsgMeasureText13rs_allocationPiS0_S0_S0_", (void *)&SC_MeasureTextAlloc },
+    { "_Z11rsgDrawTextPKcii", (void *)&SC_DrawText, false },
+    { "_Z11rsgDrawText13rs_allocationii", (void *)&SC_DrawTextAlloc, false },
+    { "_Z14rsgMeasureTextPKcPiS1_S1_S1_", (void *)&SC_MeasureText, false },
+    { "_Z14rsgMeasureText13rs_allocationPiS0_S0_S0_", (void *)&SC_MeasureTextAlloc, false },
 
-    { "_Z11rsgBindFont7rs_font", (void *)&SC_BindFont },
-    { "_Z12rsgFontColorffff", (void *)&SC_FontColor },
+    { "_Z11rsgBindFont7rs_font", (void *)&SC_BindFont, false },
+    { "_Z12rsgFontColorffff", (void *)&SC_FontColor, false },
 
     // misc
-    { "_Z5colorffff", (void *)&SC_color },
+    { "_Z5colorffff", (void *)&SC_color, false },
 
-    { NULL, NULL }
+    { NULL, NULL, false }
 };
 
 const ScriptCState::SymbolTable_t * ScriptCState::lookupSymbolGL(const char *sym)
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index b936c4d..a02c154 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -51,8 +51,8 @@
 
 namespace android {
 
-// Delay between reporting long touch events to the power manager.
-const nsecs_t EVENT_IGNORE_DURATION = 300 * 1000000LL; // 300 ms
+// Delay before reporting long touch events to the power manager.
+const nsecs_t LONG_TOUCH_DELAY = 300 * 1000000LL; // 300 ms
 
 // Default input dispatching timeout if there is no focused application or paused window
 // from which to determine an appropriate dispatching timeout.
@@ -1408,8 +1408,13 @@
 
 void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry) {
     int32_t eventType = POWER_MANAGER_BUTTON_EVENT;
-    if (eventEntry->type == EventEntry::TYPE_MOTION) {
+    switch (eventEntry->type) {
+    case EventEntry::TYPE_MOTION: {
         const MotionEntry* motionEntry = static_cast<const MotionEntry*>(eventEntry);
+        if (motionEntry->action == AMOTION_EVENT_ACTION_CANCEL) {
+            return;
+        }
+
         if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) {
             switch (motionEntry->action) {
             case AMOTION_EVENT_ACTION_DOWN:
@@ -1419,7 +1424,7 @@
                 eventType = POWER_MANAGER_TOUCH_UP_EVENT;
                 break;
             default:
-                if (motionEntry->eventTime - motionEntry->downTime >= EVENT_IGNORE_DURATION) {
+                if (motionEntry->eventTime - motionEntry->downTime < LONG_TOUCH_DELAY) {
                     eventType = POWER_MANAGER_TOUCH_EVENT;
                 } else {
                     eventType = POWER_MANAGER_LONG_TOUCH_EVENT;
@@ -1427,6 +1432,15 @@
                 break;
             }
         }
+        break;
+    }
+    case EventEntry::TYPE_KEY: {
+        const KeyEntry* keyEntry = static_cast<const KeyEntry*>(eventEntry);
+        if (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED) {
+            return;
+        }
+        break;
+    }
     }
 
     CommandEntry* commandEntry = postCommandLocked(
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index 03d2e21..f287298 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -1949,7 +1949,7 @@
         desiredConfig = overrideConfig;
     }
 
-    ssize_t rc = BAD_INDEX;
+    ssize_t rc = BAD_VALUE;
     size_t ip = grp->packages.size();
     while (ip > 0) {
         ip--;
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 23f34d2..a49bb37 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -307,10 +307,13 @@
         // Register for device connection intent broadcasts.
         IntentFilter intentFilter =
                 new IntentFilter(Intent.ACTION_HEADSET_PLUG);
+
         intentFilter.addAction(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
         intentFilter.addAction(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
         intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
         intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
+        intentFilter.addAction(Intent.ACTION_USB_ANLG_HEADSET_PLUG);
+        intentFilter.addAction(Intent.ACTION_USB_DGTL_HEADSET_PLUG);
         context.registerReceiver(mReceiver, intentFilter);
 
         // Register for media button intent broadcasts.
@@ -1816,6 +1819,12 @@
                     case Intent.EXTRA_DOCK_STATE_CAR:
                         config = AudioSystem.FORCE_BT_CAR_DOCK;
                         break;
+                    case Intent.EXTRA_DOCK_STATE_LE_DESK:
+                        config = AudioSystem.FORCE_ANALOG_DOCK;
+                        break;
+                    case Intent.EXTRA_DOCK_STATE_HE_DESK:
+                        config = AudioSystem.FORCE_DIGITAL_DOCK;
+                        break;
                     case Intent.EXTRA_DOCK_STATE_UNDOCKED:
                     default:
                         config = AudioSystem.FORCE_NONE;
@@ -1927,6 +1936,32 @@
                         mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE), "");
                     }
                 }
+            } else if (action.equals(Intent.ACTION_USB_ANLG_HEADSET_PLUG)) {
+                int state = intent.getIntExtra("state", 0);
+                Log.v(TAG, "Broadcast Receiver: Got ACTION_USB_ANLG_HEADSET_PLUG, state = "+state);
+                boolean isConnected = mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET);
+                if (state == 0 && isConnected) {
+                    AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET,
+                                                         AudioSystem.DEVICE_STATE_UNAVAILABLE, "");
+                    mConnectedDevices.remove(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET);
+                } else if (state == 1 && !isConnected)  {
+                    AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET,
+                                                         AudioSystem.DEVICE_STATE_AVAILABLE, "");
+                    mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET), "");
+                }
+            } else if (action.equals(Intent.ACTION_USB_DGTL_HEADSET_PLUG)) {
+                int state = intent.getIntExtra("state", 0);
+                Log.v(TAG, "Broadcast Receiver: Got ACTION_USB_DGTL_HEADSET_PLUG, state = "+state);
+                boolean isConnected = mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET);
+                if (state == 0 && isConnected) {
+                    AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET,
+                                                         AudioSystem.DEVICE_STATE_UNAVAILABLE, "");
+                    mConnectedDevices.remove(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET);
+                } else if (state == 1 && !isConnected)  {
+                    AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET,
+                                                         AudioSystem.DEVICE_STATE_AVAILABLE, "");
+                    mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET), "");
+                }
             } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
                 int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
                 synchronized (mScoClients) {
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index a4818ff..5442791 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -243,6 +243,8 @@
     public static final int DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100;
     public static final int DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200;
     public static final int DEVICE_OUT_AUX_DIGITAL = 0x400;
+    public static final int DEVICE_OUT_ANLG_DOCK_HEADSET = 0x800;
+    public static final int DEVICE_OUT_DGTL_DOCK_HEADSET = 0x1000;
     public static final int DEVICE_OUT_DEFAULT = 0x8000;
     // input devices
     public static final int DEVICE_IN_COMMUNICATION = 0x10000;
@@ -273,6 +275,8 @@
     public static final int FORCE_WIRED_ACCESSORY = 5;
     public static final int FORCE_BT_CAR_DOCK = 6;
     public static final int FORCE_BT_DESK_DOCK = 7;
+    public static final int FORCE_ANALOG_DOCK = 8;
+    public static final int FORCE_DIGITAL_DOCK = 9;
     public static final int FORCE_DEFAULT = FORCE_NONE;
 
     // usage for serForceUse
diff --git a/media/java/android/media/MediaFile.java b/media/java/android/media/MediaFile.java
index 381b77a..532a2df 100644
--- a/media/java/android/media/MediaFile.java
+++ b/media/java/android/media/MediaFile.java
@@ -83,6 +83,11 @@
     private static final int FIRST_PLAYLIST_FILE_TYPE = FILE_TYPE_M3U;
     private static final int LAST_PLAYLIST_FILE_TYPE = FILE_TYPE_WPL;
 
+    // Drm file types
+    public static final int FILE_TYPE_FL      = 51;
+    private static final int FIRST_DRM_FILE_TYPE = FILE_TYPE_FL;
+    private static final int LAST_DRM_FILE_TYPE = FILE_TYPE_FL;
+
     // Other popular file types
     public static final int FILE_TYPE_TEXT          = 100;
     public static final int FILE_TYPE_HTML          = 101;
@@ -189,6 +194,8 @@
         addFileType("PLS", FILE_TYPE_PLS, "audio/x-scpls", MtpConstants.FORMAT_PLS_PLAYLIST);
         addFileType("WPL", FILE_TYPE_WPL, "application/vnd.ms-wpl", MtpConstants.FORMAT_WPL_PLAYLIST);
 
+        addFileType("FL", FILE_TYPE_FL, "application/x-android-drm-fl");
+
         addFileType("TXT", FILE_TYPE_TEXT, "text/plain", MtpConstants.FORMAT_TEXT);
         addFileType("HTM", FILE_TYPE_HTML, "text/html", MtpConstants.FORMAT_HTML);
         addFileType("HTML", FILE_TYPE_HTML, "text/html", MtpConstants.FORMAT_HTML);
@@ -222,6 +229,11 @@
                 fileType <= LAST_PLAYLIST_FILE_TYPE);
     }
 
+    public static boolean isDrmFileType(int fileType) {
+        return (fileType >= FIRST_DRM_FILE_TYPE &&
+                fileType <= LAST_DRM_FILE_TYPE);
+    }
+
     public static MediaFileType getFileType(String path) {
         int lastDot = path.lastIndexOf(".");
         if (lastDot < 0)
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index e5fa0f8..8c3efff 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -26,6 +26,7 @@
 import android.content.IContentProvider;
 import android.database.Cursor;
 import android.database.SQLException;
+import android.drm.DrmManagerClient;
 import android.graphics.BitmapFactory;
 import android.net.Uri;
 import android.os.Process;
@@ -360,6 +361,7 @@
     private ArrayList<FileCacheEntry> mPlayLists;
     private HashMap<String, Uri> mGenreCache;
 
+    private DrmManagerClient mDrmManagerClient = null;
 
     public MediaScanner(Context c) {
         native_setup();
@@ -381,6 +383,11 @@
 
     private MyMediaScannerClient mClient = new MyMediaScannerClient();
 
+    private boolean isDrmEnabled() {
+        String prop = System.getProperty("drm.service.enabled");
+        return prop != null && prop.equals("true");
+    }
+    
     private class MyMediaScannerClient implements MediaScannerClient {
 
         private String mArtist;
@@ -447,6 +454,10 @@
                 }
             }
 
+            if (isDrmEnabled() && MediaFile.isDrmFileType(mFileType)) {
+                mFileType = getFileTypeFromDrm(path);
+            }
+
             String key = path;
             if (mCaseInsensitivePaths) {
                 key = path.toLowerCase();
@@ -874,6 +885,27 @@
             }
         }
 
+        private int getFileTypeFromDrm(String path) {
+            if (!isDrmEnabled()) {
+                return 0;
+            }
+
+            int resultFileType = 0;
+
+            if (mDrmManagerClient == null) {
+                mDrmManagerClient = new DrmManagerClient(mContext);
+            }
+
+            if (mDrmManagerClient.canHandle(path, null)) {
+                String drmMimetype = mDrmManagerClient.getOriginalMimeType(path);
+                if (drmMimetype != null) {
+                    mMimeType = drmMimetype;
+                    resultFileType = MediaFile.getFileTypeForMimeType(drmMimetype);
+                }
+            }
+            return resultFileType;
+        }
+
     }; // end of anonymous MediaScannerClient instance
 
     private void prescan(String filePath, boolean prescanFiles) throws RemoteException {
diff --git a/media/java/android/media/MtpDatabase.java b/media/java/android/media/MtpDatabase.java
index 51647434..57ab3a1 100644
--- a/media/java/android/media/MtpDatabase.java
+++ b/media/java/android/media/MtpDatabase.java
@@ -23,6 +23,7 @@
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
 import android.net.Uri;
+import android.os.Environment;
 import android.os.RemoteException;
 import android.provider.MediaStore.Audio;
 import android.provider.MediaStore.Files;
@@ -45,6 +46,7 @@
     private final String mVolumeName;
     private final Uri mObjectsUri;
     private final String mMediaStoragePath;
+    private final String mExternalStoragePath;
 
     // true if the database has been modified in the current MTP session
     private boolean mDatabaseModified;
@@ -77,7 +79,6 @@
             Files.FileColumns.DATE_MODIFIED, // 5
     };
     private static final String ID_WHERE = Files.FileColumns._ID + "=?";
-    private static final String PATH_WHERE = Files.FileColumns.DATA + "=?";
     private static final String PARENT_WHERE = Files.FileColumns.PARENT + "=?";
     private static final String PARENT_FORMAT_WHERE = PARENT_WHERE + " AND "
                                             + Files.FileColumns.FORMAT + "=?";
@@ -98,6 +99,7 @@
         mMediaProvider = context.getContentResolver().acquireProvider("media");
         mVolumeName = volumeName;
         mMediaStoragePath = storagePath;
+        mExternalStoragePath = Environment.getExternalStorageDirectory().getAbsolutePath();
         mObjectsUri = Files.getMtpObjectsUri(volumeName);
         mMediaScanner = new MediaScanner(context);
         openDevicePropertiesDatabase(context);
@@ -112,6 +114,16 @@
         }
     }
 
+    private String externalToMediaPath(String path) {
+        // convert external storage path to media path
+        if (path != null && mMediaStoragePath != null
+                && mExternalStoragePath != null
+                && path.startsWith(mExternalStoragePath)) {
+            path = mMediaStoragePath + path.substring(mExternalStoragePath.length());
+        }
+        return path;
+    }
+
     private void openDevicePropertiesDatabase(Context context) {
         mDevicePropDb = context.openOrCreateDatabase("device-properties", Context.MODE_PRIVATE, null);
         int version = mDevicePropDb.getVersion();
@@ -482,7 +494,7 @@
         try {
             c = mMediaProvider.query(mObjectsUri, PATH_PROJECTION, ID_WHERE, whereArgs, null);
             if (c != null && c.moveToNext()) {
-                path = c.getString(1);
+                path = externalToMediaPath(c.getString(1));
             }
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException in getObjectFilePath", e);
@@ -763,7 +775,7 @@
                 return true;
             }
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in getObjectProperty", e);
+            Log.e(TAG, "RemoteException in getObjectInfo", e);
         } finally {
             if (c != null) {
                 c.close();
@@ -786,7 +798,7 @@
             c = mMediaProvider.query(mObjectsUri, PATH_SIZE_PROJECTION,
                             ID_WHERE, new String[] {  Integer.toString(handle) }, null);
             if (c != null && c.moveToNext()) {
-                String path = c.getString(1);
+                String path = externalToMediaPath(c.getString(1));
                 path.getChars(0, path.length(), outFilePath, 0);
                 outFilePath[path.length()] = 0;
                 outFileLength[0] = c.getLong(2);
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index cf04e92..6954e36 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -1192,6 +1192,13 @@
     mFlags |= FIRST_FRAME;
     mSeeking = false;
     mSeekNotificationSent = false;
+
+    if (mDecryptHandle != NULL) {
+        mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
+                Playback::PAUSE, 0);
+        mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
+                Playback::START, videoTimeUs / 1000);
+    }
 }
 
 void AwesomePlayer::onVideoEvent() {
@@ -1291,17 +1298,11 @@
         mVideoTimeUs = timeUs;
     }
 
+    bool wasSeeking = mSeeking;
     finishSeekIfNecessary(timeUs);
 
     TimeSource *ts = (mFlags & AUDIO_AT_EOS) ? &mSystemTimeSource : mTimeSource;
 
-    if (mDecryptHandle != NULL) {
-        mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
-                Playback::PAUSE, 0);
-        mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
-                Playback::START, timeUs / 1000);
-    }
-
     if (mFlags & FIRST_FRAME) {
         mFlags &= ~FIRST_FRAME;
 
@@ -1318,6 +1319,11 @@
 
     int64_t latenessUs = nowUs - timeUs;
 
+    if (wasSeeking) {
+        // Let's display the first frame after seeking right away.
+        latenessUs = 0;
+    }
+
     if (mRTPSession != NULL) {
         // We'll completely ignore timestamps for gtalk videochat
         // and we'll play incoming video as fast as we get it.
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index ea5577d..0b8997c 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -32,6 +32,8 @@
 #include <media/stagefright/MediaErrors.h>
 #include <utils/String8.h>
 
+#include <cutils/properties.h>
+
 namespace android {
 
 bool DataSource::getUInt16(off_t offset, uint16_t *x) {
@@ -105,7 +107,12 @@
     RegisterSniffer(SniffAMR);
     RegisterSniffer(SniffMPEG2TS);
     RegisterSniffer(SniffMP3);
-    //RegisterSniffer(SniffDRM);
+
+    char value[PROPERTY_VALUE_MAX];
+    if (property_get("drm.service.enabled", value, NULL)
+            && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
+        RegisterSniffer(SniffDRM);
+    }
 }
 
 // static
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 9e79aa9..b3ed845 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -506,7 +506,7 @@
 }
 
 void MPEG4Writer::stopWriterThread() {
-    LOGV("stopWriterThread");
+    LOGD("Stopping writer thread");
 
     {
         Mutex::Autolock autolock(mLock);
@@ -517,6 +517,7 @@
 
     void *dummy;
     pthread_join(mThread, &dummy);
+    LOGD("Writer thread stopped");
 }
 
 status_t MPEG4Writer::stop() {
@@ -1228,6 +1229,7 @@
 }
 
 status_t MPEG4Writer::Track::stop() {
+    LOGD("Stopping %s track", mIsAudio? "Audio": "Video");
     if (mDone) {
         return OK;
     }
@@ -1239,6 +1241,7 @@
 
     status_t err = (status_t) dummy;
 
+    LOGD("Stopping %s track source", mIsAudio? "Audio": "Video");
     {
         status_t status = mSource->stop();
         if (err == OK && status != OK && status != ERROR_END_OF_STREAM) {
@@ -1246,6 +1249,7 @@
         }
     }
 
+    LOGD("%s track stopped", mIsAudio? "Audio": "Video");
     return err;
 }
 
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 0d8abe2..9e1b436 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -1710,16 +1710,11 @@
         return err;
     }
 
-    // Check that the color format is in the correct range.
-    CHECK(OMX_COLOR_FormatAndroidPrivateStart <= def.format.video.eColorFormat);
-    CHECK(def.format.video.eColorFormat < OMX_COLOR_FormatAndroidPrivateEnd);
-
     err = native_window_set_buffers_geometry(
             mNativeWindow.get(),
             def.format.video.nFrameWidth,
             def.format.video.nFrameHeight,
-            def.format.video.eColorFormat
-                - OMX_COLOR_FormatAndroidPrivateStart);
+            def.format.video.eColorFormat);
 
     if (err != 0) {
         LOGE("native_window_set_buffers_geometry failed: %s (%d)",
@@ -2109,6 +2104,17 @@
                     CODEC_LOGV(
                             "output crop (%ld, %ld, %ld, %ld)",
                             rect.nLeft, rect.nTop, rect.nWidth, rect.nHeight);
+
+                    if (mNativeWindow != NULL) {
+                        android_native_rect_t crop;
+                        crop.left = rect.nLeft;
+                        crop.top = rect.nTop;
+                        crop.right = crop.left + rect.nWidth - 1;
+                        crop.bottom = crop.top + rect.nHeight - 1;
+
+                        CHECK_EQ(0, native_window_set_crop(
+                                    mNativeWindow.get(), &crop));
+                    }
                 } else {
                     CODEC_LOGE("getConfig(OMX_IndexConfigCommonOutputCrop) "
                                "returned error 0x%08x", err);
diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp
index 1629e9f..6c05e03 100644
--- a/media/libstagefright/StagefrightMediaScanner.cpp
+++ b/media/libstagefright/StagefrightMediaScanner.cpp
@@ -39,7 +39,7 @@
         ".mp3", ".mp4", ".m4a", ".3gp", ".3gpp", ".3g2", ".3gpp2",
         ".mpeg", ".ogg", ".mid", ".smf", ".imy", ".wma", ".aac",
         ".wav", ".amr", ".midi", ".xmf", ".rtttl", ".rtx", ".ota",
-        ".mkv", ".mka", ".webm", ".ts"
+        ".mkv", ".mka", ".webm", ".ts", ".fl"
     };
     static const size_t kNumValidExtensions =
         sizeof(kValidExtensions) / sizeof(kValidExtensions[0]);
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png
new file mode 100644
index 0000000..6baf5ea
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png
Binary files differ
diff --git a/packages/SystemUI/res/layout-xlarge/status_bar.xml b/packages/SystemUI/res/layout-xlarge/status_bar.xml
index dbe4167..590132f 100644
--- a/packages/SystemUI/res/layout-xlarge/status_bar.xml
+++ b/packages/SystemUI/res/layout-xlarge/status_bar.xml
@@ -133,7 +133,7 @@
                 android:layout_height="match_parent"
                 android:paddingLeft="15dip"
                 android:paddingRight="15dip"
-                android:src="@drawable/status_bar_back"
+                android:src="@drawable/ic_sysbar_back"
                 android:background="@drawable/ic_sysbar_icon_bg"
                 systemui:keyCode="4"
                 />
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index aeb8d3c..9dfc9c3 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -248,7 +248,7 @@
 
         AlertDialog.Builder b = new AlertDialog.Builder(mContext);
             b.setCancelable(true);
-            b.setMessage(mContext.getString(R.string.invalid_charger));
+            b.setMessage(R.string.invalid_charger);
             b.setIcon(android.R.drawable.ic_dialog_alert);
             b.setPositiveButton(android.R.string.ok, null);
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LatestItemView.java b/packages/SystemUI/src/com/android/systemui/statusbar/LatestItemView.java
index 2f94af6..64ec063 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LatestItemView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LatestItemView.java
@@ -23,22 +23,11 @@
 import android.widget.FrameLayout;
 
 public class LatestItemView extends FrameLayout {
-    private boolean mDispatchTorches;
-
     public LatestItemView(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
-    public boolean dispatchTouchEvent(MotionEvent ev) {
-        if (mDispatchTorches) {
-            return super.dispatchTouchEvent(ev);
-        } else {
-            return onTouchEvent(ev);
-        }
-    }
-
     public void setOnClickListener(OnClickListener l) {
-        mDispatchTorches = l == null;
         super.setOnClickListener(l);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java
index 256386b..00b39c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java
@@ -65,7 +65,7 @@
         mCommandQueue = new CommandQueue(this, iconList);
         mBarService = IStatusBarService.Stub.asInterface(
                 ServiceManager.getService(Context.STATUS_BAR_SERVICE));
-        boolean[] switches = new boolean[3];
+        int[] switches = new int[4];
         try {
             mBarService.registerStatusBar(mCommandQueue, iconList, notificationKeys, notifications,
                     switches);
@@ -73,9 +73,10 @@
             // If the system process isn't there we're doomed anyway.
         }
 
-        setLightsOn(switches[0]);
-        setMenuKeyVisible(switches[1]);
-        setIMEButtonVisible(switches[2]);
+        disable(switches[0]);
+        setLightsOn(switches[1] != 0);
+        setMenuKeyVisible(switches[2] != 0);
+        setIMEButtonVisible(switches[3] != 0);
 
         // Set up the initial icon state
         int N = iconList.size();
@@ -118,9 +119,10 @@
         if (SPEW) {
             Slog.d(TAG, "Added status bar view: gravity=0x" + Integer.toHexString(lp.gravity) 
                    + " icons=" + iconList.size()
-                   + " lights=" + (switches[0]?"on":"off")
-                   + " menu=" + (switches[1]?"visible":"invisible")
-                   + " imeButton=" + (switches[2]?"visible":"invisible")
+                   + " disabled=0x" + Integer.toHexString(switches[0])
+                   + " lights=" + switches[1]
+                   + " menu=" + switches[2]
+                   + " imeButton=" + switches[3]
                    );
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodButton.java
index c416ff4..a025d63 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/InputMethodButton.java
@@ -16,10 +16,7 @@
 
 package com.android.systemui.statusbar.tablet;
 
-import android.content.BroadcastReceiver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
@@ -36,13 +33,12 @@
 import com.android.server.InputMethodManagerService;
 import com.android.systemui.R;
 
-import java.util.Calendar;
 import java.util.List;
-import java.util.TimeZone;
 
 public class InputMethodButton extends ImageView {
 
     private static final String  TAG = "StatusBar/InputMethodButton";
+    private static final boolean DEBUG = false;
 
     private boolean mKeyboardShown;
     private ImageView mIcon;
@@ -94,6 +90,9 @@
         InputMethodSubtype subtype = mImm.getCurrentInputMethodSubtype();
         Drawable icon = null;
         if (imi != null) {
+            if (DEBUG) {
+                Log.d(TAG, "--- Update icons of IME: " + imi.getPackageName() + "," + subtype);
+            }
             if (subtype != null) {
                 return pm.getDrawable(imi.getPackageName(), subtype.getIconResId(),
                         imi.getServiceInfo().applicationInfo);
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java b/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java
index 91dc2b2..0f1aa4e 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java
@@ -145,7 +145,7 @@
                 case KeyEvent.KEYCODE_MEDIA_PLAY:
                 case KeyEvent.KEYCODE_MEDIA_PAUSE:
                 case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
-                    /* Suppress PLAYPAUSE toggle when phone is ringing or
+                    /* Suppress PLAY/PAUSE toggle when phone is ringing or
                      * in-call to avoid music playback */
                     if (mTelephonyManager == null) {
                         mTelephonyManager = (TelephonyManager) getContext().getSystemService(
@@ -155,11 +155,13 @@
                             mTelephonyManager.getCallState() != TelephonyManager.CALL_STATE_IDLE) {
                         return true;  // suppress key event
                     }
-                case KeyEvent.KEYCODE_HEADSETHOOK: 
-                case KeyEvent.KEYCODE_MEDIA_STOP: 
-                case KeyEvent.KEYCODE_MEDIA_NEXT: 
-                case KeyEvent.KEYCODE_MEDIA_PREVIOUS: 
-                case KeyEvent.KEYCODE_MEDIA_REWIND: 
+                case KeyEvent.KEYCODE_MUTE:
+                case KeyEvent.KEYCODE_HEADSETHOOK:
+                case KeyEvent.KEYCODE_MEDIA_STOP:
+                case KeyEvent.KEYCODE_MEDIA_NEXT:
+                case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+                case KeyEvent.KEYCODE_MEDIA_REWIND:
+                case KeyEvent.KEYCODE_MEDIA_RECORD:
                 case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
                     Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
                     intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
@@ -191,12 +193,15 @@
         } else if (event.getAction() == KeyEvent.ACTION_UP) {
             switch (keyCode) {
                 case KeyEvent.KEYCODE_MUTE:
-                case KeyEvent.KEYCODE_HEADSETHOOK: 
-                case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: 
-                case KeyEvent.KEYCODE_MEDIA_STOP: 
-                case KeyEvent.KEYCODE_MEDIA_NEXT: 
-                case KeyEvent.KEYCODE_MEDIA_PREVIOUS: 
-                case KeyEvent.KEYCODE_MEDIA_REWIND: 
+                case KeyEvent.KEYCODE_HEADSETHOOK:
+                case KeyEvent.KEYCODE_MEDIA_PLAY:
+                case KeyEvent.KEYCODE_MEDIA_PAUSE:
+                case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+                case KeyEvent.KEYCODE_MEDIA_STOP:
+                case KeyEvent.KEYCODE_MEDIA_NEXT:
+                case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+                case KeyEvent.KEYCODE_MEDIA_REWIND:
+                case KeyEvent.KEYCODE_MEDIA_RECORD:
                 case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
                     Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
                     intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
index c034ec9..c870503 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
@@ -795,6 +795,7 @@
             case KeyEvent.KEYCODE_MEDIA_NEXT:
             case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
             case KeyEvent.KEYCODE_MEDIA_REWIND:
+            case KeyEvent.KEYCODE_MEDIA_RECORD:
             case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
             case KeyEvent.KEYCODE_CAMERA:
                 return false;
diff --git a/policy/src/com/android/internal/policy/impl/LockScreen.java b/policy/src/com/android/internal/policy/impl/LockScreen.java
index 1383354..4644a7c 100644
--- a/policy/src/com/android/internal/policy/impl/LockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/LockScreen.java
@@ -209,7 +209,12 @@
                 mSlidingTab.setRightHintText(mSilentMode ? R.string.lockscreen_sound_on_label
                         : R.string.lockscreen_sound_off_label);
             }
-            mCallback.pokeWakelock();
+            // Don't poke the wake lock when returning to a state where the handle is
+            // not grabbed since that can happen when the system (instead of the user)
+            // cancels the grab.
+            if (grabbedState != SlidingTab.OnTriggerListener.NO_HANDLE) {
+                mCallback.pokeWakelock();
+            }
         }
     }
 
@@ -231,10 +236,11 @@
 
         /** {@inheritDoc} */
         public void onGrabbedStateChange(View v, int grabbedState) {
+            // Don't poke the wake lock when returning to a state where the handle is
+            // not grabbed since that can happen when the system (instead of the user)
+            // cancels the grab.
             if (grabbedState == WaveView.OnTriggerListener.CENTER_HANDLE) {
                 mCallback.pokeWakelock(STAY_ON_WHILE_GRABBED_TIMEOUT);
-            } else {
-                mCallback.pokeWakelock();
             }
         }
     }
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 3691d97..e944f9d 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -627,13 +627,6 @@
             // should be executed...  do it!
             mPanelChordingKey = 0;
             mPanelMayLongPress = false;
-            InputMethodManager imm = (InputMethodManager)
-                    getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
-            if (imm != null) {
-                mDecor.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
-                imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
-            }
-            
         }
 
         return false;
@@ -1259,7 +1252,7 @@
             case KeyEvent.KEYCODE_MEDIA_PLAY:
             case KeyEvent.KEYCODE_MEDIA_PAUSE:
             case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
-                /* Suppress PLAYPAUSE toggle when phone is ringing or in-call
+                /* Suppress PLAY/PAUSE toggle when phone is ringing or in-call
                  * to avoid music playback */
                 if (mTelephonyManager == null) {
                     mTelephonyManager = (TelephonyManager) getContext().getSystemService(
@@ -1275,6 +1268,7 @@
             case KeyEvent.KEYCODE_MEDIA_NEXT:
             case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
             case KeyEvent.KEYCODE_MEDIA_REWIND:
+            case KeyEvent.KEYCODE_MEDIA_RECORD:
             case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
                 Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
                 intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
@@ -1455,6 +1449,7 @@
             }
 
             case KeyEvent.KEYCODE_HEADSETHOOK:
+            case KeyEvent.KEYCODE_MUTE:
             case KeyEvent.KEYCODE_MEDIA_PLAY:
             case KeyEvent.KEYCODE_MEDIA_PAUSE:
             case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
@@ -1462,6 +1457,7 @@
             case KeyEvent.KEYCODE_MEDIA_NEXT:
             case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
             case KeyEvent.KEYCODE_MEDIA_REWIND:
+            case KeyEvent.KEYCODE_MEDIA_RECORD:
             case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
                 Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
                 intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index cd1ad4c..e950ae5 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -54,6 +54,7 @@
 import com.android.internal.view.BaseInputHandler;
 import com.android.internal.widget.PointerLocationView;
 
+import android.telephony.TelephonyManager;
 import android.util.Config;
 import android.util.EventLog;
 import android.util.Log;
@@ -63,6 +64,7 @@
 import android.view.HapticFeedbackConstants;
 import android.view.IWindowManager;
 import android.view.InputChannel;
+import android.view.InputDevice;
 import android.view.InputQueue;
 import android.view.InputHandler;
 import android.view.KeyEvent;
@@ -84,6 +86,7 @@
 import static android.view.WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
 import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
@@ -216,7 +219,7 @@
     WindowState mKeyguard = null;
     KeyguardViewMediator mKeyguardMediator;
     GlobalActions mGlobalActions;
-    boolean mShouldTurnOffOnKeyUp;
+    volatile boolean mPowerKeyHandled;
     RecentApplicationsDialog mRecentAppsDialog;
     Handler mHandler;
     
@@ -476,28 +479,47 @@
         }
     }
 
-    Runnable mPowerLongPress = new Runnable() {
+    private void interceptPowerKeyDown(boolean handled) {
+        mPowerKeyHandled = handled;
+        if (!handled) {
+            mHandler.postDelayed(mPowerLongPress, ViewConfiguration.getGlobalActionKeyTimeout());
+        }
+    }
+
+    private boolean interceptPowerKeyUp(boolean canceled) {
+        if (!mPowerKeyHandled) {
+            mHandler.removeCallbacks(mPowerLongPress);
+            return !canceled;
+        } else {
+            mPowerKeyHandled = true;
+            return false;
+        }
+    }
+
+    private final Runnable mPowerLongPress = new Runnable() {
         public void run() {
-            // The context isn't read
-            if (mLongPressOnPowerBehavior < 0) {
-                mLongPressOnPowerBehavior = mContext.getResources().getInteger(
-                        com.android.internal.R.integer.config_longPressOnPowerBehavior);
-            }
-            switch (mLongPressOnPowerBehavior) {
-            case LONG_PRESS_POWER_NOTHING:
-                break;
-            case LONG_PRESS_POWER_GLOBAL_ACTIONS:
-                mShouldTurnOffOnKeyUp = false;
-                performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
-                sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
-                showGlobalActionsDialog();
-                break;
-            case LONG_PRESS_POWER_SHUT_OFF:
-                mShouldTurnOffOnKeyUp = false;
-                performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
-                sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
-                ShutdownThread.shutdown(mContext, true);
-                break;
+            if (!mPowerKeyHandled) {
+                // The context isn't read
+                if (mLongPressOnPowerBehavior < 0) {
+                    mLongPressOnPowerBehavior = mContext.getResources().getInteger(
+                            com.android.internal.R.integer.config_longPressOnPowerBehavior);
+                }
+                switch (mLongPressOnPowerBehavior) {
+                case LONG_PRESS_POWER_NOTHING:
+                    break;
+                case LONG_PRESS_POWER_GLOBAL_ACTIONS:
+                    mPowerKeyHandled = true;
+                    performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
+                    sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
+                    showGlobalActionsDialog();
+                    break;
+                case LONG_PRESS_POWER_SHUT_OFF:
+                    mPowerKeyHandled = true;
+                    performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
+                    sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
+                    ShutdownThread.shutdown(mContext, true);
+                    break;
+                }
             }
         }
     };
@@ -1110,12 +1132,22 @@
                 com.android.internal.R.anim.lock_screen_behind_enter);
     }
     
-    static ITelephony getPhoneInterface() {
-        return ITelephony.Stub.asInterface(ServiceManager.checkService(Context.TELEPHONY_SERVICE));
+    static ITelephony getTelephonyService() {
+        ITelephony telephonyService = ITelephony.Stub.asInterface(
+                ServiceManager.checkService(Context.TELEPHONY_SERVICE));
+        if (telephonyService == null) {
+            Log.w(TAG, "Unable to find ITelephony interface.");
+        }
+        return telephonyService;
     }
 
-    static IAudioService getAudioInterface() {
-        return IAudioService.Stub.asInterface(ServiceManager.checkService(Context.AUDIO_SERVICE));
+    static IAudioService getAudioService() {
+        IAudioService audioService = IAudioService.Stub.asInterface(
+                ServiceManager.checkService(Context.AUDIO_SERVICE));
+        if (audioService == null) {
+            Log.w(TAG, "Unable to find IAudioService interface.");
+        }
+        return audioService;
     }
 
     boolean keyguardOn() {
@@ -1130,7 +1162,7 @@
     /** {@inheritDoc} */
     @Override
     public boolean interceptKeyBeforeDispatching(WindowState win, int action, int flags,
-            int keyCode, int metaState, int repeatCount, int policyFlags) {
+            int keyCode, int scanCode, int metaState, int repeatCount, int policyFlags) {
         final boolean keyguardOn = keyguardOn();
         final boolean down = (action == KeyEvent.ACTION_DOWN);
         final boolean canceled = ((flags & KeyEvent.FLAG_CANCELED) != 0);
@@ -1163,11 +1195,9 @@
                         // and his ONLY options are to answer or reject the call.)
                         boolean incomingRinging = false;
                         try {
-                            ITelephony phoneServ = getPhoneInterface();
-                            if (phoneServ != null) {
-                                incomingRinging = phoneServ.isRinging();
-                            } else {
-                                Log.w(TAG, "Unable to find ITelephony interface");
+                            ITelephony telephonyService = getTelephonyService();
+                            if (telephonyService != null) {
+                                incomingRinging = telephonyService.isRinging();
                             }
                         } catch (RemoteException ex) {
                             Log.w(TAG, "RemoteException from getPhoneInterface()", ex);
@@ -1386,7 +1416,7 @@
         }
     }
 
-    void setAttachedWindowFrames(WindowState win, int fl, int sim,
+    void setAttachedWindowFrames(WindowState win, int fl, int adjust,
             WindowState attached, boolean insetDecors, Rect pf, Rect df, Rect cf, Rect vf) {
         if (win.getSurfaceLayer() > mDockLayer && attached.getSurfaceLayer() < mDockLayer) {
             // Here's a special case: if this attached window is a panel that is
@@ -1407,7 +1437,7 @@
             // window is positioned within that content.  Otherwise we can use
             // the display frame and let the attached window take care of
             // positioning its content appropriately.
-            if ((sim & SOFT_INPUT_MASK_ADJUST) != SOFT_INPUT_ADJUST_RESIZE) {
+            if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
                 cf.set(attached.getDisplayFrameLw());
             } else {
                 // If the window is resizing, then we want to base the content
@@ -1466,6 +1496,8 @@
             attrs.gravity = Gravity.BOTTOM;
             mDockLayer = win.getSurfaceLayer();
         } else {
+            final int adjust = sim & SOFT_INPUT_MASK_ADJUST;
+
             if ((fl & (FLAG_LAYOUT_IN_SCREEN | FLAG_FULLSCREEN | FLAG_LAYOUT_INSET_DECOR))
                     == (FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR)) {
                 // This is the case for a normal activity window: we want it
@@ -1481,7 +1513,7 @@
                     pf.top = df.top = mScreenTop;
                     pf.right = df.right = mScreenLeft+mScreenWidth;
                     pf.bottom = df.bottom = mScreenTop+mScreenHeight;
-                    if ((sim & SOFT_INPUT_MASK_ADJUST) != SOFT_INPUT_ADJUST_RESIZE) {
+                    if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
                         cf.left = mDockLeft;
                         cf.top = mDockTop;
                         cf.right = mDockRight;
@@ -1492,10 +1524,14 @@
                         cf.right = mContentRight;
                         cf.bottom = mContentBottom;
                     }
-                    vf.left = mCurLeft;
-                    vf.top = mCurTop;
-                    vf.right = mCurRight;
-                    vf.bottom = mCurBottom;
+                    if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
+                        vf.left = mCurLeft;
+                        vf.top = mCurTop;
+                        vf.right = mCurRight;
+                        vf.bottom = mCurBottom;
+                    } else {
+                        vf.set(cf);
+                    }
                 }
             } else if ((fl & FLAG_LAYOUT_IN_SCREEN) != 0) {
                 // A window that has requested to fill the entire screen just
@@ -1504,14 +1540,18 @@
                 pf.top = df.top = cf.top = mScreenTop;
                 pf.right = df.right = cf.right = mScreenLeft+mScreenWidth;
                 pf.bottom = df.bottom = cf.bottom = mScreenTop+mScreenHeight;
-                vf.left = mCurLeft;
-                vf.top = mCurTop;
-                vf.right = mCurRight;
-                vf.bottom = mCurBottom;
+                if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
+                    vf.left = mCurLeft;
+                    vf.top = mCurTop;
+                    vf.right = mCurRight;
+                    vf.bottom = mCurBottom;
+                } else {
+                    vf.set(cf);
+                }
             } else if (attached != null) {
                 // A child window should be placed inside of the same visible
                 // frame that its parent had.
-                setAttachedWindowFrames(win, fl, sim, attached, false, pf, df, cf, vf);
+                setAttachedWindowFrames(win, fl, adjust, attached, false, pf, df, cf, vf);
             } else {
                 // Otherwise, a normal window must be placed inside the content
                 // of all screen decorations.
@@ -1519,7 +1559,7 @@
                 pf.top = mContentTop;
                 pf.right = mContentRight;
                 pf.bottom = mContentBottom;
-                if ((sim & SOFT_INPUT_MASK_ADJUST) != SOFT_INPUT_ADJUST_RESIZE) {
+                if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
                     df.left = cf.left = mDockLeft;
                     df.top = cf.top = mDockTop;
                     df.right = cf.right = mDockRight;
@@ -1530,10 +1570,14 @@
                     df.right = cf.right = mContentRight;
                     df.bottom = cf.bottom = mContentBottom;
                 }
-                vf.left = mCurLeft;
-                vf.top = mCurTop;
-                vf.right = mCurRight;
-                vf.bottom = mCurBottom;
+                if (adjust != SOFT_INPUT_ADJUST_NOTHING) {
+                    vf.left = mCurLeft;
+                    vf.top = mCurTop;
+                    vf.right = mCurRight;
+                    vf.bottom = mCurBottom;
+                } else {
+                    vf.set(cf);
+                }
             }
         }
         
@@ -1809,23 +1853,6 @@
     }
 
     /**
-     * @return Whether a telephone call is in progress right now.
-     */
-    boolean isInCall() {
-        final ITelephony phone = getPhoneInterface();
-        if (phone == null) {
-            Log.w(TAG, "couldn't get ITelephony reference");
-            return false;
-        }
-        try {
-            return phone.isOffhook();
-        } catch (RemoteException e) {
-            Log.w(TAG, "ITelephony.isOffhhook threw RemoteException " + e);
-            return false;
-        }
-    }
-
-    /**
      * @return Whether music is being played right now.
      */
     boolean isMusicActive() {
@@ -1842,9 +1869,8 @@
      * @param keycode
      */
     void handleVolumeKey(int stream, int keycode) {
-        final IAudioService audio = getAudioInterface();
-        if (audio == null) {
-            Log.w(TAG, "handleVolumeKey: couldn't get IAudioService reference");
+        IAudioService audioService = getAudioService();
+        if (audioService == null) {
             return;
         }
         try {
@@ -1852,7 +1878,7 @@
             // during the call, but we do it as a precaution for the rare possibility
             // that the music stops right before we call this
             mBroadcastWakeLock.acquire();
-            audio.adjustStreamVolume(stream,
+            audioService.adjustStreamVolume(stream,
                 keycode == KeyEvent.KEYCODE_VOLUME_UP
                             ? AudioManager.ADJUST_RAISE
                             : AudioManager.ADJUST_LOWER,
@@ -1863,41 +1889,15 @@
             mBroadcastWakeLock.release();
         }
     }
-    
-    static boolean isMediaKey(int code) {
-        if (code == KeyEvent.KEYCODE_HEADSETHOOK || 
-                code == KeyEvent.KEYCODE_MEDIA_PLAY ||
-                code == KeyEvent.KEYCODE_MEDIA_PAUSE ||
-                code == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE ||
-                code == KeyEvent.KEYCODE_MEDIA_STOP || 
-                code == KeyEvent.KEYCODE_MEDIA_NEXT ||
-                code == KeyEvent.KEYCODE_MEDIA_PREVIOUS || 
-                code == KeyEvent.KEYCODE_MEDIA_REWIND ||
-                code == KeyEvent.KEYCODE_MEDIA_FAST_FORWARD) {
-            return true;
-        }
-        return false;    
-    }
- 
+
     /** {@inheritDoc} */
     @Override
-    public int interceptKeyBeforeQueueing(long whenNanos, int keyCode, boolean down,
-            int policyFlags, boolean isScreenOn) {
-        int result = ACTION_PASS_TO_USER;
+    public int interceptKeyBeforeQueueing(long whenNanos, int action, int flags,
+            int keyCode, int scanCode, int policyFlags, boolean isScreenOn) {
+        final boolean down = action == KeyEvent.ACTION_DOWN;
+        final boolean canceled = (flags & KeyEvent.FLAG_CANCELED) != 0;
 
-        if (down && (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0) {
-            performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
-        }
-
-        final boolean isWakeKey = (policyFlags
-                & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
-
-        // If the key is injected, pretend that the screen is on and don't let the
-        // device go to sleep.  This feature is mainly used for testing purposes.
         final boolean isInjected = (policyFlags & WindowManagerPolicy.FLAG_INJECTED) != 0;
-        if (isInjected) {
-            isScreenOn = true;
-        }
 
         // If screen is off then we treat the case where the keyguard is open but hidden
         // the same as if it were open and in front.
@@ -1912,202 +1912,210 @@
                   + " screenIsOn=" + isScreenOn + " keyguardActive=" + keyguardActive);
         }
 
-        if (keyguardActive) {
-            if (isScreenOn) {
-                // when the screen is on, always give the event to the keyguard
-                result |= ACTION_PASS_TO_USER;
-            } else {
-                // otherwise, don't pass it to the user
-                result &= ~ACTION_PASS_TO_USER;
+        if (down && (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0) {
+            performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
+        }
 
-                if (isWakeKey && down) {
+        // Basic policy based on screen state and keyguard.
+        // FIXME: This policy isn't quite correct.  We shouldn't care whether the screen
+        //        is on or off, really.  We should care about whether the device is in an
+        //        interactive state or is in suspend pretending to be "off".
+        //        The primary screen might be turned off due to proximity sensor or
+        //        because we are presenting media on an auxiliary screen or remotely controlling
+        //        the device some other way (which is why we have an exemption here for injected
+        //        events).
+        int result;
+        if (isScreenOn || isInjected) {
+            // When the screen is on or if the key is injected pass the key to the application.
+            result = ACTION_PASS_TO_USER;
+        } else {
+            // When the screen is off and the key is not injected, determine whether
+            // to wake the device but don't pass the key to the application.
+            result = 0;
 
-                    // tell the mediator about a wake key, it may decide to
-                    // turn on the screen depending on whether the key is
-                    // appropriate.
-                    if (!mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(keyCode)
-                            && (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
-                                || keyCode == KeyEvent.KEYCODE_VOLUME_UP)) {
-                        // when keyguard is showing and screen off, we need
-                        // to handle the volume key for calls and  music here
-                        if (isInCall()) {
-                            handleVolumeKey(AudioManager.STREAM_VOICE_CALL, keyCode);
-                        } else if (isMusicActive()) {
-                            handleVolumeKey(AudioManager.STREAM_MUSIC, keyCode);
-                        }
-                    }
+            final boolean isWakeKey = (policyFlags
+                    & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
+            if (down && isWakeKey) {
+                if (keyguardActive) {
+                    // If the keyguard is showing, let it decide what to do with the wake key.
+                    mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(keyCode);
+                } else {
+                    // Otherwise, wake the device ourselves.
+                    result |= ACTION_POKE_USER_ACTIVITY;
                 }
             }
-        } else if (!isScreenOn) {
-            // If we are in-call with screen off and keyguard is not showing,
-            // then handle the volume key ourselves.
-            // This is necessary because the phone app will disable the keyguard
-            // when the proximity sensor is in use.
-            if (isInCall() &&
-                     (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
-                                || keyCode == KeyEvent.KEYCODE_VOLUME_UP)) {
-                result &= ~ACTION_PASS_TO_USER;
-                handleVolumeKey(AudioManager.STREAM_VOICE_CALL, keyCode);
-            }
-            if (isWakeKey) {
-                // a wake key has a sole purpose of waking the device; don't pass
-                // it to the user
-                result |= ACTION_POKE_USER_ACTIVITY;
-                result &= ~ACTION_PASS_TO_USER;
-            }
         }
 
-        if (keyCode == KeyEvent.KEYCODE_ENDCALL
-                || keyCode == KeyEvent.KEYCODE_POWER) {
-            if (down) {
-                boolean handled = false;
-                boolean hungUp = false;
-                // key repeats are generated by the window manager, and we don't see them
-                // here, so unless the driver is doing something it shouldn't be, we know
-                // this is the real press event.
-                ITelephony phoneServ = getPhoneInterface();
-                if (phoneServ != null) {
-                    try {
-                        if (keyCode == KeyEvent.KEYCODE_ENDCALL) {
-                            handled = hungUp = phoneServ.endCall();
-                        } else if (keyCode == KeyEvent.KEYCODE_POWER) {
-                            if (phoneServ.isRinging()) {
-                                // Pressing Power while there's a ringing incoming
-                                // call should silence the ringer.
-                                phoneServ.silenceRinger();
-                                handled = true;
-                            } else if (phoneServ.isOffhook() &&
-                                       ((mIncallPowerBehavior
-                                         & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP)
-                                        != 0)) {
-                                // Otherwise, if "Power button ends call" is enabled,
-                                // the Power button will hang up any current active call.
-                                handled = hungUp = phoneServ.endCall();
+        // Handle special keys.
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_VOLUME_DOWN:
+            case KeyEvent.KEYCODE_VOLUME_UP: {
+                if (down) {
+                    ITelephony telephonyService = getTelephonyService();
+                    if (telephonyService != null) {
+                        try {
+                            if (telephonyService.isRinging()) {
+                                // If an incoming call is ringing, either VOLUME key means
+                                // "silence ringer".  We handle these keys here, rather than
+                                // in the InCallScreen, to make sure we'll respond to them
+                                // even if the InCallScreen hasn't come to the foreground yet.
+                                // Look for the DOWN event here, to agree with the "fallback"
+                                // behavior in the InCallScreen.
+                                Log.i(TAG, "interceptKeyBeforeQueueing:"
+                                      + " VOLUME key-down while ringing: Silence ringer!");
+
+                                // Silence the ringer.  (It's safe to call this
+                                // even if the ringer has already been silenced.)
+                                telephonyService.silenceRinger();
+
+                                // And *don't* pass this key thru to the current activity
+                                // (which is probably the InCallScreen.)
+                                result &= ~ACTION_PASS_TO_USER;
+                                break;
+                            }
+                            if (telephonyService.isOffhook()
+                                    && (result & ACTION_PASS_TO_USER) == 0) {
+                                // If we are in call but we decided not to pass the key to
+                                // the application, handle the volume change here.
+                                handleVolumeKey(AudioManager.STREAM_VOICE_CALL, keyCode);
+                                break;
+                            }
+                        } catch (RemoteException ex) {
+                            Log.w(TAG, "ITelephony threw RemoteException", ex);
+                        }
+                    }
+
+                    if (isMusicActive() && (result & ACTION_PASS_TO_USER) == 0) {
+                        // If music is playing but we decided not to pass the key to the
+                        // application, handle the volume change here.
+                        handleVolumeKey(AudioManager.STREAM_MUSIC, keyCode);
+                        break;
+                    }
+                }
+                break;
+            }
+
+            case KeyEvent.KEYCODE_ENDCALL: {
+                result &= ~ACTION_PASS_TO_USER;
+                if (down) {
+                    ITelephony telephonyService = getTelephonyService();
+                    boolean hungUp = false;
+                    if (telephonyService != null) {
+                        try {
+                            hungUp = telephonyService.endCall();
+                        } catch (RemoteException ex) {
+                            Log.w(TAG, "ITelephony threw RemoteException", ex);
+                        }
+                    }
+                    interceptPowerKeyDown(!isScreenOn || hungUp);
+                } else {
+                    if (interceptPowerKeyUp(canceled)) {
+                        if ((mEndcallBehavior
+                                & Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0) {
+                            if (goHome()) {
+                                break;
                             }
                         }
-                    } catch (RemoteException ex) {
-                        Log.w(TAG, "ITelephony threw RemoteException" + ex);
+                        if ((mEndcallBehavior
+                                & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) {
+                            result = (result & ~ACTION_POKE_USER_ACTIVITY) | ACTION_GO_TO_SLEEP;
+                        }
                     }
+                }
+                break;
+            }
+
+            case KeyEvent.KEYCODE_POWER: {
+                result &= ~ACTION_PASS_TO_USER;
+                if (down) {
+                    ITelephony telephonyService = getTelephonyService();
+                    boolean hungUp = false;
+                    if (telephonyService != null) {
+                        try {
+                            if (telephonyService.isRinging()) {
+                                // Pressing Power while there's a ringing incoming
+                                // call should silence the ringer.
+                                telephonyService.silenceRinger();
+                            } else if ((mIncallPowerBehavior
+                                    & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0
+                                    && telephonyService.isOffhook()) {
+                                // Otherwise, if "Power button ends call" is enabled,
+                                // the Power button will hang up any current active call.
+                                hungUp = telephonyService.endCall();
+                            }
+                        } catch (RemoteException ex) {
+                            Log.w(TAG, "ITelephony threw RemoteException", ex);
+                        }
+                    }
+                    interceptPowerKeyDown(!isScreenOn || hungUp);
                 } else {
-                    Log.w(TAG, "!!! Unable to find ITelephony interface !!!");
-                }
-
-                if (!isScreenOn
-                        || (handled && keyCode != KeyEvent.KEYCODE_POWER)
-                        || (handled && hungUp && keyCode == KeyEvent.KEYCODE_POWER)) {
-                    mShouldTurnOffOnKeyUp = false;
-                } else {
-                    // Only try to turn off the screen if we didn't already hang up.
-                    mShouldTurnOffOnKeyUp = true;
-                    mHandler.postDelayed(mPowerLongPress,
-                            ViewConfiguration.getGlobalActionKeyTimeout());
-                    result &= ~ACTION_PASS_TO_USER;
-                }
-            } else {
-                mHandler.removeCallbacks(mPowerLongPress);
-                if (mShouldTurnOffOnKeyUp) {
-                    mShouldTurnOffOnKeyUp = false;
-                    boolean gohome, sleeps;
-                    if (keyCode == KeyEvent.KEYCODE_ENDCALL) {
-                        gohome = (mEndcallBehavior
-                                  & Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0;
-                        sleeps = (mEndcallBehavior
-                                  & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0;
-                    } else {
-                        gohome = false;
-                        sleeps = true;
+                    if (interceptPowerKeyUp(canceled)) {
+                        result = (result & ~ACTION_POKE_USER_ACTIVITY) | ACTION_GO_TO_SLEEP;
                     }
-                    if (keyguardActive
-                            || (sleeps && !gohome)
-                            || (gohome && !goHome() && sleeps)) {
-                        // They must already be on the keyguard or home screen,
-                        // go to sleep instead unless the event was injected.
-                        if (!isInjected) {
-                            Log.d(TAG, "I'm tired mEndcallBehavior=0x"
-                                    + Integer.toHexString(mEndcallBehavior));
-                            result &= ~ACTION_POKE_USER_ACTIVITY;
-                            result |= ACTION_GO_TO_SLEEP;
+                }
+                break;
+            }
+
+            case KeyEvent.KEYCODE_MEDIA_PLAY:
+            case KeyEvent.KEYCODE_MEDIA_PAUSE:
+            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+                if (down) {
+                    ITelephony telephonyService = getTelephonyService();
+                    if (telephonyService != null) {
+                        try {
+                            if (!telephonyService.isIdle()) {
+                                // Suppress PLAY/PAUSE toggle when phone is ringing or in-call
+                                // to avoid music playback.
+                                break;
+                            }
+                        } catch (RemoteException ex) {
+                            Log.w(TAG, "ITelephony threw RemoteException", ex);
                         }
                     }
-                    result &= ~ACTION_PASS_TO_USER;
                 }
+            case KeyEvent.KEYCODE_HEADSETHOOK:
+            case KeyEvent.KEYCODE_MUTE:
+            case KeyEvent.KEYCODE_MEDIA_STOP:
+            case KeyEvent.KEYCODE_MEDIA_NEXT:
+            case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+            case KeyEvent.KEYCODE_MEDIA_REWIND:
+            case KeyEvent.KEYCODE_MEDIA_RECORD:
+            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
+                if ((result & ACTION_PASS_TO_USER) == 0) {
+                    // Only do this if we would otherwise not pass it to the user. In that
+                    // case, the PhoneWindow class will do the same thing, except it will
+                    // only do it if the showing app doesn't process the key on its own.
+                    long when = whenNanos / 1000000;
+                    KeyEvent keyEvent = new KeyEvent(when, when, action, keyCode, 0, 0,
+                            0, scanCode, flags, InputDevice.SOURCE_KEYBOARD);
+                    mBroadcastWakeLock.acquire();
+                    mHandler.post(new PassHeadsetKey(keyEvent));
+                }
+                break;
             }
-        } else if (isMediaKey(keyCode)) {
-            // This key needs to be handled even if the screen is off.
-            // If others need to be handled while it's off, this is a reasonable
-            // pattern to follow.
-            if ((result & ACTION_PASS_TO_USER) == 0) {
-                // Only do this if we would otherwise not pass it to the user. In that
-                // case, the PhoneWindow class will do the same thing, except it will
-                // only do it if the showing app doesn't process the key on its own.
-                long when = whenNanos / 1000000;
-                KeyEvent keyEvent = new KeyEvent(when, when,
-                        down ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP,
-                        keyCode, 0);
-                mBroadcastWakeLock.acquire();
-                mHandler.post(new PassHeadsetKey(keyEvent));
-            }
-        } else if (keyCode == KeyEvent.KEYCODE_CALL) {
-            // If an incoming call is ringing, answer it!
-            // (We handle this key here, rather than in the InCallScreen, to make
-            // sure we'll respond to the key even if the InCallScreen hasn't come to
-            // the foreground yet.)
 
-            // We answer the call on the DOWN event, to agree with
-            // the "fallback" behavior in the InCallScreen.
-            if (down) {
-                try {
-                    ITelephony phoneServ = getPhoneInterface();
-                    if (phoneServ != null) {
-                        if (phoneServ.isRinging()) {
-                            Log.i(TAG, "interceptKeyTq:"
-                                  + " CALL key-down while ringing: Answer the call!");
-                            phoneServ.answerRingingCall();
+            case KeyEvent.KEYCODE_CALL: {
+                if (down) {
+                    ITelephony telephonyService = getTelephonyService();
+                    if (telephonyService != null) {
+                        try {
+                            if (telephonyService.isRinging()) {
+                                Log.i(TAG, "interceptKeyBeforeQueueing:"
+                                      + " CALL key-down while ringing: Answer the call!");
+                                telephonyService.answerRingingCall();
 
-                            // And *don't* pass this key thru to the current activity
-                            // (which is presumably the InCallScreen.)
-                            result &= ~ACTION_PASS_TO_USER;
+                                // And *don't* pass this key thru to the current activity
+                                // (which is presumably the InCallScreen.)
+                                result &= ~ACTION_PASS_TO_USER;
+                            }
+                        } catch (RemoteException ex) {
+                            Log.w(TAG, "ITelephony threw RemoteException", ex);
                         }
-                    } else {
-                        Log.w(TAG, "CALL button: Unable to find ITelephony interface");
                     }
-                } catch (RemoteException ex) {
-                    Log.w(TAG, "CALL button: RemoteException from getPhoneInterface()", ex);
                 }
-            }
-        } else if ((keyCode == KeyEvent.KEYCODE_VOLUME_UP)
-                   || (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)) {
-            // If an incoming call is ringing, either VOLUME key means
-            // "silence ringer".  We handle these keys here, rather than
-            // in the InCallScreen, to make sure we'll respond to them
-            // even if the InCallScreen hasn't come to the foreground yet.
-
-            // Look for the DOWN event here, to agree with the "fallback"
-            // behavior in the InCallScreen.
-            if (down) {
-                try {
-                    ITelephony phoneServ = getPhoneInterface();
-                    if (phoneServ != null) {
-                        if (phoneServ.isRinging()) {
-                            Log.i(TAG, "interceptKeyTq:"
-                                  + " VOLUME key-down while ringing: Silence ringer!");
-                            // Silence the ringer.  (It's safe to call this
-                            // even if the ringer has already been silenced.)
-                            phoneServ.silenceRinger();
-
-                            // And *don't* pass this key thru to the current activity
-                            // (which is probably the InCallScreen.)
-                            result &= ~ACTION_PASS_TO_USER;
-                        }
-                    } else {
-                        Log.w(TAG, "VOLUME button: Unable to find ITelephony interface");
-                    }
-                } catch (RemoteException ex) {
-                    Log.w(TAG, "VOLUME button: RemoteException from getPhoneInterface()", ex);
-                }
+                break;
             }
         }
-
         return result;
     }
 
diff --git a/services/audioflinger/AudioPolicyManagerBase.cpp b/services/audioflinger/AudioPolicyManagerBase.cpp
index 65d9ef7..86d4c9f 100644
--- a/services/audioflinger/AudioPolicyManagerBase.cpp
+++ b/services/audioflinger/AudioPolicyManagerBase.cpp
@@ -356,7 +356,9 @@
         break;
     case AudioSystem::FOR_MEDIA:
         if (config != AudioSystem::FORCE_HEADPHONES && config != AudioSystem::FORCE_BT_A2DP &&
-            config != AudioSystem::FORCE_WIRED_ACCESSORY && config != AudioSystem::FORCE_NONE) {
+            config != AudioSystem::FORCE_WIRED_ACCESSORY &&
+            config != AudioSystem::FORCE_ANALOG_DOCK &&
+            config != AudioSystem::FORCE_DIGITAL_DOCK && config != AudioSystem::FORCE_NONE) {
             LOGW("setForceUse() invalid config %d for FOR_MEDIA", config);
             return;
         }
@@ -372,7 +374,10 @@
         break;
     case AudioSystem::FOR_DOCK:
         if (config != AudioSystem::FORCE_NONE && config != AudioSystem::FORCE_BT_CAR_DOCK &&
-            config != AudioSystem::FORCE_BT_DESK_DOCK && config != AudioSystem::FORCE_WIRED_ACCESSORY) {
+            config != AudioSystem::FORCE_BT_DESK_DOCK &&
+            config != AudioSystem::FORCE_WIRED_ACCESSORY &&
+            config != AudioSystem::FORCE_ANALOG_DOCK &&
+            config != AudioSystem::FORCE_DIGITAL_DOCK) {
             LOGW("setForceUse() invalid config %d for FOR_DOCK", config);
         }
         forceVolumeReeval = true;
@@ -1366,6 +1371,7 @@
 
 void AudioPolicyManagerBase::closeA2dpOutputs()
 {
+
     LOGV("setDeviceConnectionState() closing A2DP and duplicated output!");
 
     if (mDuplicatedOutput != 0) {
@@ -1558,6 +1564,8 @@
             if (device) break;
             device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET;
             if (device) break;
+            device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET;
+            if (device) break;
 #ifdef WITH_A2DP
             // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP
             if (mPhoneState != AudioSystem::MODE_IN_CALL) {
@@ -1617,6 +1625,12 @@
         if (device2 == 0) {
             device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET;
         }
+        if (device2 == 0) {
+            device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET;
+        }
+        if (device2 == 0) {
+            device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET;
+        }
 #ifdef WITH_A2DP
         if (mA2dpOutput != 0) {
             if (strategy == STRATEGY_SONIFICATION && !a2dpUsedForSonification()) {
@@ -1797,7 +1811,9 @@
         (AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP |
         AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
         AudioSystem::DEVICE_OUT_WIRED_HEADSET |
-        AudioSystem::DEVICE_OUT_WIRED_HEADPHONE)) &&
+        AudioSystem::DEVICE_OUT_WIRED_HEADPHONE |
+        AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET |
+        AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)) &&
         (getStrategy((AudioSystem::stream_type)stream) == STRATEGY_SONIFICATION) &&
         streamDesc.mCanBeMuted) {
         volume *= SONIFICATION_HEADSET_VOLUME_FACTOR;
diff --git a/services/java/com/android/server/DockObserver.java b/services/java/com/android/server/DockObserver.java
index bee8872..f993093 100644
--- a/services/java/com/android/server/DockObserver.java
+++ b/services/java/com/android/server/DockObserver.java
@@ -103,7 +103,6 @@
             FileReader file = new FileReader(DOCK_STATE_PATH);
             int len = file.read(buffer, 0, 1024);
             mPreviousDockState = mDockState = Integer.valueOf((new String(buffer, 0, len)).trim());
-
         } catch (FileNotFoundException e) {
             Slog.w(TAG, "This kernel does not have dock station support");
         } catch (Exception e) {
@@ -158,13 +157,17 @@
                         {
                             String whichSound = null;
                             if (mDockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) {
-                                if (mPreviousDockState == Intent.EXTRA_DOCK_STATE_DESK) {
+                                if ((mPreviousDockState == Intent.EXTRA_DOCK_STATE_DESK) ||
+                                    (mPreviousDockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
+                                    (mPreviousDockState == Intent.EXTRA_DOCK_STATE_HE_DESK)) {
                                     whichSound = Settings.System.DESK_UNDOCK_SOUND;
                                 } else if (mPreviousDockState == Intent.EXTRA_DOCK_STATE_CAR) {
                                     whichSound = Settings.System.CAR_UNDOCK_SOUND;
                                 }
                             } else {
-                                if (mDockState == Intent.EXTRA_DOCK_STATE_DESK) {
+                                if ((mDockState == Intent.EXTRA_DOCK_STATE_DESK) ||
+                                    (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
+                                    (mDockState == Intent.EXTRA_DOCK_STATE_HE_DESK)) {
                                     whichSound = Settings.System.DESK_DOCK_SOUND;
                                 } else if (mDockState == Intent.EXTRA_DOCK_STATE_CAR) {
                                     whichSound = Settings.System.CAR_DOCK_SOUND;
diff --git a/services/java/com/android/server/HeadsetObserver.java b/services/java/com/android/server/HeadsetObserver.java
deleted file mode 100644
index 6f0a91d..0000000
--- a/services/java/com/android/server/HeadsetObserver.java
+++ /dev/null
@@ -1,183 +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 com.android.server;
-
-import android.app.ActivityManagerNative;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Handler;
-import android.os.Message;
-import android.os.PowerManager;
-import android.os.PowerManager.WakeLock;
-import android.os.UEventObserver;
-import android.util.Slog;
-import android.media.AudioManager;
-
-import java.io.FileReader;
-import java.io.FileNotFoundException;
-
-/**
- * <p>HeadsetObserver monitors for a wired headset.
- */
-class HeadsetObserver extends UEventObserver {
-    private static final String TAG = HeadsetObserver.class.getSimpleName();
-    private static final boolean LOG = true;
-
-    private static final String HEADSET_UEVENT_MATCH = "DEVPATH=/devices/virtual/switch/h2w";
-    private static final String HEADSET_STATE_PATH = "/sys/class/switch/h2w/state";
-    private static final String HEADSET_NAME_PATH = "/sys/class/switch/h2w/name";
-
-    private static final int BIT_HEADSET = (1 << 0);
-    private static final int BIT_HEADSET_NO_MIC = (1 << 1);
-    private static final int SUPPORTED_HEADSETS = (BIT_HEADSET|BIT_HEADSET_NO_MIC);
-    private static final int HEADSETS_WITH_MIC = BIT_HEADSET;
-
-    private int mHeadsetState;
-    private int mPrevHeadsetState;
-    private String mHeadsetName;
-
-    private final Context mContext;
-    private final WakeLock mWakeLock;  // held while there is a pending route change
-
-    public HeadsetObserver(Context context) {
-        mContext = context;
-        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
-        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "HeadsetObserver");
-        mWakeLock.setReferenceCounted(false);
-
-        startObserving(HEADSET_UEVENT_MATCH);
-
-        init();  // set initial status
-    }
-
-    @Override
-    public void onUEvent(UEventObserver.UEvent event) {
-        if (LOG) Slog.v(TAG, "Headset UEVENT: " + event.toString());
-
-        try {
-            update(event.get("SWITCH_NAME"), Integer.parseInt(event.get("SWITCH_STATE")));
-        } catch (NumberFormatException e) {
-            Slog.e(TAG, "Could not parse switch state from event " + event);
-        }
-    }
-
-    private synchronized final void init() {
-        char[] buffer = new char[1024];
-
-        String newName = mHeadsetName;
-        int newState = mHeadsetState;
-        mPrevHeadsetState = mHeadsetState;
-        try {
-            FileReader file = new FileReader(HEADSET_STATE_PATH);
-            int len = file.read(buffer, 0, 1024);
-            newState = Integer.valueOf((new String(buffer, 0, len)).trim());
-
-            file = new FileReader(HEADSET_NAME_PATH);
-            len = file.read(buffer, 0, 1024);
-            newName = new String(buffer, 0, len).trim();
-
-        } catch (FileNotFoundException e) {
-            Slog.w(TAG, "This kernel does not have wired headset support");
-        } catch (Exception e) {
-            Slog.e(TAG, "" , e);
-        }
-
-        update(newName, newState);
-    }
-
-    private synchronized final void update(String newName, int newState) {
-        // Retain only relevant bits
-        int headsetState = newState & SUPPORTED_HEADSETS;
-        int newOrOld = headsetState | mHeadsetState;
-        int delay = 0;
-        // reject all suspect transitions: only accept state changes from:
-        // - a: 0 heaset to 1 headset
-        // - b: 1 headset to 0 headset
-        if (mHeadsetState == headsetState || ((newOrOld & (newOrOld - 1)) != 0)) {
-            return;
-        }
-
-        mHeadsetName = newName;
-        mPrevHeadsetState = mHeadsetState;
-        mHeadsetState = headsetState;
-
-        if (headsetState == 0) {
-            Intent intent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
-            mContext.sendBroadcast(intent);
-            // It can take hundreds of ms flush the audio pipeline after
-            // apps pause audio playback, but audio route changes are
-            // immediate, so delay the route change by 1000ms.
-            // This could be improved once the audio sub-system provides an
-            // interface to clear the audio pipeline.
-            delay = 1000;
-        } else {
-            // Insert the same delay for headset connection so that the connection event is not
-            // broadcast before the disconnection event in case of fast removal/insertion
-            if (mHandler.hasMessages(0)) {
-                delay = 1000;
-            }
-        }
-        mWakeLock.acquire();
-        mHandler.sendMessageDelayed(mHandler.obtainMessage(0,
-                                                           mHeadsetState,
-                                                           mPrevHeadsetState,
-                                                           mHeadsetName),
-                                    delay);
-    }
-
-    private synchronized final void sendIntents(int headsetState, int prevHeadsetState, String headsetName) {
-        int allHeadsets = SUPPORTED_HEADSETS;
-        for (int curHeadset = 1; allHeadsets != 0; curHeadset <<= 1) {
-            if ((curHeadset & allHeadsets) != 0) {
-                sendIntent(curHeadset, headsetState, prevHeadsetState, headsetName);
-                allHeadsets &= ~curHeadset;
-            }
-        }
-    }
-
-    private final void sendIntent(int headset, int headsetState, int prevHeadsetState, String headsetName) {
-        if ((headsetState & headset) != (prevHeadsetState & headset)) {
-            //  Pack up the values and broadcast them to everyone
-            Intent intent = new Intent(Intent.ACTION_HEADSET_PLUG);
-            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-            int state = 0;
-            int microphone = 0;
-
-            if ((headset & HEADSETS_WITH_MIC) != 0) {
-                microphone = 1;
-            }
-            if ((headsetState & headset) != 0) {
-                state = 1;
-            }
-            intent.putExtra("state", state);
-            intent.putExtra("name", headsetName);
-            intent.putExtra("microphone", microphone);
-
-            if (LOG) Slog.v(TAG, "Intent.ACTION_HEADSET_PLUG: state: "+state+" name: "+headsetName+" mic: "+microphone);
-            // TODO: Should we require a permission?
-            ActivityManagerNative.broadcastStickyIntent(intent, null);
-        }
-    }
-
-    private final Handler mHandler = new Handler() {
-        @Override
-        public void handleMessage(Message msg) {
-            sendIntents(msg.arg1, msg.arg2, (String)msg.obj);
-            mWakeLock.release();
-        }
-    };
-}
diff --git a/services/java/com/android/server/InputManager.java b/services/java/com/android/server/InputManager.java
index cb4071a..e7eb129 100644
--- a/services/java/com/android/server/InputManager.java
+++ b/services/java/com/android/server/InputManager.java
@@ -404,17 +404,18 @@
         }
         
         @SuppressWarnings("unused")
-        public int interceptKeyBeforeQueueing(long whenNanos, int keyCode, boolean down,
-                int policyFlags, boolean isScreenOn) {
+        public int interceptKeyBeforeQueueing(long whenNanos, int action, int flags,
+                int keyCode, int scanCode, int policyFlags, boolean isScreenOn) {
             return mWindowManagerService.mInputMonitor.interceptKeyBeforeQueueing(
-                    whenNanos, keyCode, down, policyFlags, isScreenOn);
+                    whenNanos, action, flags, keyCode, scanCode, policyFlags, isScreenOn);
         }
         
         @SuppressWarnings("unused")
         public boolean interceptKeyBeforeDispatching(InputChannel focus, int action,
-                int flags, int keyCode, int metaState, int repeatCount, int policyFlags) {
+                int flags, int keyCode, int scanCode, int metaState, int repeatCount,
+                int policyFlags) {
             return mWindowManagerService.mInputMonitor.interceptKeyBeforeDispatching(focus,
-                    action, flags, keyCode, metaState, repeatCount, policyFlags);
+                    action, flags, keyCode, scanCode, metaState, repeatCount, policyFlags);
         }
         
         @SuppressWarnings("unused")
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 07da0fa..155c397 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -993,6 +993,13 @@
                         if (mCurMethod != null) {
                             try {
                                 putSelectedInputMethodSubtype(info, subtypeId);
+                                mCurrentSubtype = subtype;
+                                if (mInputShown) {
+                                    // If mInputShown is false, there is no IME button on the
+                                    // system bar.
+                                    // Thus there is no need to make it invisible explicitly.
+                                    mStatusBar.setIMEButtonVisible(true);
+                                }
                                 mCurMethod.changeInputMethodSubtype(subtype);
                             } catch (RemoteException e) {
                                 return;
@@ -1881,11 +1888,10 @@
             String id = pair.first;
             ArrayList<String> subtypes = pair.second;
             builder.append(id);
-            if (subtypes.size() > 0) {
-                builder.append(subtypes.get(0));
-                for (int i = 1; i < subtypes.size(); ++i) {
-                    builder.append(INPUT_METHOD_SUBTYPE_SEPARATER).append(subtypes.get(i));
-                }
+            // Inputmethod and subtypes are saved in the settings as follows:
+            // ime0;subtype0;subtype1:ime1;subtype0:ime2:ime3;subtype0;subtype1
+            for (String subtypeId: subtypes) {
+                builder.append(INPUT_METHOD_SUBTYPE_SEPARATER).append(subtypeId);
             }
         }
 
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 5cf013f..e9a2ebf 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -2219,9 +2219,9 @@
             int eventType, boolean force) {
 
         if (((mPokey & POKE_LOCK_IGNORE_CHEEK_EVENTS) != 0)
-                && (eventType == CHEEK_EVENT || eventType == TOUCH_EVENT)) {
+                && (eventType == CHEEK_EVENT)) {
             if (false) {
-                Slog.d(TAG, "dropping cheek or short event mPokey=0x" + Integer.toHexString(mPokey));
+                Slog.d(TAG, "dropping cheek event mPokey=0x" + Integer.toHexString(mPokey));
             }
             return;
         }
diff --git a/services/java/com/android/server/StatusBarManagerService.java b/services/java/com/android/server/StatusBarManagerService.java
index 95d2b65..596db57 100644
--- a/services/java/com/android/server/StatusBarManagerService.java
+++ b/services/java/com/android/server/StatusBarManagerService.java
@@ -71,9 +71,7 @@
     Object mLock = new Object();
     // We usually call it lights out mode, but double negatives are annoying
     boolean mLightsOn = true;
-
     boolean mMenuVisible = false;
-
     boolean mIMEButtonVisible = false;
 
     private class DisableRecord implements IBinder.DeathRecipient {
@@ -265,19 +263,20 @@
         if (SPEW) Slog.d(TAG, (visible?"showing":"hiding") + " IME Button");
 
         synchronized(mLock) {
-            if (mIMEButtonVisible != visible) {
-                mIMEButtonVisible = visible;
-                mHandler.post(new Runnable() {
-                    public void run() {
-                        if (mBar != null) {
-                            try {
-                                mBar.setIMEButtonVisible(visible);
-                            } catch (RemoteException ex) {
-                            }
+            // In case of IME change, we need to call up setIMEButtonVisible() regardless of
+            // mIMEButtonVisible because mIMEButtonVisible may not have been set to false when the
+            // previous IME was destroyed.
+            mIMEButtonVisible = visible;
+            mHandler.post(new Runnable() {
+                public void run() {
+                    if (mBar != null) {
+                        try {
+                            mBar.setIMEButtonVisible(visible);
+                        } catch (RemoteException ex) {
                         }
                     }
-                });
-            }
+                }
+            });
         }
     }
 
@@ -352,7 +351,7 @@
     // ================================================================================
     public void registerStatusBar(IStatusBar bar, StatusBarIconList iconList,
             List<IBinder> notificationKeys, List<StatusBarNotification> notifications,
-            boolean switches[]) {
+            int switches[]) {
         enforceStatusBarService();
 
         Slog.i(TAG, "registerStatusBar bar=" + bar);
@@ -367,9 +366,10 @@
             }
         }
         synchronized (mLock) {
-            switches[0] = mLightsOn;
-            switches[1] = mMenuVisible;
-            switches[2] = mIMEButtonVisible;
+            switches[0] = gatherDisableActionsLocked();
+            switches[1] = mLightsOn ? 1 : 0;
+            switches[2] = mMenuVisible ? 1 : 0;
+            switches[3] = mIMEButtonVisible ? 1 : 0;
         }
     }
 
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 237ab80..54f7441 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -121,7 +121,7 @@
         WindowManagerService wm = null;
         BluetoothService bluetooth = null;
         BluetoothA2dpService bluetoothA2dp = null;
-        HeadsetObserver headset = null;
+        WiredAccessoryObserver wiredAccessory = null;
         DockObserver dock = null;
         UsbObserver usb = null;
         UiModeManagerService uiMode = null;
@@ -388,14 +388,6 @@
             }
 
             try {
-                Slog.i(TAG, "Headset Observer");
-                // Listen for wired headset changes
-                headset = new HeadsetObserver(context);
-            } catch (Throwable e) {
-                Slog.e(TAG, "Failure starting HeadsetObserver", e);
-            }
-
-            try {
                 Slog.i(TAG, "Dock Observer");
                 // Listen for dock station changes
                 dock = new DockObserver(context, power);
@@ -404,6 +396,14 @@
             }
 
             try {
+                Slog.i(TAG, "Wired Accessory Observer");
+                // Listen for wired headset changes
+                wiredAccessory = new WiredAccessoryObserver(context);
+            } catch (Throwable e) {
+                Slog.e(TAG, "Failure starting WiredAccessoryObserver", e);
+            }
+
+            try {
                 Slog.i(TAG, "USB Observer");
                 // Listen for USB changes
                 usb = new UsbObserver(context);
diff --git a/services/java/com/android/server/TelephonyRegistry.java b/services/java/com/android/server/TelephonyRegistry.java
index 747af26..a7a0c68 100644
--- a/services/java/com/android/server/TelephonyRegistry.java
+++ b/services/java/com/android/server/TelephonyRegistry.java
@@ -103,6 +103,8 @@
 
     private int mDataConnectionNetworkType;
 
+    private int mOtaspMode;
+
     static final int PHONE_STATE_PERMISSION_MASK =
                 PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR |
                 PhoneStateListener.LISTEN_CALL_STATE |
@@ -225,6 +227,13 @@
                             remove(r.binder);
                         }
                     }
+                    if ((events & PhoneStateListener.LISTEN_OTASP_CHANGED) != 0) {
+                        try {
+                            r.callback.onOtaspChanged(mOtaspMode);
+                        } catch (RemoteException ex) {
+                            remove(r.binder);
+                        }
+                    }
                 }
             }
         } else {
@@ -467,6 +476,25 @@
         }
     }
 
+    public void notifyOtaspChanged(int otaspMode) {
+        if (!checkNotifyPermission("notifyOtaspChanged()" )) {
+            return;
+        }
+        synchronized (mRecords) {
+            mOtaspMode = otaspMode;
+            for (Record r : mRecords) {
+                if ((r.events & PhoneStateListener.LISTEN_OTASP_CHANGED) != 0) {
+                    try {
+                        r.callback.onOtaspChanged(otaspMode);
+                    } catch (RemoteException ex) {
+                        mRemoveList.add(r.binder);
+                    }
+                }
+            }
+            handleRemoveListLocked();
+        }
+    }
+
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index c29e4a9..55ebded 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -5706,20 +5706,20 @@
         
         /* Provides an opportunity for the window manager policy to intercept early key
          * processing as soon as the key has been read from the device. */
-        public int interceptKeyBeforeQueueing(long whenNanos, int keyCode, boolean down,
-                int policyFlags, boolean isScreenOn) {
-            return mPolicy.interceptKeyBeforeQueueing(whenNanos,
-                    keyCode, down, policyFlags, isScreenOn);
+        public int interceptKeyBeforeQueueing(long whenNanos, int action, int flags,
+                int keyCode, int scanCode, int policyFlags, boolean isScreenOn) {
+            return mPolicy.interceptKeyBeforeQueueing(whenNanos, action, flags,
+                    keyCode, scanCode, policyFlags, isScreenOn);
         }
         
         /* Provides an opportunity for the window manager policy to process a key before
          * ordinary dispatch. */
         public boolean interceptKeyBeforeDispatching(InputChannel focus,
-                int action, int flags, int keyCode, int metaState, int repeatCount,
+                int action, int flags, int keyCode, int scanCode, int metaState, int repeatCount,
                 int policyFlags) {
             WindowState windowState = getWindowStateForInputChannel(focus);
             return mPolicy.interceptKeyBeforeDispatching(windowState, action, flags,
-                    keyCode, metaState, repeatCount, policyFlags);
+                    keyCode, scanCode, metaState, repeatCount, policyFlags);
         }
         
         /* Called when the current input focus changes.
diff --git a/services/java/com/android/server/WiredAccessoryObserver.java b/services/java/com/android/server/WiredAccessoryObserver.java
new file mode 100644
index 0000000..ab92fdf
--- /dev/null
+++ b/services/java/com/android/server/WiredAccessoryObserver.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.app.ActivityManagerNative;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.PowerManager.WakeLock;
+import android.os.UEventObserver;
+import android.util.Slog;
+import android.media.AudioManager;
+import android.util.Log;
+
+import java.io.FileReader;
+import java.io.FileNotFoundException;
+
+/**
+ * <p>WiredAccessoryObserver monitors for a wired headset on the main board or dock.
+ */
+class WiredAccessoryObserver extends UEventObserver {
+    private static final String TAG = WiredAccessoryObserver.class.getSimpleName();
+    private static final boolean LOG = true;
+    private static final int MAX_AUDIO_PORTS = 2; /* h2w & USB Audio */
+    private static final String uEventInfo[][] = { {"DEVPATH=/devices/virtual/switch/h2w",
+                                                    "/sys/class/switch/h2w/state",
+                                                    "/sys/class/switch/h2w/name"},
+                                                   {"DEVPATH=/devices/virtual/switch/usb_audio",
+                                                    "/sys/class/switch/usb_audio/state",
+                                                    "/sys/class/switch/usb_audio/name"} };
+
+    private static final int BIT_HEADSET = (1 << 0);
+    private static final int BIT_HEADSET_NO_MIC = (1 << 1);
+    private static final int BIT_USB_HEADSET_ANLG = (1 << 2);
+    private static final int BIT_USB_HEADSET_DGTL = (1 << 3);
+    private static final int SUPPORTED_HEADSETS = (BIT_HEADSET|BIT_HEADSET_NO_MIC|
+                                                   BIT_USB_HEADSET_ANLG|BIT_USB_HEADSET_DGTL);
+    private static final int HEADSETS_WITH_MIC = BIT_HEADSET;
+
+    private int mHeadsetState;
+    private int mPrevHeadsetState;
+    private String mHeadsetName;
+    private int switchState;
+
+    private final Context mContext;
+    private final WakeLock mWakeLock;  // held while there is a pending route change
+
+    public WiredAccessoryObserver(Context context) {
+        mContext = context;
+        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WiredAccessoryObserver");
+        mWakeLock.setReferenceCounted(false);
+
+        // At any given time both headsets could be inserted
+        // one on the board and one on the dock
+        // observe two UEVENTs
+        for (int i = 0; i <= MAX_AUDIO_PORTS; i++) {
+            startObserving(uEventInfo[i][0]);
+        }
+        init();  // set initial status
+    }
+
+    @Override
+    public void onUEvent(UEventObserver.UEvent event) {
+        if (LOG) Slog.v(TAG, "Headset UEVENT: " + event.toString());
+
+        try {
+            if ((event.get("SWITCH_NAME")).equals("usb_audio")) {
+                if (Integer.parseInt(event.get("SWITCH_STATE")) == 1) {
+                    switchState = ((mHeadsetState & (BIT_HEADSET|BIT_HEADSET_NO_MIC|
+                                                     BIT_USB_HEADSET_DGTL)) |
+                                   (Integer.parseInt(event.get("SWITCH_STATE")) << 2));
+                } else if (Integer.parseInt(event.get("SWITCH_STATE")) == 2) {
+                    switchState = ((mHeadsetState & (BIT_HEADSET|BIT_HEADSET_NO_MIC|
+                                                     BIT_USB_HEADSET_ANLG)) |
+                                   (Integer.parseInt(event.get("SWITCH_STATE")) << 3));
+                }
+                else switchState = (mHeadsetState & (BIT_HEADSET|BIT_HEADSET_NO_MIC));
+            }
+            else {
+                switchState = ((mHeadsetState & (BIT_USB_HEADSET_ANLG|BIT_USB_HEADSET_DGTL)) |
+                              (Integer.parseInt(event.get("SWITCH_STATE"))));
+            }
+            update(event.get("SWITCH_NAME"), switchState);
+        } catch (NumberFormatException e) {
+            Slog.e(TAG, "Could not parse switch state from event " + event);
+        }
+    }
+
+    private synchronized final void init() {
+        char[] buffer = new char[1024];
+
+        String newName = mHeadsetName;
+        int newState = mHeadsetState;
+        mPrevHeadsetState = mHeadsetState;
+
+        for (int i = 0; i <= MAX_AUDIO_PORTS; i++) {
+            try {
+                FileReader file = new FileReader(uEventInfo[i][1]);
+                int len = file.read(buffer, 0, 1024);
+                newState = Integer.valueOf((new String(buffer, 0, len)).trim());
+
+                file = new FileReader(uEventInfo[i][2]);
+                len = file.read(buffer, 0, 1024);
+                newName = new String(buffer, 0, len).trim();
+
+            } catch (FileNotFoundException e) {
+                Slog.w(TAG, "This kernel does not have wired headset support");
+            } catch (Exception e) {
+                Slog.e(TAG, "" , e);
+            }
+
+            update(newName, newState);
+        }
+    }
+
+    private synchronized final void update(String newName, int newState) {
+        // Retain only relevant bits
+        int headsetState = newState & SUPPORTED_HEADSETS;
+        int newOrOld = headsetState | mHeadsetState;
+        int delay = 0;
+        int usb_headset_anlg = headsetState & BIT_USB_HEADSET_ANLG;
+        int usb_headset_dgtl = headsetState & BIT_USB_HEADSET_DGTL;
+        int h2w_headset = headsetState & (BIT_HEADSET | BIT_HEADSET_NO_MIC);
+        boolean h2wStateChange = true;
+        boolean usbStateChange = true;
+        // reject all suspect transitions: only accept state changes from:
+        // - a: 0 heaset to 1 headset
+        // - b: 1 headset to 0 headset
+        Log.v(TAG, "newState = "+newState+", headsetState = "+headsetState+", mHeadsetState = "+mHeadsetState);
+        if (mHeadsetState == headsetState || ((h2w_headset & (h2w_headset - 1)) != 0)) {
+            Log.e(TAG, "unsetting h2w flag");
+            h2wStateChange = false;
+        }
+        // - c: 0 usb headset to 1 usb headset
+        // - d: 1 usb headset to 0 usb headset
+        if ((usb_headset_anlg >> 2) == 1 && (usb_headset_dgtl >> 3) == 1) {
+            Log.e(TAG, "unsetting usb flag");
+            usbStateChange = false;
+        }
+        if (!h2wStateChange && !usbStateChange) {
+            Log.e(TAG, "invalid transition, returning ...");
+            return;
+        }
+
+        mHeadsetName = newName;
+        mPrevHeadsetState = mHeadsetState;
+        mHeadsetState = headsetState;
+
+        if (headsetState == 0) {
+            Intent intent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
+            mContext.sendBroadcast(intent);
+            // It can take hundreds of ms flush the audio pipeline after
+            // apps pause audio playback, but audio route changes are
+            // immediate, so delay the route change by 1000ms.
+            // This could be improved once the audio sub-system provides an
+            // interface to clear the audio pipeline.
+            delay = 1000;
+        } else {
+            // Insert the same delay for headset connection so that the connection event is not
+            // broadcast before the disconnection event in case of fast removal/insertion
+            if (mHandler.hasMessages(0)) {
+                delay = 1000;
+            }
+        }
+        mWakeLock.acquire();
+        mHandler.sendMessageDelayed(mHandler.obtainMessage(0,
+                                                           mHeadsetState,
+                                                           mPrevHeadsetState,
+                                                           mHeadsetName),
+                                    delay);
+    }
+
+    private synchronized final void sendIntents(int headsetState, int prevHeadsetState, String headsetName) {
+        int allHeadsets = SUPPORTED_HEADSETS;
+        for (int curHeadset = 1; allHeadsets != 0; curHeadset <<= 1) {
+            if ((curHeadset & allHeadsets) != 0) {
+                sendIntent(curHeadset, headsetState, prevHeadsetState, headsetName);
+                allHeadsets &= ~curHeadset;
+            }
+        }
+    }
+
+    private final void sendIntent(int headset, int headsetState, int prevHeadsetState, String headsetName) {
+        if ((headsetState & headset) != (prevHeadsetState & headset)) {
+
+            int state = 0;
+            if ((headsetState & headset) != 0) {
+                state = 1;
+            }
+            if((headset == BIT_USB_HEADSET_ANLG) || (headset == BIT_USB_HEADSET_DGTL)) {
+                Intent intent;
+
+                //  Pack up the values and broadcast them to everyone
+                if (headset == BIT_USB_HEADSET_ANLG) {
+                    intent = new Intent(Intent.ACTION_USB_ANLG_HEADSET_PLUG);
+                    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+                    intent.putExtra("state", state);
+                    intent.putExtra("name", headsetName);
+                    ActivityManagerNative.broadcastStickyIntent(intent, null);
+                } else if (headset == BIT_USB_HEADSET_DGTL) {
+                    intent = new Intent(Intent.ACTION_USB_DGTL_HEADSET_PLUG);
+                    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+                    intent.putExtra("state", state);
+                    intent.putExtra("name", headsetName);
+                    ActivityManagerNative.broadcastStickyIntent(intent, null);
+                }
+
+                if (LOG) Slog.v(TAG, "Intent.ACTION_USB_HEADSET_PLUG: state: "+state+" name: "+headsetName);
+                // TODO: Should we require a permission?
+            }
+            if((headset == BIT_HEADSET) || (headset == BIT_HEADSET_NO_MIC)) {
+
+                //  Pack up the values and broadcast them to everyone
+                Intent intent = new Intent(Intent.ACTION_HEADSET_PLUG);
+                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+                //int state = 0;
+                int microphone = 0;
+
+                if ((headset & HEADSETS_WITH_MIC) != 0) {
+                    microphone = 1;
+                }
+
+                intent.putExtra("state", state);
+                intent.putExtra("name", headsetName);
+                intent.putExtra("microphone", microphone);
+
+                if (LOG) Slog.v(TAG, "Intent.ACTION_HEADSET_PLUG: state: "+state+" name: "+headsetName+" mic: "+microphone);
+                // TODO: Should we require a permission?
+                ActivityManagerNative.broadcastStickyIntent(intent, null);
+            }
+        }
+    }
+
+    private final Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            sendIntents(msg.arg1, msg.arg2, (String)msg.obj);
+            mWakeLock.release();
+        }
+    };
+}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 8d36e4f..60b2b67 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -6679,6 +6679,9 @@
             if (info.numAnimationsRunning != 0) {
                 sb.append("Animations-Running: ").append(info.numAnimationsRunning).append("\n");
             }
+            if (info.broadcastIntentAction != null) {
+                sb.append("Broadcast-Intent-Action: ").append(info.broadcastIntentAction).append("\n");
+            }
             if (info != null && info.durationMillis != -1) {
                 sb.append("Duration-Millis: ").append(info.durationMillis).append("\n");
             }
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index 599163b..d4c4ba4 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -857,7 +857,7 @@
         JNIEnv* env = jniEnv();
         jint wmActions = env->CallIntMethod(mCallbacksObj,
                 gCallbacksClassInfo.interceptKeyBeforeQueueing,
-                when, keyCode, action == AKEY_EVENT_ACTION_DOWN, policyFlags, isScreenOn);
+                when, action, flags, keyCode, scanCode, policyFlags, isScreenOn);
         if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
             wmActions = 0;
         }
@@ -926,7 +926,7 @@
         jboolean consumed = env->CallBooleanMethod(mCallbacksObj,
                 gCallbacksClassInfo.interceptKeyBeforeDispatching,
                 inputChannelObj, keyEvent->getAction(), keyEvent->getFlags(),
-                keyEvent->getKeyCode(), keyEvent->getMetaState(),
+                keyEvent->getKeyCode(), keyEvent->getScanCode(), keyEvent->getMetaState(),
                 keyEvent->getRepeatCount(), policyFlags);
         bool error = checkAndClearExceptionFromCallback(env, "interceptKeyBeforeDispatching");
 
@@ -1358,10 +1358,10 @@
             "notifyANR", "(Ljava/lang/Object;Landroid/view/InputChannel;)J");
 
     GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeQueueing, gCallbacksClassInfo.clazz,
-            "interceptKeyBeforeQueueing", "(JIZIZ)I");
+            "interceptKeyBeforeQueueing", "(JIIIIIZ)I");
 
     GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeDispatching, gCallbacksClassInfo.clazz,
-            "interceptKeyBeforeDispatching", "(Landroid/view/InputChannel;IIIIII)Z");
+            "interceptKeyBeforeDispatching", "(Landroid/view/InputChannel;IIIIIII)Z");
 
     GET_METHOD_ID(gCallbacksClassInfo.checkInjectEventsPermission, gCallbacksClassInfo.clazz,
             "checkInjectEventsPermission", "(II)Z");
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 38f44d8..eda9b71 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -148,6 +148,14 @@
      */
     public static final int LISTEN_SIGNAL_STRENGTHS                         = 0x00000100;
 
+    /**
+     * Listen for changes to OTASP mode.
+     *
+     * @see #onOtaspChanged
+     * @hide
+     */
+    public static final int LISTEN_OTASP_CHANGED                            = 0x00000200;
+
     public PhoneStateListener() {
     }
 
@@ -252,6 +260,21 @@
         // default implementation empty
     }
 
+
+    /**
+     * The Over The Air Service Provisioning (OTASP) has changed. Requires
+     * the READ_PHONE_STATE permission.
+     * @param otaspMode is integer <code>OTASP_UNKNOWN=1<code>
+     *   means the value is currently unknown and the system should wait until
+     *   <code>OTASP_NEEDED=2<code> or <code>OTASP_NOT_NEEDED=3<code> is received before
+     *   making the decisision to perform OTASP or not.
+     *
+     * @hide
+     */
+    public void onOtaspChanged(int otaspMode) {
+        // default implementation empty
+    }
+
     /**
      * The callback methods need to be called on the handler thread where
      * this object was created.  If the binder did that for us it'd be nice.
@@ -292,9 +315,14 @@
         public void onDataActivity(int direction) {
             Message.obtain(mHandler, LISTEN_DATA_ACTIVITY, direction, 0, null).sendToTarget();
         }
+
         public void onSignalStrengthsChanged(SignalStrength signalStrength) {
             Message.obtain(mHandler, LISTEN_SIGNAL_STRENGTHS, 0, 0, signalStrength).sendToTarget();
         }
+
+        public void onOtaspChanged(int otaspMode) {
+            Message.obtain(mHandler, LISTEN_OTASP_CHANGED, otaspMode, 0).sendToTarget();
+        }
     };
 
     Handler mHandler = new Handler() {
@@ -329,6 +357,9 @@
                 case LISTEN_SIGNAL_STRENGTHS:
                     PhoneStateListener.this.onSignalStrengthsChanged((SignalStrength)msg.obj);
                     break;
+                case LISTEN_OTASP_CHANGED:
+                    PhoneStateListener.this.onOtaspChanged(msg.arg1);
+                    break;
             }
         }
     };
diff --git a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
index 6a163dd..14808b6 100644
--- a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
+++ b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
@@ -148,6 +148,14 @@
         }
     }
 
+    public void notifyOtaspChanged(Phone sender, int otaspMode) {
+        try {
+            mRegistry.notifyOtaspChanged(otaspMode);
+        } catch (RemoteException ex) {
+            // system process is dead
+        }
+    }
+
     private void log(String s) {
         Log.d(LOG_TAG, "[PhoneNotifier] " + s);
     }
diff --git a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
index 856d663..082c097 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -32,5 +32,6 @@
     void onDataConnectionStateChanged(int state, int networkType);
     void onDataActivity(int direction);
     void onSignalStrengthsChanged(in SignalStrength signalStrength);
+    void onOtaspChanged(in int otaspMode);
 }
 
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 7a1587b..3c4bb12 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -66,7 +66,7 @@
     boolean showCallScreenWithDialpad(boolean showDialpad);
 
     /**
-     * End call or go to the Home screen
+     * End call if there is a call in progress, otherwise does nothing.
      *
      * @return whether it hung up
      */
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 6407a4e..3c83e50 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -38,4 +38,5 @@
             in LinkCapabilities linkCapabilities, int networkType);
     void notifyDataConnectionFailed(String reason, String apnType);
     void notifyCellLocation(in Bundle cellLocation);
+    void notifyOtaspChanged(in int otaspMode);
 }
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index 74e8c1b..554a7ba 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -750,6 +750,10 @@
         mNotifier.notifyDataConnection(this, reason, apnType);
     }
 
+    public void notifyOtaspChanged(int otaspMode) {
+        mNotifier.notifyOtaspChanged(this, otaspMode);
+    }
+
     public abstract String getPhoneName();
 
     public abstract int getPhoneType();
diff --git a/telephony/java/com/android/internal/telephony/PhoneNotifier.java b/telephony/java/com/android/internal/telephony/PhoneNotifier.java
index 691271f..b1cf953 100644
--- a/telephony/java/com/android/internal/telephony/PhoneNotifier.java
+++ b/telephony/java/com/android/internal/telephony/PhoneNotifier.java
@@ -42,4 +42,5 @@
 
     public void notifyDataActivity(Phone sender);
 
+    public void notifyOtaspChanged(Phone sender, int otaspMode);
 }
diff --git a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
index e8bbe5e..3f9ffc3 100644
--- a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -53,6 +53,12 @@
 
     public SignalStrength mSignalStrength;
 
+    /* The otaspMode passed to PhoneStateListener#onOtaspChanged */
+    static public final int OTASP_UNINITIALIZED = 0;
+    static public final int OTASP_UNKNOWN = 1;
+    static public final int OTASP_NEEDED = 2;
+    static public final int OTASP_NOT_NEEDED = 3;
+
     /**
      * A unique identifier to track requests associated with a poll
      * and ignore stale responses.  The value is a count-down of
@@ -268,9 +274,11 @@
 
     public abstract void handleMessage(Message msg);
 
+    protected abstract Phone getPhone();
     protected abstract void handlePollStateResult(int what, AsyncResult ar);
     protected abstract void updateSpnDisplay();
     protected abstract void setPowerStateToDesired();
+    protected abstract void log(String s);
 
     /**
      * Clean up existing voice and data connection then turn off radio power.
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index 6e53ec5..b9d5673 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -61,6 +61,7 @@
 import com.android.internal.telephony.PhoneNotifier;
 import com.android.internal.telephony.PhoneProxy;
 import com.android.internal.telephony.PhoneSubInfo;
+import com.android.internal.telephony.ServiceStateTracker;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.telephony.TelephonyProperties;
 import com.android.internal.telephony.UUSInfo;
@@ -83,10 +84,6 @@
     static final String LOG_TAG = "CDMA";
     private static final boolean DBG = true;
 
-    // Min values used to by needsActivation
-    private static final String UNACTIVATED_MIN2_VALUE = "000000";
-    private static final String UNACTIVATED_MIN_VALUE = "1111110111";
-
     // Default Emergency Callback Mode exit timer
     private static final int DEFAULT_ECM_EXIT_TIMER_VALUE = 300000;
 
@@ -1170,19 +1167,7 @@
      */
     @Override
     public boolean needsOtaServiceProvisioning() {
-        String cdmaMin = getCdmaMin();
-        boolean needsProvisioning;
-        if (cdmaMin == null || (cdmaMin.length() < 6)) {
-            if (DBG) Log.d(LOG_TAG, "needsOtaServiceProvisioning: illegal cdmaMin='"
-                                    + cdmaMin + "' assume provisioning needed.");
-            needsProvisioning = true;
-        } else {
-            needsProvisioning = (cdmaMin.equals(UNACTIVATED_MIN_VALUE)
-                    || cdmaMin.substring(0,6).equals(UNACTIVATED_MIN2_VALUE))
-                    || SystemProperties.getBoolean("test_cdma_setup", false);
-        }
-        if (DBG) Log.d(LOG_TAG, "needsOtaServiceProvisioning: ret=" + needsProvisioning);
-        return needsProvisioning;
+        return mSST.getOtasp() != ServiceStateTracker.OTASP_NOT_NEEDED;
     }
 
     private static final String IS683A_FEATURE_CODE = "*228";
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
index 3669e60..325c2e1 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
@@ -354,6 +354,24 @@
                     || (foregroundCall.getState() == CdmaCall.State.ACTIVE)
                     || !backgroundCall.getState().isAlive());
 
+        if (!ret) {
+            log(String.format("canDial is false\n" +
+                              "((serviceState=%d) != ServiceState.STATE_POWER_OFF)::=%s\n" +
+                              "&& pendingMO == null::=%s\n" +
+                              "&& !ringingCall.isRinging()::=%s\n" +
+                              "&& !disableCall.equals(\"true\")::=%s\n" +
+                              "&& (!foregroundCall.getState().isAlive()::=%s\n" +
+                              "   || foregroundCall.getState() == CdmaCall.State.ACTIVE::=%s\n" +
+                              "   ||!backgroundCall.getState().isAlive())::=%s)",
+                    serviceState,
+                    serviceState != ServiceState.STATE_POWER_OFF,
+                    pendingMO == null,
+                    !ringingCall.isRinging(),
+                    !disableCall.equals("true"),
+                    !foregroundCall.getState().isAlive(),
+                    foregroundCall.getState() == CdmaCall.State.ACTIVE,
+                    !backgroundCall.getState().isAlive()));
+        }
         return ret;
     }
 
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
index 7d2013b..11e04d4 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaServiceStateTracker.java
@@ -22,6 +22,7 @@
 import com.android.internal.telephony.EventLogTags;
 import com.android.internal.telephony.IccCard;
 import com.android.internal.telephony.MccTable;
+import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.ServiceStateTracker;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.telephony.TelephonyProperties;
@@ -65,6 +66,13 @@
     CdmaCellLocation cellLoc;
     CdmaCellLocation newCellLoc;
 
+    // Min values used to by getOtasp()
+    private static final String UNACTIVATED_MIN2_VALUE = "000000";
+    private static final String UNACTIVATED_MIN_VALUE = "1111110111";
+
+    // Current Otasp value
+    int mCurrentOtaspMode = OTASP_UNINITIALIZED;
+
      /** if time between NITZ updates is less than mNitzUpdateSpacing the update may be ignored. */
     private static final int NITZ_UPDATE_SPACING_DEFAULT = 1000 * 60 * 10;
     private int mNitzUpdateSpacing = SystemProperties.getInt("ro.nitz_update_spacing",
@@ -446,6 +454,13 @@
                     if (!mIsMinInfoReady) {
                         mIsMinInfoReady = true;
                     }
+                    int otaspMode = getOtasp();
+                    if (mCurrentOtaspMode != otaspMode) {
+                        Log.d(LOG_TAG, "call phone.notifyOtaspChanged old otaspMode=" +
+                                mCurrentOtaspMode + " new otaspMode=" + otaspMode);
+                        mCurrentOtaspMode = otaspMode;
+                        phone.notifyOtaspChanged(mCurrentOtaspMode);
+                    }
                     phone.getIccCard().broadcastIccStateChangedIntent(IccCard.INTENT_VALUE_ICC_IMSI,
                             null);
                 } else {
@@ -642,6 +657,11 @@
         curPlmn = plmn;
     }
 
+    @Override
+    protected Phone getPhone() {
+        return phone;
+    }
+
     /**
      * Handle the result of one of the pollState()-related requests
      */
@@ -1641,10 +1661,6 @@
         return false;
     }
 
-    protected void log(String s) {
-        Log.d(LOG_TAG, "[CdmaServiceStateTracker] " + s);
-    }
-
     public String getMdnNumber() {
         return mMdn;
     }
@@ -1700,6 +1716,32 @@
         }
     }
 
+    /**
+     * Returns OTASP_UNKNOWN, OTASP_NEEDED or OTASP_NOT_NEEDED
+     */
+    int getOtasp() {
+        int provisioningState;
+        if (mMin == null || (mMin.length() < 6)) {
+            if (DBG) Log.d(LOG_TAG, "getOtasp: bad mMin='" + mMin + "'");
+            provisioningState = OTASP_UNKNOWN;
+        } else {
+            if ((mMin.equals(UNACTIVATED_MIN_VALUE)
+                    || mMin.substring(0,6).equals(UNACTIVATED_MIN2_VALUE))
+                    || SystemProperties.getBoolean("test_cdma_setup", false)) {
+                provisioningState = OTASP_NEEDED;
+            } else {
+                provisioningState = OTASP_NOT_NEEDED;
+            }
+        }
+        if (DBG) Log.d(LOG_TAG, "getOtasp: state=" + provisioningState);
+        return provisioningState;
+    }
+
+    @Override
+    protected void log(String s) {
+        Log.d(LOG_TAG, "[CdmaServiceStateTracker] " + s);
+    }
+
     private void hangupAndPowerOff() {
         // hang up all active voice calls
         phone.mCT.ringingCall.hangupIfAlive();
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
index 6332415..bc41b01 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmServiceStateTracker.java
@@ -22,6 +22,7 @@
 import com.android.internal.telephony.EventLogTags;
 import com.android.internal.telephony.IccCard;
 import com.android.internal.telephony.MccTable;
+import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.RILConstants;
 import com.android.internal.telephony.ServiceStateTracker;
 import com.android.internal.telephony.TelephonyIntents;
@@ -226,6 +227,9 @@
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_LOCALE_CHANGED);
         phone.getContext().registerReceiver(mIntentReceiver, filter);
+
+        // Gsm doesn't support OTASP so its not needed
+        phone.notifyOtaspChanged(OTASP_NOT_NEEDED);
     }
 
     public void dispose() {
@@ -246,6 +250,11 @@
         if(DBG) Log.d(LOG_TAG, "GsmServiceStateTracker finalized");
     }
 
+    @Override
+    public Phone getPhone() {
+        return phone;
+    }
+
     /**
      * Registration point for transition into GPRS attached.
      * @param h handler to notify
@@ -1676,7 +1685,8 @@
         }
     }
 
-    private void log(String s) {
+    @Override
+    protected void log(String s) {
         Log.d(LOG_TAG, "[GsmServiceStateTracker] " + s);
     }
 }
diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/TestPhoneNotifier.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/TestPhoneNotifier.java
index 8cb05cc..7bbe696 100644
--- a/telephony/tests/telephonytests/src/com/android/internal/telephony/TestPhoneNotifier.java
+++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/TestPhoneNotifier.java
@@ -56,4 +56,7 @@
 
     public void notifyDataActivity(Phone sender) {
     }
+
+    public void notifyOtaspChanged(Phone sender, int otaspMode) {
+    }
 }
diff --git a/tests/StatusBar/res/layout/button_notification.xml b/tests/StatusBar/res/layout/button_notification.xml
new file mode 100644
index 0000000..822e8cd
--- /dev/null
+++ b/tests/StatusBar/res/layout/button_notification.xml
@@ -0,0 +1,21 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="80sp"
+    android:orientation="horizontal"
+    >
+
+    <ImageView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:src="@drawable/icon1"
+        />
+
+    <Button android:id="@+id/button"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="button"
+        />
+
+</LinearLayout>
+
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
index 38ee1b8..2df97dc 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
@@ -100,6 +100,19 @@
             }
         },
 
+        new Test("Button") {
+            public void run() {
+                Notification n = new Notification(R.drawable.icon1, null,
+                        mActivityCreateTime);
+                n.contentView = new RemoteViews(getPackageName(), R.layout.button_notification);
+                n.flags |= Notification.FLAG_ONGOING_EVENT;
+                n.contentIntent = makeIntent();
+                n.contentView.setOnClickPendingIntent(R.id.button, makeIntent2());
+
+                mNM.notify(1, n);
+            }
+        },
+
         new Test("custom intent on text view") {
             public void run() {
                 Notification n = new Notification(R.drawable.icon1, null,
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap.java
deleted file mode 100644
index 35f022e..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/Bitmap.java
+++ /dev/null
@@ -1,278 +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.graphics;
-
-
-import java.awt.image.BufferedImage;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-
-import javax.imageio.ImageIO;
-
-public final class Bitmap extends _Original_Bitmap {
-
-    private BufferedImage mImage;
-
-    public Bitmap(File input) throws IOException {
-        super(1, true, null, -1);
-
-        mImage = ImageIO.read(input);
-    }
-
-    public Bitmap(InputStream is) throws IOException {
-        super(1, true, null, -1);
-
-        mImage = ImageIO.read(is);
-    }
-
-    Bitmap(BufferedImage image) {
-        super(1, true, null, -1);
-        mImage = image;
-    }
-
-    public BufferedImage getImage() {
-        return mImage;
-    }
-
-    // ----- overriden methods
-
-    public enum Config {
-        // these native values must match up with the enum in SkBitmap.h
-        ALPHA_8     (2),
-        RGB_565     (4),
-        ARGB_4444   (5),
-        ARGB_8888   (6);
-
-        Config(int ni) {
-            this.nativeInt = ni;
-        }
-        final int nativeInt;
-
-        /* package */ static Config nativeToConfig(int ni) {
-            return sConfigs[ni];
-        }
-
-        private static Config sConfigs[] = {
-            null, null, ALPHA_8, null, RGB_565, ARGB_4444, ARGB_8888
-        };
-    }
-
-    @Override
-    public int getWidth() {
-        return mImage.getWidth();
-    }
-
-    @Override
-    public int getHeight() {
-        return mImage.getHeight();
-    }
-
-    /**
-     * Returns an immutable bitmap from the source bitmap. The new bitmap may
-     * be the same object as source, or a copy may have been made.
-     */
-    public static Bitmap createBitmap(Bitmap src) {
-        return createBitmap(src, 0, 0, src.getWidth(), src.getHeight(), null, false);
-    }
-
-    /**
-     * Returns an immutable bitmap from the specified subset of the source
-     * bitmap. The new bitmap may be the same object as source, or a copy may
-     * have been made.
-     *
-     * @param source   The bitmap we are subsetting
-     * @param x        The x coordinate of the first pixel in source
-     * @param y        The y coordinate of the first pixel in source
-     * @param width    The number of pixels in each row
-     * @param height   The number of rows
-     */
-    public static Bitmap createBitmap(Bitmap source, int x, int y,
-                                      int width, int height) {
-        return new Bitmap(source.mImage.getSubimage(x, y, width, height));
-    }
-
-    /**
-     * Returns an immutable bitmap from subset of the source bitmap,
-     * transformed by the optional matrix.
-     *
-     * @param source   The bitmap we are subsetting
-     * @param x        The x coordinate of the first pixel in source
-     * @param y        The y coordinate of the first pixel in source
-     * @param width    The number of pixels in each row
-     * @param height   The number of rows
-     * @param m        Option matrix to be applied to the pixels
-     * @param filter   true if the source should be filtered.
-     *                   Only applies if the matrix contains more than just
-     *                   translation.
-     * @return A bitmap that represents the specified subset of source
-     * @throws IllegalArgumentException if the x, y, width, height values are
-     *         outside of the dimensions of the source bitmap.
-     */
-    public static Bitmap createBitmap(Bitmap source, int x, int y, int width,
-                                      int height, Matrix m, boolean filter) {
-        checkXYSign(x, y);
-        checkWidthHeight(width, height);
-        if (x + width > source.getWidth()) {
-            throw new IllegalArgumentException(
-                    "x + width must be <= bitmap.width()");
-        }
-        if (y + height > source.getHeight()) {
-            throw new IllegalArgumentException(
-                    "y + height must be <= bitmap.height()");
-        }
-
-        // check if we can just return our argument unchanged
-        if (!source.isMutable() && x == 0 && y == 0
-                && width == source.getWidth() && height == source.getHeight()
-                && (m == null || m.isIdentity())) {
-            return source;
-        }
-
-        if (m == null || m.isIdentity()) {
-            return new Bitmap(source.mImage.getSubimage(x, y, width, height));
-        }
-
-        int neww = width;
-        int newh = height;
-        Paint paint;
-
-        Rect srcR = new Rect(x, y, x + width, y + height);
-        RectF dstR = new RectF(0, 0, width, height);
-
-        /*  the dst should have alpha if the src does, or if our matrix
-            doesn't preserve rectness
-        */
-        boolean hasAlpha = source.hasAlpha() || !m.rectStaysRect();
-        RectF deviceR = new RectF();
-        m.mapRect(deviceR, dstR);
-        neww = Math.round(deviceR.width());
-        newh = Math.round(deviceR.height());
-
-        Canvas canvas = new Canvas(neww, newh);
-
-        canvas.translate(-deviceR.left, -deviceR.top);
-        canvas.concat(m);
-        paint = new Paint();
-        paint.setFilterBitmap(filter);
-        if (!m.rectStaysRect()) {
-            paint.setAntiAlias(true);
-        }
-
-        canvas.drawBitmap(source, srcR, dstR, paint);
-
-        return new Bitmap(canvas.getImage());
-    }
-
-    /**
-     * Returns a mutable bitmap with the specified width and height.
-     *
-     * @param width    The width of the bitmap
-     * @param height   The height of the bitmap
-     * @param config   The bitmap config to create.
-     * @throws IllegalArgumentException if the width or height are <= 0
-     */
-    public static Bitmap createBitmap(int width, int height, Config config) {
-        return new Bitmap(new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB));
-    }
-
-    /**
-     * Returns a immutable bitmap with the specified width and height, with each
-     * pixel value set to the corresponding value in the colors array.
-     *
-     * @param colors   Array of {@link Color} used to initialize the pixels.
-     * @param offset   Number of values to skip before the first color in the
-     *                 array of colors.
-     * @param stride   Number of colors in the array between rows (must be >=
-     *                 width or <= -width).
-     * @param width    The width of the bitmap
-     * @param height   The height of the bitmap
-     * @param config   The bitmap config to create. If the config does not
-     *                 support per-pixel alpha (e.g. RGB_565), then the alpha
-     *                 bytes in the colors[] will be ignored (assumed to be FF)
-     * @throws IllegalArgumentException if the width or height are <= 0, or if
-     *         the color array's length is less than the number of pixels.
-     */
-    public static Bitmap createBitmap(int colors[], int offset, int stride,
-                                      int width, int height, Config config) {
-        checkWidthHeight(width, height);
-        if (Math.abs(stride) < width) {
-            throw new IllegalArgumentException("abs(stride) must be >= width");
-        }
-        int lastScanline = offset + (height - 1) * stride;
-        int length = colors.length;
-        if (offset < 0 || (offset + width > length)
-            || lastScanline < 0
-            || (lastScanline + width > length)) {
-            throw new ArrayIndexOutOfBoundsException();
-        }
-
-        // TODO: create an immutable bitmap...
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * Returns a immutable bitmap with the specified width and height, with each
-     * pixel value set to the corresponding value in the colors array.
-     *
-     * @param colors   Array of {@link Color} used to initialize the pixels.
-     *                 This array must be at least as large as width * height.
-     * @param width    The width of the bitmap
-     * @param height   The height of the bitmap
-     * @param config   The bitmap config to create. If the config does not
-     *                 support per-pixel alpha (e.g. RGB_565), then the alpha
-     *                 bytes in the colors[] will be ignored (assumed to be FF)
-     * @throws IllegalArgumentException if the width or height are <= 0, or if
-     *         the color array's length is less than the number of pixels.
-     */
-    public static Bitmap createBitmap(int colors[], int width, int height,
-                                      Config config) {
-        return createBitmap(colors, 0, width, width, height, config);
-    }
-
-    public static Bitmap createScaledBitmap(Bitmap src, int dstWidth,
-            int dstHeight, boolean filter) {
-        Matrix m;
-        synchronized (Bitmap.class) {
-            // small pool of just 1 matrix
-            m = sScaleMatrix;
-            sScaleMatrix = null;
-        }
-
-        if (m == null) {
-            m = new Matrix();
-        }
-
-        final int width = src.getWidth();
-        final int height = src.getHeight();
-        final float sx = dstWidth  / (float)width;
-        final float sy = dstHeight / (float)height;
-        m.setScale(sx, sy);
-        Bitmap b = Bitmap.createBitmap(src, 0, 0, width, height, m, filter);
-
-        synchronized (Bitmap.class) {
-            // do we need to check for null? why not just assign everytime?
-            if (sScaleMatrix == null) {
-                sScaleMatrix = m;
-            }
-        }
-
-        return b;
-    }
-
-
-}
diff --git a/tools/layoutlib/bridge/src/android/graphics/BitmapFactory.java b/tools/layoutlib/bridge/src/android/graphics/BitmapFactory.java
index e978fe8..6fd59c4 100644
--- a/tools/layoutlib/bridge/src/android/graphics/BitmapFactory.java
+++ b/tools/layoutlib/bridge/src/android/graphics/BitmapFactory.java
@@ -16,6 +16,8 @@
 
 package android.graphics;
 
+import com.android.layoutlib.api.IDensityBasedResourceValue.Density;
+
 import android.content.res.AssetManager;
 import android.content.res.Resources;
 import android.util.DisplayMetrics;
@@ -454,7 +456,7 @@
             // into is.read(...) This number is not related to the value passed
             // to mark(...) above.
             try {
-                bm = new Bitmap(is);
+                bm = Bitmap_Delegate.createBitmap(is, Density.MEDIUM);
             } catch (IOException e) {
                 return null;
             }
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
new file mode 100644
index 0000000..e97b1e6
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
@@ -0,0 +1,347 @@
+/*
+ * Copyright (C) 2010 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.graphics;
+
+import com.android.layoutlib.api.IDensityBasedResourceValue.Density;
+import com.android.layoutlib.bridge.DelegateManager;
+
+import android.graphics.Bitmap.Config;
+import android.os.Parcel;
+
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.Buffer;
+
+import javax.imageio.ImageIO;
+
+/**
+ * Delegate implementing the native methods of android.graphics.Bitmap
+ *
+ * Through the layoutlib_create tool, the original native methods of Bitmap have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original Bitmap class.
+ *
+ * @see DelegateManager
+ *
+ */
+public class Bitmap_Delegate {
+
+    // ---- delegate manager ----
+    private static final DelegateManager<Bitmap_Delegate> sManager =
+            new DelegateManager<Bitmap_Delegate>();
+
+    // ---- delegate helper data ----
+
+    // ---- delegate data ----
+    private BufferedImage mImage;
+    private boolean mHasAlpha = true;
+
+    // ---- Public Helper methods ----
+
+    /**
+     * Returns the native delegate associated to a given {@link Bitmap_Delegate} object.
+     */
+    public static Bitmap_Delegate getDelegate(Bitmap bitmap) {
+        return sManager.getDelegate(bitmap.mNativeBitmap);
+    }
+
+    /**
+     * Returns the native delegate associated to a given an int referencing a {@link Bitmap} object.
+     */
+    public static Bitmap_Delegate getDelegate(int native_bitmap) {
+        return sManager.getDelegate(native_bitmap);
+    }
+
+    /**
+     * Creates and returns a {@link Bitmap} initialized with the given file content.
+     */
+    public static Bitmap createBitmap(File input, Density density) throws IOException {
+        // create a delegate with the content of the file.
+        Bitmap_Delegate delegate = new Bitmap_Delegate(ImageIO.read(input));
+
+        return createBitmap(delegate, density.getValue());
+    }
+
+    /**
+     * Creates and returns a {@link Bitmap} initialized with the given stream content.
+     */
+    public static Bitmap createBitmap(InputStream input, Density density) throws IOException {
+        // create a delegate with the content of the stream.
+        Bitmap_Delegate delegate = new Bitmap_Delegate(ImageIO.read(input));
+
+        return createBitmap(delegate, density.getValue());
+    }
+
+    /**
+     * Creates and returns a {@link Bitmap} initialized with the given {@link BufferedImage}
+     */
+    public static Bitmap createBitmap(BufferedImage image, Density density) throws IOException {
+        // create a delegate with the given image.
+        Bitmap_Delegate delegate = new Bitmap_Delegate(image);
+
+        return createBitmap(delegate, density.getValue());
+    }
+
+    /**
+     * Returns the {@link BufferedImage} used by the delegate of the given {@link Bitmap}.
+     */
+    public static BufferedImage getImage(Bitmap bitmap) {
+        // get the delegate from the native int.
+        Bitmap_Delegate delegate = sManager.getDelegate(bitmap.mNativeBitmap);
+        if (delegate == null) {
+            assert false;
+            return null;
+        }
+
+        return delegate.mImage;
+    }
+
+    public static int getBufferedImageType(int nativeBitmapConfig) {
+        switch (Config.sConfigs[nativeBitmapConfig]) {
+            case ALPHA_8:
+                return BufferedImage.TYPE_INT_ARGB;
+            case RGB_565:
+                return BufferedImage.TYPE_INT_ARGB;
+            case ARGB_4444:
+                return BufferedImage.TYPE_INT_ARGB;
+            case ARGB_8888:
+                return BufferedImage.TYPE_INT_ARGB;
+        }
+
+        return BufferedImage.TYPE_INT_ARGB;
+    }
+
+    /**
+     * Returns the {@link BufferedImage} used by the delegate of the given {@link Bitmap}.
+     */
+    public BufferedImage getImage() {
+        return mImage;
+    }
+
+    // ---- native methods ----
+
+    /*package*/ static Bitmap nativeCreate(int[] colors, int offset, int stride, int width,
+            int height, int nativeConfig, boolean mutable) {
+        int imageType = getBufferedImageType(nativeConfig);
+
+        // create the image
+        BufferedImage image = new BufferedImage(width, height, imageType);
+
+        // FIXME fill the bitmap!
+
+        // create a delegate with the content of the stream.
+        Bitmap_Delegate delegate = new Bitmap_Delegate(image);
+
+        return createBitmap(delegate, Bitmap.getDefaultDensity());
+    }
+
+    /*package*/ static Bitmap nativeCopy(int srcBitmap, int nativeConfig, boolean isMutable) {
+        // FIXME implement native delegate
+        throw new UnsupportedOperationException("Native delegate needed for Bitmap");
+    }
+
+    /*package*/ static void nativeDestructor(int nativeBitmap) {
+        // FIXME implement native delegate
+        throw new UnsupportedOperationException("Native delegate needed for Bitmap");
+    }
+
+    /*package*/ static void nativeRecycle(int nativeBitmap) {
+        // FIXME implement native delegate
+        throw new UnsupportedOperationException("Native delegate needed for Bitmap");
+    }
+
+    /*package*/ static boolean nativeCompress(int nativeBitmap, int format, int quality,
+            OutputStream stream, byte[] tempStorage) {
+        // FIXME implement native delegate
+        throw new UnsupportedOperationException("Native delegate needed for Bitmap");
+    }
+
+    /*package*/ static void nativeErase(int nativeBitmap, int color) {
+        // get the delegate from the native int.
+        Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+        if (delegate == null) {
+            assert false;
+            return;
+        }
+
+        BufferedImage image = delegate.mImage;
+
+        Graphics2D g = image.createGraphics();
+        try {
+            if (delegate.mHasAlpha == false) {
+                color |= color & 0xFF000000;
+            }
+            g.setColor(new java.awt.Color(color));
+
+            g.fillRect(0, 0, image.getWidth(), image.getHeight());
+        } finally {
+            g.dispose();
+        }
+    }
+
+    /*package*/ static int nativeWidth(int nativeBitmap) {
+        // get the delegate from the native int.
+        Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+        if (delegate == null) {
+            assert false;
+            return 0;
+        }
+
+        return delegate.mImage.getWidth();
+    }
+
+    /*package*/ static int nativeHeight(int nativeBitmap) {
+        // get the delegate from the native int.
+        Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+        if (delegate == null) {
+            assert false;
+            return 0;
+        }
+
+        return delegate.mImage.getHeight();
+    }
+
+    /*package*/ static int nativeRowBytes(int nativeBitmap) {
+        // get the delegate from the native int.
+        Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+        if (delegate == null) {
+            assert false;
+            return 0;
+        }
+
+        return delegate.mImage.getWidth();
+    }
+
+    /*package*/ static int nativeConfig(int nativeBitmap) {
+        return Config.ARGB_8888.nativeInt;
+    }
+
+    /*package*/ static boolean nativeHasAlpha(int nativeBitmap) {
+        // get the delegate from the native int.
+        Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+        if (delegate == null) {
+            assert false;
+            return true;
+        }
+
+        return delegate.mHasAlpha;
+    }
+
+    /*package*/ static int nativeGetPixel(int nativeBitmap, int x, int y) {
+        // get the delegate from the native int.
+        Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+        if (delegate == null) {
+            assert false;
+            return 0;
+        }
+
+        return delegate.mImage.getRGB(x, y);
+    }
+
+    /*package*/ static void nativeGetPixels(int nativeBitmap, int[] pixels, int offset,
+            int stride, int x, int y, int width, int height) {
+        // FIXME implement native delegate
+        throw new UnsupportedOperationException("Native delegate needed for Bitmap.nativeGetPixels");
+    }
+
+
+    /*package*/ static void nativeSetPixel(int nativeBitmap, int x, int y, int color) {
+        // FIXME implement native delegate
+        throw new UnsupportedOperationException("Native delegate needed for Bitmap.nativeSetPixel");
+    }
+
+    /*package*/ static void nativeSetPixels(int nativeBitmap, int[] colors, int offset,
+            int stride, int x, int y, int width, int height) {
+        // FIXME implement native delegate
+        throw new UnsupportedOperationException("Native delegate needed for Bitmap.nativeSetPixels");
+    }
+
+    /*package*/ static void nativeCopyPixelsToBuffer(int nativeBitmap, Buffer dst) {
+        // FIXME implement native delegate
+        throw new UnsupportedOperationException("Native delegate needed for Bitmap.nativeCopyPixelsToBuffer");
+    }
+
+    /*package*/ static void nativeCopyPixelsFromBuffer(int nb, Buffer src) {
+        // FIXME implement native delegate
+        throw new UnsupportedOperationException("Native delegate needed for Bitmap.nativeCopyPixelsFromBuffer");
+    }
+
+    /*package*/ static int nativeGenerationId(int nativeBitmap) {
+        // FIXME implement native delegate
+        throw new UnsupportedOperationException("Native delegate needed for Bitmap.nativeGenerationId");
+    }
+
+    /*package*/ static Bitmap nativeCreateFromParcel(Parcel p) {
+        // FIXME implement native delegate
+        throw new UnsupportedOperationException("Native delegate needed for Bitmap.nativeCreateFromParcel");
+    }
+
+    /*package*/ static boolean nativeWriteToParcel(int nativeBitmap, boolean isMutable,
+            int density, Parcel p) {
+        // FIXME implement native delegate
+        throw new UnsupportedOperationException("Native delegate needed for Bitmap.nativeWriteToParcel");
+    }
+
+    /*package*/ static Bitmap nativeExtractAlpha(int nativeBitmap, int nativePaint,
+            int[] offsetXY) {
+        // FIXME implement native delegate
+        throw new UnsupportedOperationException("Native delegate needed for Bitmap.nativeExtractAlpha");
+    }
+
+
+    /*package*/ static void nativePrepareToDraw(int nativeBitmap) {
+        // FIXME implement native delegate
+        throw new UnsupportedOperationException("Native delegate needed for Bitmap.nativePrepareToDraw");
+    }
+
+    /*package*/ static void nativeSetHasAlpha(int nativeBitmap, boolean hasAlpha) {
+        // get the delegate from the native int.
+        Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+        if (delegate == null) {
+            assert false;
+            return;
+        }
+
+        delegate.mHasAlpha = hasAlpha;
+    }
+
+    /*package*/ static boolean nativeSameAs(int nb0, int nb1) {
+        // FIXME implement native delegate
+        throw new UnsupportedOperationException("Native delegate needed for Bitmap.nativeSameAs");
+    }
+
+    // ---- Private delegate/helper methods ----
+
+    private Bitmap_Delegate(BufferedImage image) {
+        mImage = image;
+    }
+
+    private static Bitmap createBitmap(Bitmap_Delegate delegate, int density) {
+        // get its native_int
+        int nativeInt = sManager.addDelegate(delegate);
+
+        // and create/return a new Bitmap with it
+        return new Bitmap(nativeInt, true /*isMutable*/, null /*ninePatchChunk*/, density);
+    }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas.java b/tools/layoutlib/bridge/src/android/graphics/Canvas.java
deleted file mode 100644
index 0dccc0d6..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas.java
+++ /dev/null
@@ -1,1247 +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.graphics;
-
-import com.android.layoutlib.api.ILayoutLog;
-
-import android.graphics.Paint.Align;
-import android.graphics.Paint.FontInfo;
-import android.graphics.Paint.Style;
-import android.graphics.Region.Op;
-
-import java.awt.AlphaComposite;
-import java.awt.BasicStroke;
-import java.awt.Color;
-import java.awt.Composite;
-import java.awt.Graphics2D;
-import java.awt.Rectangle;
-import java.awt.RenderingHints;
-import java.awt.geom.AffineTransform;
-import java.awt.image.BufferedImage;
-import java.util.List;
-import java.util.Stack;
-
-/**
- * Re-implementation of the Canvas, 100% in java on top of a BufferedImage.
- */
-public class Canvas extends _Original_Canvas {
-
-    private BufferedImage mBufferedImage;
-    private final Stack<Graphics2D> mGraphicsStack = new Stack<Graphics2D>();
-    private final ILayoutLog mLogger;
-
-    public Canvas() {
-        mLogger = null;
-        // the mBufferedImage will be taken from a bitmap in #setBitmap()
-    }
-
-    public Canvas(Bitmap bitmap) {
-        mLogger = null;
-        mBufferedImage = bitmap.getImage();
-        mGraphicsStack.push(mBufferedImage.createGraphics());
-    }
-
-    public Canvas(int nativeCanvas) {
-        mLogger = null;
-        throw new UnsupportedOperationException("Can't create Canvas(int)");
-    }
-
-    // custom constructors for our use.
-    public Canvas(int width, int height, ILayoutLog logger) {
-        mLogger = logger;
-        mBufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
-        mGraphicsStack.push(mBufferedImage.createGraphics());
-    }
-
-    public Canvas(int width, int height) {
-        this(width, height, null /* logger*/);
-    }
-
-    // custom mehtods
-    public BufferedImage getImage() {
-        return mBufferedImage;
-    }
-
-    public Graphics2D getGraphics2d() {
-        return mGraphicsStack.peek();
-    }
-
-    public void dispose() {
-        while (mGraphicsStack.size() > 0) {
-            mGraphicsStack.pop().dispose();
-        }
-    }
-
-    /**
-     * Creates a new {@link Graphics2D} based on the {@link Paint} parameters.
-     * <p/>The object must be disposed ({@link Graphics2D#dispose()}) after being used.
-     */
-    private Graphics2D getCustomGraphics(Paint paint) {
-        // make new one
-        Graphics2D g = getGraphics2d();
-        g = (Graphics2D)g.create();
-
-        // configure it
-        g.setColor(new Color(paint.getColor()));
-        int alpha = paint.getAlpha();
-        float falpha = alpha / 255.f;
-
-        Style style = paint.getStyle();
-        if (style == Style.STROKE || style == Style.FILL_AND_STROKE) {
-            PathEffect e = paint.getPathEffect();
-            if (e instanceof DashPathEffect) {
-                DashPathEffect dpe = (DashPathEffect)e;
-                g.setStroke(new BasicStroke(
-                        paint.getStrokeWidth(),
-                        paint.getStrokeCap().getJavaCap(),
-                        paint.getStrokeJoin().getJavaJoin(),
-                        paint.getStrokeMiter(),
-                        dpe.getIntervals(),
-                        dpe.getPhase()));
-            } else {
-                g.setStroke(new BasicStroke(
-                        paint.getStrokeWidth(),
-                        paint.getStrokeCap().getJavaCap(),
-                        paint.getStrokeJoin().getJavaJoin(),
-                        paint.getStrokeMiter()));
-            }
-        }
-
-        Xfermode xfermode = paint.getXfermode();
-        if (xfermode instanceof PorterDuffXfermode) {
-            PorterDuff.Mode mode = ((PorterDuffXfermode)xfermode).getMode();
-
-            setModeInGraphics(mode, g, falpha);
-        } else {
-            if (mLogger != null && xfermode != null) {
-                mLogger.warning(String.format(
-                        "Xfermode '%1$s' is not supported in the Layout Editor.",
-                        xfermode.getClass().getCanonicalName()));
-            }
-            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, falpha));
-        }
-
-        Shader shader = paint.getShader();
-        if (shader != null) {
-            java.awt.Paint shaderPaint = shader.getJavaPaint();
-            if (shaderPaint != null) {
-                g.setPaint(shaderPaint);
-            } else {
-                if (mLogger != null) {
-                    mLogger.warning(String.format(
-                            "Shader '%1$s' is not supported in the Layout Editor.",
-                            shader.getClass().getCanonicalName()));
-                }
-            }
-        }
-
-        return g;
-    }
-
-    private void setModeInGraphics(PorterDuff.Mode mode, Graphics2D g, float falpha) {
-        switch (mode) {
-            case CLEAR:
-                g.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, falpha));
-                break;
-            case DARKEN:
-                break;
-            case DST:
-                g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST, falpha));
-                break;
-            case DST_ATOP:
-                g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_ATOP, falpha));
-                break;
-            case DST_IN:
-                g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_IN, falpha));
-                break;
-            case DST_OUT:
-                g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_OUT, falpha));
-                break;
-            case DST_OVER:
-                g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_OVER, falpha));
-                break;
-            case LIGHTEN:
-                break;
-            case MULTIPLY:
-                break;
-            case SCREEN:
-                break;
-            case SRC:
-                g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC, falpha));
-                break;
-            case SRC_ATOP:
-                g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, falpha));
-                break;
-            case SRC_IN:
-                g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_IN, falpha));
-                break;
-            case SRC_OUT:
-                g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OUT, falpha));
-                break;
-            case SRC_OVER:
-                g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, falpha));
-                break;
-            case XOR:
-                g.setComposite(AlphaComposite.getInstance(AlphaComposite.XOR, falpha));
-                break;
-        }
-    }
-
-
-    // --------------------
-    // OVERRIDEN ENUMS
-    // This is needed since we rename Canvas into _Original_Canvas
-    // --------------------
-
-    public enum EdgeType {
-        BW(0),  //!< treat edges by just rounding to nearest pixel boundary
-        AA(1);  //!< treat edges by rounding-out, since they may be antialiased
-
-        EdgeType(int nativeInt) {
-            this.nativeInt = nativeInt;
-        }
-        final int nativeInt;
-    }
-
-
-    // --------------------
-    // OVERRIDEN METHODS
-    // --------------------
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#setBitmap(android.graphics.Bitmap)
-     */
-    @Override
-    public void setBitmap(Bitmap bitmap) {
-        mBufferedImage = bitmap.getImage();
-        mGraphicsStack.push(mBufferedImage.createGraphics());
-    }
-
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#translate(float, float)
-     */
-    @Override
-    public void translate(float dx, float dy) {
-        getGraphics2d().translate(dx, dy);
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#save()
-     */
-    @Override
-    public int save() {
-        // get the current save count
-        int count = mGraphicsStack.size();
-
-        // create a new graphics and add it to the stack
-        Graphics2D g = (Graphics2D)getGraphics2d().create();
-        mGraphicsStack.push(g);
-
-        // return the old save count
-        return count;
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#save(int)
-     */
-    @Override
-    public int save(int saveFlags) {
-        // For now we ignore saveFlags
-        return save();
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#restore()
-     */
-    @Override
-    public void restore() {
-        mGraphicsStack.pop();
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#restoreToCount(int)
-     */
-    @Override
-    public void restoreToCount(int saveCount) {
-        while (mGraphicsStack.size() > saveCount) {
-            mGraphicsStack.pop();
-        }
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#getSaveCount()
-     */
-    @Override
-    public int getSaveCount() {
-        return mGraphicsStack.size();
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#clipRect(float, float, float, float, android.graphics.Region.Op)
-     */
-    @Override
-    public boolean clipRect(float left, float top, float right, float bottom, Op op) {
-        return clipRect(left, top, right, bottom);
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#clipRect(float, float, float, float)
-     */
-    @Override
-    public boolean clipRect(float left, float top, float right, float bottom) {
-        getGraphics2d().clipRect((int)left, (int)top, (int)(right-left), (int)(bottom-top));
-        return true;
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#clipRect(int, int, int, int)
-     */
-    @Override
-    public boolean clipRect(int left, int top, int right, int bottom) {
-        getGraphics2d().clipRect(left, top, right-left, bottom-top);
-        return true;
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#clipRect(android.graphics.Rect, android.graphics.Region.Op)
-     */
-    @Override
-    public boolean clipRect(Rect rect, Op op) {
-        return clipRect(rect.left, rect.top, rect.right, rect.bottom);
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#clipRect(android.graphics.Rect)
-     */
-    @Override
-    public boolean clipRect(Rect rect) {
-        return clipRect(rect.left, rect.top, rect.right, rect.bottom);
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#clipRect(android.graphics.RectF, android.graphics.Region.Op)
-     */
-    @Override
-    public boolean clipRect(RectF rect, Op op) {
-        return clipRect(rect.left, rect.top, rect.right, rect.bottom);
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#clipRect(android.graphics.RectF)
-     */
-    @Override
-    public boolean clipRect(RectF rect) {
-        return clipRect(rect.left, rect.top, rect.right, rect.bottom);
-    }
-
-    public boolean quickReject(RectF rect, EdgeType type) {
-        return false;
-    }
-
-    @Override
-    public boolean quickReject(RectF rect, _Original_Canvas.EdgeType type) {
-        throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
-    }
-
-    public boolean quickReject(Path path, EdgeType type) {
-        return false;
-    }
-
-    @Override
-    public boolean quickReject(Path path, _Original_Canvas.EdgeType type) {
-        throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
-    }
-
-    public boolean quickReject(float left, float top, float right, float bottom,
-                               EdgeType type) {
-        return false;
-    }
-
-    @Override
-    public boolean quickReject(float left, float top, float right, float bottom,
-                               _Original_Canvas.EdgeType type) {
-        throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
-    }
-
-    /**
-     * Retrieve the clip bounds, returning true if they are non-empty.
-     *
-     * @param bounds Return the clip bounds here. If it is null, ignore it but
-     *               still return true if the current clip is non-empty.
-     * @return true if the current clip is non-empty.
-     */
-    @Override
-    public boolean getClipBounds(Rect bounds) {
-        Rectangle rect = getGraphics2d().getClipBounds();
-        if (rect != null) {
-            bounds.left = rect.x;
-            bounds.top = rect.y;
-            bounds.right = rect.x + rect.width;
-            bounds.bottom = rect.y + rect.height;
-            return true;
-        }
-        return false;
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#drawColor(int, android.graphics.PorterDuff.Mode)
-     */
-    @Override
-    public void drawColor(int color, PorterDuff.Mode mode) {
-        Graphics2D g = getGraphics2d();
-
-        // save old color
-        Color c = g.getColor();
-
-        Composite composite = g.getComposite();
-
-        // get the alpha from the color
-        int alpha = color >>> 24;
-        float falpha = alpha / 255.f;
-
-        setModeInGraphics(mode, g, falpha);
-
-        g.setColor(new Color(color));
-
-        g.fillRect(0, 0, getWidth(), getHeight());
-
-        g.setComposite(composite);
-
-        // restore color
-        g.setColor(c);
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#drawColor(int)
-     */
-    @Override
-    public void drawColor(int color) {
-        drawColor(color, PorterDuff.Mode.SRC_OVER);
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#drawARGB(int, int, int, int)
-     */
-    @Override
-    public void drawARGB(int a, int r, int g, int b) {
-        drawColor(a << 24 | r << 16 | g << 8 | b, PorterDuff.Mode.SRC_OVER);
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#drawRGB(int, int, int)
-     */
-    @Override
-    public void drawRGB(int r, int g, int b) {
-        drawColor(0xFF << 24 | r << 16 | g << 8 | b, PorterDuff.Mode.SRC_OVER);
-    }
-
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#getWidth()
-     */
-    @Override
-    public int getWidth() {
-        return mBufferedImage.getWidth();
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#getHeight()
-     */
-    @Override
-    public int getHeight() {
-        return mBufferedImage.getHeight();
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#drawPaint(android.graphics.Paint)
-     */
-    @Override
-    public void drawPaint(Paint paint) {
-        drawColor(paint.getColor());
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#drawBitmap(android.graphics.Bitmap, float, float, android.graphics.Paint)
-     */
-    @Override
-    public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
-        drawBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(),
-                (int)left, (int)top,
-                (int)left+bitmap.getWidth(), (int)top+bitmap.getHeight(), paint);
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#drawBitmap(android.graphics.Bitmap, android.graphics.Matrix, android.graphics.Paint)
-     */
-    @Override
-    public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
-        boolean needsRestore = false;
-        if (matrix.isIdentity() == false) {
-            // create a new graphics and apply the matrix to it
-            save(); // this creates a new Graphics2D, and stores it for children call to use
-            needsRestore = true;
-            Graphics2D g = getGraphics2d(); // get the newly create Graphics2D
-
-            // get the Graphics2D current matrix
-            AffineTransform currentTx = g.getTransform();
-            // get the AffineTransform from the matrix
-            AffineTransform matrixTx = Matrix_Delegate.getAffineTransform(matrix);
-
-            // combine them so that the matrix is applied after.
-            currentTx.preConcatenate(matrixTx);
-
-            // give it to the graphics as a new matrix replacing all previous transform
-            g.setTransform(currentTx);
-        }
-
-        // draw the bitmap
-        drawBitmap(bitmap, 0, 0, paint);
-
-        if (needsRestore) {
-            // remove the new graphics
-            restore();
-        }
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#drawBitmap(android.graphics.Bitmap, android.graphics.Rect, android.graphics.Rect, android.graphics.Paint)
-     */
-    @Override
-    public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
-        if (src == null) {
-            drawBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(),
-                    dst.left, dst.top, dst.right, dst.bottom, paint);
-        } else {
-            drawBitmap(bitmap, src.left, src.top, src.width(), src.height(),
-                    dst.left, dst.top, dst.right, dst.bottom, paint);
-        }
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#drawBitmap(android.graphics.Bitmap, android.graphics.Rect, android.graphics.RectF, android.graphics.Paint)
-     */
-    @Override
-    public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
-        if (src == null) {
-            drawBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(),
-                    (int)dst.left, (int)dst.top, (int)dst.right, (int)dst.bottom, paint);
-        } else {
-            drawBitmap(bitmap, src.left, src.top, src.width(), src.height(),
-                    (int)dst.left, (int)dst.top, (int)dst.right, (int)dst.bottom, paint);
-        }
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#drawBitmap(int[], int, int, int, int, int, int, boolean, android.graphics.Paint)
-     */
-    @Override
-    public void drawBitmap(int[] colors, int offset, int stride, int x, int y, int width,
-            int height, boolean hasAlpha, Paint paint) {
-        throw new UnsupportedOperationException();
-    }
-
-    private void drawBitmap(Bitmap bitmap, int sleft, int stop, int sright, int sbottom, int dleft,
-            int dtop, int dright, int dbottom, Paint paint) {
-        BufferedImage image = bitmap.getImage();
-
-        Graphics2D g = getGraphics2d();
-
-        Composite c = null;
-
-        if (paint != null) {
-            if (paint.isFilterBitmap()) {
-                g = (Graphics2D)g.create();
-                g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
-                        RenderingHints.VALUE_INTERPOLATION_BILINEAR);
-            }
-
-            if (paint.getAlpha() != 0xFF) {
-                c = g.getComposite();
-                g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
-                        paint.getAlpha()/255.f));
-            }
-        }
-
-        g.drawImage(image, dleft, dtop, dright, dbottom,
-                sleft, stop, sright, sbottom, null);
-
-        if (paint != null) {
-            if (paint.isFilterBitmap()) {
-                g.dispose();
-            }
-            if (c != null) {
-                g.setComposite(c);
-            }
-        }
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#rotate(float, float, float)
-     */
-    @Override
-    public void rotate(float degrees, float px, float py) {
-        if (degrees != 0) {
-            Graphics2D g = getGraphics2d();
-            g.translate(px, py);
-            g.rotate(Math.toRadians(degrees));
-            g.translate(-px, -py);
-        }
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#rotate(float)
-     */
-    @Override
-    public void rotate(float degrees) {
-        getGraphics2d().rotate(Math.toRadians(degrees));
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#scale(float, float, float, float)
-     */
-    @Override
-    public void scale(float sx, float sy, float px, float py) {
-        Graphics2D g = getGraphics2d();
-        g.translate(px, py);
-        g.scale(sx, sy);
-        g.translate(-px, -py);
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#scale(float, float)
-     */
-    @Override
-    public void scale(float sx, float sy) {
-        getGraphics2d().scale(sx, sy);
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#drawText(char[], int, int, float, float, android.graphics.Paint)
-     */
-    @Override
-    public void drawText(char[] text, int index, int count, float x, float y, Paint paint) {
-        // WARNING: the logic in this method is similar to Paint.measureText.
-        // Any change to this method should be reflected in Paint.measureText
-        Graphics2D g = getGraphics2d();
-
-        g = (Graphics2D)g.create();
-        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
-
-        // set the color. because this only handles RGB, the alpha channel is handled
-        // as a composite.
-        g.setColor(new Color(paint.getColor()));
-        int alpha = paint.getAlpha();
-        float falpha = alpha / 255.f;
-        g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, falpha));
-
-
-        // Paint.TextAlign indicates how the text is positioned relative to X.
-        // LEFT is the default and there's nothing to do.
-        if (paint.getTextAlign() != Align.LEFT) {
-            float m = paint.measureText(text, index, count);
-            if (paint.getTextAlign() == Align.CENTER) {
-                x -= m / 2;
-            } else if (paint.getTextAlign() == Align.RIGHT) {
-                x -= m;
-            }
-        }
-
-        List<FontInfo> fonts = paint.getFonts();
-        try {
-            if (fonts.size() > 0) {
-                FontInfo mainFont = fonts.get(0);
-                int i = index;
-                int lastIndex = index + count;
-                while (i < lastIndex) {
-                    // always start with the main font.
-                    int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex);
-                    if (upTo == -1) {
-                        // draw all the rest and exit.
-                        g.setFont(mainFont.mFont);
-                        g.drawChars(text, i, lastIndex - i, (int)x, (int)y);
-                        return;
-                    } else if (upTo > 0) {
-                        // draw what's possible
-                        g.setFont(mainFont.mFont);
-                        g.drawChars(text, i, upTo - i, (int)x, (int)y);
-
-                        // compute the width that was drawn to increase x
-                        x += mainFont.mMetrics.charsWidth(text, i, upTo - i);
-
-                        // move index to the first non displayed char.
-                        i = upTo;
-
-                        // don't call continue at this point. Since it is certain the main font
-                        // cannot display the font a index upTo (now ==i), we move on to the
-                        // fallback fonts directly.
-                    }
-
-                    // no char supported, attempt to read the next char(s) with the
-                    // fallback font. In this case we only test the first character
-                    // and then go back to test with the main font.
-                    // Special test for 2-char characters.
-                    boolean foundFont = false;
-                    for (int f = 1 ; f < fonts.size() ; f++) {
-                        FontInfo fontInfo = fonts.get(f);
-
-                        // need to check that the font can display the character. We test
-                        // differently if the char is a high surrogate.
-                        int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
-                        upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount);
-                        if (upTo == -1) {
-                            // draw that char
-                            g.setFont(fontInfo.mFont);
-                            g.drawChars(text, i, charCount, (int)x, (int)y);
-
-                            // update x
-                            x += fontInfo.mMetrics.charsWidth(text, i, charCount);
-
-                            // update the index in the text, and move on
-                            i += charCount;
-                            foundFont = true;
-                            break;
-
-                        }
-                    }
-
-                    // in case no font can display the char, display it with the main font.
-                    // (it'll put a square probably)
-                    if (foundFont == false) {
-                        int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
-
-                        g.setFont(mainFont.mFont);
-                        g.drawChars(text, i, charCount, (int)x, (int)y);
-
-                        // measure it to advance x
-                        x += mainFont.mMetrics.charsWidth(text, i, charCount);
-
-                        // and move to the next chars.
-                        i += charCount;
-                    }
-                }
-            }
-        } finally {
-            g.dispose();
-        }
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#drawText(java.lang.CharSequence, int, int, float, float, android.graphics.Paint)
-     */
-    @Override
-    public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
-        drawText(text.toString().toCharArray(), start, end - start, x, y, paint);
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#drawText(java.lang.String, float, float, android.graphics.Paint)
-     */
-    @Override
-    public void drawText(String text, float x, float y, Paint paint) {
-        drawText(text.toCharArray(), 0, text.length(), x, y, paint);
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#drawText(java.lang.String, int, int, float, float, android.graphics.Paint)
-     */
-    @Override
-    public void drawText(String text, int start, int end, float x, float y, Paint paint) {
-        drawText(text.toCharArray(), start, end - start, x, y, paint);
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#drawRect(android.graphics.RectF, android.graphics.Paint)
-     */
-    @Override
-    public void drawRect(RectF rect, Paint paint) {
-        doDrawRect((int)rect.left, (int)rect.top, (int)rect.width(), (int)rect.height(), paint);
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#drawRect(float, float, float, float, android.graphics.Paint)
-     */
-    @Override
-    public void drawRect(float left, float top, float right, float bottom, Paint paint) {
-        doDrawRect((int)left, (int)top, (int)(right-left), (int)(bottom-top), paint);
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#drawRect(android.graphics.Rect, android.graphics.Paint)
-     */
-    @Override
-    public void drawRect(Rect r, Paint paint) {
-        doDrawRect(r.left, r.top, r.width(), r.height(), paint);
-    }
-
-    private final void doDrawRect(int left, int top, int width, int height, Paint paint) {
-        if (width > 0 && height > 0) {
-            // get a Graphics2D object configured with the drawing parameters.
-            Graphics2D g = getCustomGraphics(paint);
-
-            Style style = paint.getStyle();
-
-            // draw
-            if (style == Style.FILL || style == Style.FILL_AND_STROKE) {
-                g.fillRect(left, top, width, height);
-            }
-
-            if (style == Style.STROKE || style == Style.FILL_AND_STROKE) {
-                g.drawRect(left, top, width, height);
-            }
-
-            // dispose Graphics2D object
-            g.dispose();
-        }
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#drawRoundRect(android.graphics.RectF, float, float, android.graphics.Paint)
-     */
-    @Override
-    public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) {
-        if (rect.width() > 0 && rect.height() > 0) {
-            // get a Graphics2D object configured with the drawing parameters.
-            Graphics2D g = getCustomGraphics(paint);
-
-            Style style = paint.getStyle();
-
-            // draw
-
-            int arcWidth = (int)(rx * 2);
-            int arcHeight = (int)(ry * 2);
-
-            if (style == Style.FILL || style == Style.FILL_AND_STROKE) {
-                g.fillRoundRect((int)rect.left, (int)rect.top, (int)rect.width(), (int)rect.height(),
-                        arcWidth, arcHeight);
-            }
-
-            if (style == Style.STROKE || style == Style.FILL_AND_STROKE) {
-                g.drawRoundRect((int)rect.left, (int)rect.top, (int)rect.width(), (int)rect.height(),
-                        arcWidth, arcHeight);
-            }
-
-            // dispose Graphics2D object
-            g.dispose();
-        }
-    }
-
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#drawLine(float, float, float, float, android.graphics.Paint)
-     */
-    @Override
-    public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) {
-        // get a Graphics2D object configured with the drawing parameters.
-        Graphics2D g = getCustomGraphics(paint);
-
-        g.drawLine((int)startX, (int)startY, (int)stopX, (int)stopY);
-
-        // dispose Graphics2D object
-        g.dispose();
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#drawLines(float[], int, int, android.graphics.Paint)
-     */
-    @Override
-    public void drawLines(float[] pts, int offset, int count, Paint paint) {
-        // get a Graphics2D object configured with the drawing parameters.
-        Graphics2D g = getCustomGraphics(paint);
-
-        for (int i = 0 ; i < count ; i += 4) {
-            g.drawLine((int)pts[i + offset], (int)pts[i + offset + 1],
-                    (int)pts[i + offset + 2], (int)pts[i + offset + 3]);
-        }
-
-        // dispose Graphics2D object
-        g.dispose();
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#drawLines(float[], android.graphics.Paint)
-     */
-    @Override
-    public void drawLines(float[] pts, Paint paint) {
-        drawLines(pts, 0, pts.length, paint);
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#drawCircle(float, float, float, android.graphics.Paint)
-     */
-    @Override
-    public void drawCircle(float cx, float cy, float radius, Paint paint) {
-        // get a Graphics2D object configured with the drawing parameters.
-        Graphics2D g = getCustomGraphics(paint);
-
-        Style style = paint.getStyle();
-
-        int size = (int)(radius * 2);
-
-        // draw
-        if (style == Style.FILL || style == Style.FILL_AND_STROKE) {
-            g.fillOval((int)(cx - radius), (int)(cy - radius), size, size);
-        }
-
-        if (style == Style.STROKE || style == Style.FILL_AND_STROKE) {
-            g.drawOval((int)(cx - radius), (int)(cy - radius), size, size);
-        }
-
-        // dispose Graphics2D object
-        g.dispose();
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#drawOval(android.graphics.RectF, android.graphics.Paint)
-     */
-    @Override
-    public void drawOval(RectF oval, Paint paint) {
-        // get a Graphics2D object configured with the drawing parameters.
-        Graphics2D g = getCustomGraphics(paint);
-
-        Style style = paint.getStyle();
-
-        // draw
-        if (style == Style.FILL || style == Style.FILL_AND_STROKE) {
-            g.fillOval((int)oval.left, (int)oval.top, (int)oval.width(), (int)oval.height());
-        }
-
-        if (style == Style.STROKE || style == Style.FILL_AND_STROKE) {
-            g.drawOval((int)oval.left, (int)oval.top, (int)oval.width(), (int)oval.height());
-        }
-
-        // dispose Graphics2D object
-        g.dispose();
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#drawPath(android.graphics.Path, android.graphics.Paint)
-     */
-    @Override
-    public void drawPath(Path path, Paint paint) {
-        // get a Graphics2D object configured with the drawing parameters.
-        Graphics2D g = getCustomGraphics(paint);
-
-        Style style = paint.getStyle();
-
-        // draw
-        if (style == Style.FILL || style == Style.FILL_AND_STROKE) {
-            g.fill(path.getAwtShape());
-        }
-
-        if (style == Style.STROKE || style == Style.FILL_AND_STROKE) {
-            g.draw(path.getAwtShape());
-        }
-
-        // dispose Graphics2D object
-        g.dispose();
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#setMatrix(android.graphics.Matrix)
-     */
-    @Override
-    public void setMatrix(Matrix matrix) {
-        // get the new current graphics
-        Graphics2D g = getGraphics2d();
-
-        // and apply the matrix
-        g.setTransform(Matrix_Delegate.getAffineTransform(matrix));
-
-        if (mLogger != null && Matrix_Delegate.hasPerspective(matrix)) {
-            mLogger.warning("android.graphics.Canvas#setMatrix(android.graphics.Matrix) only supports affine transformations in the Layout Editor.");
-        }
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#concat(android.graphics.Matrix)
-     */
-    @Override
-    public void concat(Matrix matrix) {
-        // get the current top graphics2D object.
-        Graphics2D g = getGraphics2d();
-
-        // get its current matrix
-        AffineTransform currentTx = g.getTransform();
-        // get the AffineTransform of the given matrix
-        AffineTransform matrixTx = Matrix_Delegate.getAffineTransform(matrix);
-
-        // combine them so that the given matrix is applied after.
-        currentTx.preConcatenate(matrixTx);
-
-        // give it to the graphics2D as a new matrix replacing all previous transform
-        g.setTransform(currentTx);
-    }
-
-
-    // --------------------
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#clipPath(android.graphics.Path, android.graphics.Region.Op)
-     */
-    @Override
-    public boolean clipPath(Path path, Op op) {
-        // TODO Auto-generated method stub
-        return super.clipPath(path, op);
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#clipPath(android.graphics.Path)
-     */
-    @Override
-    public boolean clipPath(Path path) {
-        // TODO Auto-generated method stub
-        return super.clipPath(path);
-    }
-
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#clipRegion(android.graphics.Region, android.graphics.Region.Op)
-     */
-    @Override
-    public boolean clipRegion(Region region, Op op) {
-        // TODO Auto-generated method stub
-        return super.clipRegion(region, op);
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#clipRegion(android.graphics.Region)
-     */
-    @Override
-    public boolean clipRegion(Region region) {
-        // TODO Auto-generated method stub
-        return super.clipRegion(region);
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#drawArc(android.graphics.RectF, float, float, boolean, android.graphics.Paint)
-     */
-    @Override
-    public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,
-            Paint paint) {
-        // TODO Auto-generated method stub
-        super.drawArc(oval, startAngle, sweepAngle, useCenter, paint);
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#drawBitmapMesh(android.graphics.Bitmap, int, int, float[], int, int[], int, android.graphics.Paint)
-     */
-    @Override
-    public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts,
-            int vertOffset, int[] colors, int colorOffset, Paint paint) {
-        // TODO Auto-generated method stub
-        super.drawBitmapMesh(bitmap, meshWidth, meshHeight, verts, vertOffset, colors, colorOffset, paint);
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#drawPicture(android.graphics.Picture, android.graphics.Rect)
-     */
-    @Override
-    public void drawPicture(Picture picture, Rect dst) {
-        // TODO Auto-generated method stub
-        super.drawPicture(picture, dst);
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#drawPicture(android.graphics.Picture, android.graphics.RectF)
-     */
-    @Override
-    public void drawPicture(Picture picture, RectF dst) {
-        // TODO Auto-generated method stub
-        super.drawPicture(picture, dst);
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#drawPicture(android.graphics.Picture)
-     */
-    @Override
-    public void drawPicture(Picture picture) {
-        // TODO Auto-generated method stub
-        super.drawPicture(picture);
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#drawPoint(float, float, android.graphics.Paint)
-     */
-    @Override
-    public void drawPoint(float x, float y, Paint paint) {
-        // TODO Auto-generated method stub
-        super.drawPoint(x, y, paint);
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#drawPoints(float[], int, int, android.graphics.Paint)
-     */
-    @Override
-    public void drawPoints(float[] pts, int offset, int count, Paint paint) {
-        // TODO Auto-generated method stub
-        super.drawPoints(pts, offset, count, paint);
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#drawPoints(float[], android.graphics.Paint)
-     */
-    @Override
-    public void drawPoints(float[] pts, Paint paint) {
-        // TODO Auto-generated method stub
-        super.drawPoints(pts, paint);
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#drawPosText(char[], int, int, float[], android.graphics.Paint)
-     */
-    @Override
-    public void drawPosText(char[] text, int index, int count, float[] pos, Paint paint) {
-        // TODO Auto-generated method stub
-        super.drawPosText(text, index, count, pos, paint);
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#drawPosText(java.lang.String, float[], android.graphics.Paint)
-     */
-    @Override
-    public void drawPosText(String text, float[] pos, Paint paint) {
-        // TODO Auto-generated method stub
-        super.drawPosText(text, pos, paint);
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#drawTextOnPath(char[], int, int, android.graphics.Path, float, float, android.graphics.Paint)
-     */
-    @Override
-    public void drawTextOnPath(char[] text, int index, int count, Path path, float offset,
-            float offset2, Paint paint) {
-        // TODO Auto-generated method stub
-        super.drawTextOnPath(text, index, count, path, offset, offset2, paint);
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#drawTextOnPath(java.lang.String, android.graphics.Path, float, float, android.graphics.Paint)
-     */
-    @Override
-    public void drawTextOnPath(String text, Path path, float offset, float offset2, Paint paint) {
-        // TODO Auto-generated method stub
-        super.drawTextOnPath(text, path, offset, offset2, paint);
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#drawVertices(android.graphics.Canvas.VertexMode, int, float[], int, float[], int, int[], int, short[], int, int, android.graphics.Paint)
-     */
-    @Override
-    public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset,
-            float[] texs, int texOffset, int[] colors, int colorOffset, short[] indices,
-            int indexOffset, int indexCount, Paint paint) {
-        // TODO Auto-generated method stub
-        super.drawVertices(mode, vertexCount, verts, vertOffset, texs, texOffset, colors, colorOffset,
-                indices, indexOffset, indexCount, paint);
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#getDrawFilter()
-     */
-    @Override
-    public DrawFilter getDrawFilter() {
-        // TODO Auto-generated method stub
-        return super.getDrawFilter();
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#getMatrix()
-     */
-    @Override
-    public Matrix getMatrix() {
-        // TODO Auto-generated method stub
-        return super.getMatrix();
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#getMatrix(android.graphics.Matrix)
-     */
-    @Override
-    public void getMatrix(Matrix ctm) {
-        // TODO Auto-generated method stub
-        super.getMatrix(ctm);
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#isOpaque()
-     */
-    @Override
-    public boolean isOpaque() {
-        // TODO Auto-generated method stub
-        return super.isOpaque();
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#saveLayer(float, float, float, float, android.graphics.Paint, int)
-     */
-    @Override
-    public int saveLayer(float left, float top, float right, float bottom, Paint paint,
-            int saveFlags) {
-        // TODO Auto-generated method stub
-        return super.saveLayer(left, top, right, bottom, paint, saveFlags);
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#saveLayer(android.graphics.RectF, android.graphics.Paint, int)
-     */
-    @Override
-    public int saveLayer(RectF bounds, Paint paint, int saveFlags) {
-        // TODO Auto-generated method stub
-        return super.saveLayer(bounds, paint, saveFlags);
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#saveLayerAlpha(float, float, float, float, int, int)
-     */
-    @Override
-    public int saveLayerAlpha(float left, float top, float right, float bottom, int alpha,
-            int saveFlags) {
-        // TODO Auto-generated method stub
-        return super.saveLayerAlpha(left, top, right, bottom, alpha, saveFlags);
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#saveLayerAlpha(android.graphics.RectF, int, int)
-     */
-    @Override
-    public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags) {
-        // TODO Auto-generated method stub
-        return super.saveLayerAlpha(bounds, alpha, saveFlags);
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#setDrawFilter(android.graphics.DrawFilter)
-     */
-    @Override
-    public void setDrawFilter(DrawFilter filter) {
-        // TODO Auto-generated method stub
-        super.setDrawFilter(filter);
-    }
-
-    /* (non-Javadoc)
-     * @see android.graphics.Canvas#skew(float, float)
-     */
-    @Override
-    public void skew(float sx, float sy) {
-        // TODO Auto-generated method stub
-        super.skew(sx, sy);
-    }
-
-
-
-}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
new file mode 100644
index 0000000..6627d37
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -0,0 +1,559 @@
+/*
+ * Copyright (C) 2010 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.graphics;
+
+import com.android.layoutlib.api.ILayoutLog;
+import com.android.layoutlib.bridge.DelegateManager;
+
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+import java.util.Stack;
+
+/**
+ * Delegate implementing the native methods of android.graphics.Canvas
+ *
+ * Through the layoutlib_create tool, the original native methods of Canvas have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original Canvas class.
+ *
+ * @see DelegateManager
+ *
+ */
+public class Canvas_Delegate {
+
+    // ---- delegate manager ----
+    private static final DelegateManager<Canvas_Delegate> sManager =
+            new DelegateManager<Canvas_Delegate>();
+
+    // ---- delegate helper data ----
+
+    // ---- delegate data ----
+    private BufferedImage mBufferedImage;
+    private final Stack<Graphics2D> mGraphicsStack = new Stack<Graphics2D>();
+    private ILayoutLog mLogger;
+
+    // ---- Public Helper methods ----
+
+    /**
+     * Returns the native delegate associated to a given {@link Canvas} object.
+     */
+    public static Canvas_Delegate getDelegate(Canvas canvas) {
+        return sManager.getDelegate(canvas.mNativeCanvas);
+    }
+
+    /**
+     * Returns the native delegate associated to a given an int referencing a {@link Canvas} object.
+     */
+    public static Canvas_Delegate getDelegate(int native_canvas) {
+        return sManager.getDelegate(native_canvas);
+    }
+
+    /**
+     * Sets the layoutlib logger into the canvas.
+     * @param logger
+     */
+    public void setLogger(ILayoutLog logger) {
+        mLogger = logger;
+    }
+
+    /**
+     * Returns the current {@link Graphics2D} used to draw.
+     */
+    public Graphics2D getGraphics2d() {
+        return mGraphicsStack.peek();
+    }
+
+    /**
+     * Disposes of the {@link Graphics2D} stack.
+     */
+    public void dispose() {
+
+    }
+
+    // ---- native methods ----
+
+    /*package*/ static boolean isOpaque(Canvas thisCanvas) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static int getWidth(Canvas thisCanvas) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static int getHeight(Canvas thisCanvas) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void translate(Canvas thisCanvas, float dx, float dy) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void rotate(Canvas thisCanvas, float degrees) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void scale(Canvas thisCanvas, float sx, float sy) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void skew(Canvas thisCanvas, float sx, float sy) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static boolean clipRect(Canvas thisCanvas, RectF rect) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static boolean clipRect(Canvas thisCanvas, Rect rect) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static boolean clipRect(Canvas thisCanvas, float left, float top, float right,
+            float bottom) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static boolean clipRect(Canvas thisCanvas, int left, int top, int right,
+            int bottom) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static int save(Canvas thisCanvas) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static int save(Canvas thisCanvas, int saveFlags) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void restore(Canvas thisCanvas) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static int getSaveCount(Canvas thisCanvas) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void restoreToCount(Canvas thisCanvas, int saveCount) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void drawPoints(Canvas thisCanvas, float[] pts, int offset, int count,
+            Paint paint) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void drawPoint(Canvas thisCanvas, float x, float y, Paint paint) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void drawLines(Canvas thisCanvas, float[] pts, int offset, int count,
+            Paint paint) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void freeCaches() {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static int initRaster(int nativeBitmapOrZero) {
+        if (nativeBitmapOrZero > 0) {
+            // get the Bitmap from the int
+            Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(nativeBitmapOrZero);
+
+            // create a new Canvas_Delegate with the given bitmap and return its new native int.
+            Canvas_Delegate newDelegate = new Canvas_Delegate(bitmapDelegate.getImage());
+
+            return sManager.addDelegate(newDelegate);
+        } else {
+            // create a new Canvas_Delegate and return its new native int.
+            Canvas_Delegate newDelegate = new Canvas_Delegate();
+
+            return sManager.addDelegate(newDelegate);
+        }
+    }
+
+    /*package*/ static void native_setBitmap(int nativeCanvas, int bitmap) {
+        // get the delegate from the native int.
+        Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+        if (canvasDelegate == null) {
+            assert false;
+            return;
+        }
+
+        // get the delegate from the native int.
+        Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap);
+        if (bitmapDelegate == null) {
+            assert false;
+            return;
+        }
+
+        canvasDelegate.setBitmap(bitmapDelegate.getImage());
+    }
+
+    /*package*/ static int native_saveLayer(int nativeCanvas, RectF bounds,
+                                               int paint, int layerFlags) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static int native_saveLayer(int nativeCanvas, float l,
+                                               float t, float r, float b,
+                                               int paint, int layerFlags) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static int native_saveLayerAlpha(int nativeCanvas,
+                                                    RectF bounds, int alpha,
+                                                    int layerFlags) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static int native_saveLayerAlpha(int nativeCanvas, float l,
+                                                    float t, float r, float b,
+                                                    int alpha, int layerFlags) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+
+    /*package*/ static void native_concat(int nCanvas, int nMatrix) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void native_setMatrix(int nCanvas, int nMatrix) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static boolean native_clipRect(int nCanvas,
+                                                  float left, float top,
+                                                  float right, float bottom,
+                                                  int regionOp) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static boolean native_clipPath(int nativeCanvas,
+                                                  int nativePath,
+                                                  int regionOp) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static boolean native_clipRegion(int nativeCanvas,
+                                                    int nativeRegion,
+                                                    int regionOp) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void nativeSetDrawFilter(int nativeCanvas,
+                                                   int nativeFilter) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static boolean native_getClipBounds(int nativeCanvas,
+                                                       Rect bounds) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void native_getCTM(int canvas, int matrix) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static boolean native_quickReject(int nativeCanvas,
+                                                     RectF rect,
+                                                     int native_edgeType) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static boolean native_quickReject(int nativeCanvas,
+                                                     int path,
+                                                     int native_edgeType) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static boolean native_quickReject(int nativeCanvas,
+                                                     float left, float top,
+                                                     float right, float bottom,
+                                                     int native_edgeType) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void native_drawRGB(int nativeCanvas, int r, int g,
+                                              int b) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void native_drawARGB(int nativeCanvas, int a, int r,
+                                               int g, int b) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void native_drawColor(int nativeCanvas, int color) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void native_drawColor(int nativeCanvas, int color,
+                                                int mode) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void native_drawPaint(int nativeCanvas, int paint) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void native_drawLine(int nativeCanvas, float startX,
+                                               float startY, float stopX,
+                                               float stopY, int paint) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void native_drawRect(int nativeCanvas, RectF rect,
+                                               int paint) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void native_drawRect(int nativeCanvas, float left,
+                                               float top, float right,
+                                               float bottom, int paint) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void native_drawOval(int nativeCanvas, RectF oval,
+                                               int paint) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void native_drawCircle(int nativeCanvas, float cx,
+                                                 float cy, float radius,
+                                                 int paint) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void native_drawArc(int nativeCanvas, RectF oval,
+                                              float startAngle, float sweep,
+                                              boolean useCenter, int paint) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void native_drawRoundRect(int nativeCanvas,
+                                                    RectF rect, float rx,
+                                                    float ry, int paint) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void native_drawPath(int nativeCanvas, int path,
+                                               int paint) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void native_drawBitmap(Canvas thisCanvas, int nativeCanvas, int bitmap,
+                                                 float left, float top,
+                                                 int nativePaintOrZero,
+                                                 int canvasDensity,
+                                                 int screenDensity,
+                                                 int bitmapDensity) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void native_drawBitmap(Canvas thisCanvas, int nativeCanvas, int bitmap,
+                                                 Rect src, RectF dst,
+                                                 int nativePaintOrZero,
+                                                 int screenDensity,
+                                                 int bitmapDensity) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void native_drawBitmap(int nativeCanvas, int bitmap,
+                                                 Rect src, Rect dst,
+                                                 int nativePaintOrZero,
+                                                 int screenDensity,
+                                                 int bitmapDensity) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void native_drawBitmap(int nativeCanvas, int[] colors,
+                                                int offset, int stride, float x,
+                                                 float y, int width, int height,
+                                                 boolean hasAlpha,
+                                                 int nativePaintOrZero) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void nativeDrawBitmapMatrix(int nCanvas, int nBitmap,
+                                                      int nMatrix, int nPaint) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void nativeDrawBitmapMesh(int nCanvas, int nBitmap,
+                                                    int meshWidth, int meshHeight,
+                                                    float[] verts, int vertOffset,
+                                                    int[] colors, int colorOffset, int nPaint) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void nativeDrawVertices(int nCanvas, int mode, int n,
+                   float[] verts, int vertOffset, float[] texs, int texOffset,
+                   int[] colors, int colorOffset, short[] indices,
+                   int indexOffset, int indexCount, int nPaint) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+
+    /*package*/ static void native_drawText(int nativeCanvas, char[] text,
+                                               int index, int count, float x,
+                                               float y, int flags, int paint) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void native_drawText(int nativeCanvas, String text,
+                                               int start, int end, float x,
+                                               float y, int flags, int paint) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+
+    /*package*/ static void native_drawTextRun(int nativeCanvas, String text,
+            int start, int end, int contextStart, int contextEnd,
+            float x, float y, int flags, int paint) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+
+    /*package*/ static void native_drawTextRun(int nativeCanvas, char[] text,
+            int start, int count, int contextStart, int contextCount,
+            float x, float y, int flags, int paint) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+
+    /*package*/ static void native_drawPosText(int nativeCanvas,
+                                                  char[] text, int index,
+                                                  int count, float[] pos,
+                                                  int paint) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void native_drawPosText(int nativeCanvas,
+                                                  String text, float[] pos,
+                                                  int paint) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void native_drawTextOnPath(int nativeCanvas,
+                                                     char[] text, int index,
+                                                     int count, int path,
+                                                     float hOffset,
+                                                     float vOffset, int bidiFlags,
+                                                     int paint) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void native_drawTextOnPath(int nativeCanvas,
+                                                     String text, int path,
+                                                     float hOffset,
+                                                     float vOffset,
+                                                     int flags, int paint) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void native_drawPicture(int nativeCanvas,
+                                                  int nativePicture) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void finalizer(int nativeCanvas) {
+        sManager.removeDelegate(nativeCanvas);
+    }
+
+    // ---- Private delegate/helper methods ----
+
+    private Canvas_Delegate(BufferedImage image) {
+        setBitmap(image);
+    }
+
+    private Canvas_Delegate() {
+    }
+
+    private void setBitmap(BufferedImage image) {
+        mBufferedImage = image;
+        mGraphicsStack.push(mBufferedImage.createGraphics());
+    }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
index ed2eff2..cc4a80c 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
@@ -76,7 +76,7 @@
 
     // ---- native methods ----
 
-    public static int native_create(int native_src_or_zero) {
+    /*package*/ static int native_create(int native_src_or_zero) {
         // create the delegate
         Matrix_Delegate newDelegate = new Matrix_Delegate();
 
@@ -94,7 +94,7 @@
         return sManager.addDelegate(newDelegate);
     }
 
-    public static boolean native_isIdentity(int native_object) {
+    /*package*/ static boolean native_isIdentity(int native_object) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -112,7 +112,7 @@
         return true;
     }
 
-    public static boolean native_rectStaysRect(int native_object) {
+    /*package*/ static boolean native_rectStaysRect(int native_object) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -122,7 +122,7 @@
         return (d.computeTypeMask() & kRectStaysRect_Mask) != 0;
     }
 
-    public static void native_reset(int native_object) {
+    /*package*/ static void native_reset(int native_object) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -132,7 +132,7 @@
         reset(d.mValues);
     }
 
-    public static void native_set(int native_object, int other) {
+    /*package*/ static void native_set(int native_object, int other) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -148,7 +148,7 @@
         System.arraycopy(src.mValues, 0, d.mValues, 0, MATRIX_SIZE);
     }
 
-    public static void native_setTranslate(int native_object, float dx, float dy) {
+    /*package*/ static void native_setTranslate(int native_object, float dx, float dy) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -158,7 +158,7 @@
         setTranslate(d.mValues, dx, dy);
     }
 
-    public static void native_setScale(int native_object, float sx, float sy, float px, float py) {
+    /*package*/ static void native_setScale(int native_object, float sx, float sy, float px, float py) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -168,7 +168,7 @@
         d.mValues = getScale(sx, sy, px, py);
     }
 
-    public static void native_setScale(int native_object, float sx, float sy) {
+    /*package*/ static void native_setScale(int native_object, float sx, float sy) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -186,7 +186,7 @@
         d.mValues[8] = 1;
     }
 
-    public static void native_setRotate(int native_object, float degrees, float px, float py) {
+    /*package*/ static void native_setRotate(int native_object, float degrees, float px, float py) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -196,7 +196,7 @@
         d.mValues = getRotate(degrees, px, py);
     }
 
-    public static void native_setRotate(int native_object, float degrees) {
+    /*package*/ static void native_setRotate(int native_object, float degrees) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -206,7 +206,7 @@
         setRotate(d.mValues, degrees);
     }
 
-    public static void native_setSinCos(int native_object, float sinValue, float cosValue,
+    /*package*/ static void native_setSinCos(int native_object, float sinValue, float cosValue,
             float px, float py) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
@@ -225,7 +225,7 @@
         d.postTransform(getTranslate(px, py));
     }
 
-    public static void native_setSinCos(int native_object, float sinValue, float cosValue) {
+    /*package*/ static void native_setSinCos(int native_object, float sinValue, float cosValue) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -235,7 +235,7 @@
         setRotate(d.mValues, sinValue, cosValue);
     }
 
-    public static void native_setSkew(int native_object, float kx, float ky, float px, float py) {
+    /*package*/ static void native_setSkew(int native_object, float kx, float ky, float px, float py) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -245,7 +245,7 @@
         d.mValues = getSkew(kx, ky, px, py);
     }
 
-    public static void native_setSkew(int native_object, float kx, float ky) {
+    /*package*/ static void native_setSkew(int native_object, float kx, float ky) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -263,7 +263,7 @@
         d.mValues[8] = 1;
     }
 
-    public static boolean native_setConcat(int native_object, int a, int b) {
+    /*package*/ static boolean native_setConcat(int native_object, int a, int b) {
         if (a == native_object) {
             return native_preConcat(native_object, b);
         } else if (b == native_object) {
@@ -293,7 +293,7 @@
         return true;
     }
 
-    public static boolean native_preTranslate(int native_object, float dx, float dy) {
+    /*package*/ static boolean native_preTranslate(int native_object, float dx, float dy) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -304,7 +304,7 @@
         return true;
     }
 
-    public static boolean native_preScale(int native_object, float sx, float sy,
+    /*package*/ static boolean native_preScale(int native_object, float sx, float sy,
             float px, float py) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
@@ -316,7 +316,7 @@
         return true;
     }
 
-    public static boolean native_preScale(int native_object, float sx, float sy) {
+    /*package*/ static boolean native_preScale(int native_object, float sx, float sy) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -327,7 +327,7 @@
         return true;
     }
 
-    public static boolean native_preRotate(int native_object, float degrees, float px, float py) {
+    /*package*/ static boolean native_preRotate(int native_object, float degrees, float px, float py) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -338,7 +338,7 @@
         return true;
     }
 
-    public static boolean native_preRotate(int native_object, float degrees) {
+    /*package*/ static boolean native_preRotate(int native_object, float degrees) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -353,7 +353,7 @@
         return true;
     }
 
-    public static boolean native_preSkew(int native_object, float kx, float ky,
+    /*package*/ static boolean native_preSkew(int native_object, float kx, float ky,
             float px, float py) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
@@ -365,7 +365,7 @@
         return true;
     }
 
-    public static boolean native_preSkew(int native_object, float kx, float ky) {
+    /*package*/ static boolean native_preSkew(int native_object, float kx, float ky) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -376,7 +376,7 @@
         return true;
     }
 
-    public static boolean native_preConcat(int native_object, int other_matrix) {
+    /*package*/ static boolean native_preConcat(int native_object, int other_matrix) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -393,7 +393,7 @@
         return true;
     }
 
-    public static boolean native_postTranslate(int native_object, float dx, float dy) {
+    /*package*/ static boolean native_postTranslate(int native_object, float dx, float dy) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -404,7 +404,7 @@
         return true;
     }
 
-    public static boolean native_postScale(int native_object, float sx, float sy,
+    /*package*/ static boolean native_postScale(int native_object, float sx, float sy,
             float px, float py) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
@@ -416,7 +416,7 @@
         return true;
     }
 
-    public static boolean native_postScale(int native_object, float sx, float sy) {
+    /*package*/ static boolean native_postScale(int native_object, float sx, float sy) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -427,7 +427,7 @@
         return true;
     }
 
-    public static boolean native_postRotate(int native_object, float degrees, float px, float py) {
+    /*package*/ static boolean native_postRotate(int native_object, float degrees, float px, float py) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -438,7 +438,7 @@
         return true;
     }
 
-    public static boolean native_postRotate(int native_object, float degrees) {
+    /*package*/ static boolean native_postRotate(int native_object, float degrees) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -449,7 +449,7 @@
         return true;
     }
 
-    public static boolean native_postSkew(int native_object, float kx, float ky,
+    /*package*/ static boolean native_postSkew(int native_object, float kx, float ky,
             float px, float py) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
@@ -461,7 +461,7 @@
         return true;
     }
 
-    public static boolean native_postSkew(int native_object, float kx, float ky) {
+    /*package*/ static boolean native_postSkew(int native_object, float kx, float ky) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -472,7 +472,7 @@
         return true;
     }
 
-    public static boolean native_postConcat(int native_object, int other_matrix) {
+    /*package*/ static boolean native_postConcat(int native_object, int other_matrix) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -489,7 +489,7 @@
         return true;
     }
 
-    public static boolean native_setRectToRect(int native_object, RectF src, RectF dst, int stf) {
+    /*package*/ static boolean native_setRectToRect(int native_object, RectF src, RectF dst, int stf) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -553,13 +553,13 @@
         return true;
     }
 
-    public static boolean native_setPolyToPoly(int native_object, float[] src, int srcIndex,
+    /*package*/ static boolean native_setPolyToPoly(int native_object, float[] src, int srcIndex,
             float[] dst, int dstIndex, int pointCount) {
         // FIXME
-        throw new UnsupportedOperationException("NATIVE DELEGATE NEEDED");
+        throw new UnsupportedOperationException("Native delegate needed: Matrix_Delegate.native_setPolyToPoly");
     }
 
-    public static boolean native_invert(int native_object, int inverse) {
+    /*package*/ static boolean native_invert(int native_object, int inverse) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -589,7 +589,7 @@
         }
     }
 
-    public static void native_mapPoints(int native_object, float[] dst, int dstIndex,
+    /*package*/ static void native_mapPoints(int native_object, float[] dst, int dstIndex,
             float[] src, int srcIndex, int ptCount, boolean isPts) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
@@ -602,11 +602,11 @@
         } else {
             // src is vectors
             // FIXME
-            throw new UnsupportedOperationException("NATIVE DELEGATE NEEDED");
+            throw new UnsupportedOperationException("Native delegate needed: Matrix_Delegate.native_mapPoints");
         }
     }
 
-    public static boolean native_mapRect(int native_object, RectF dst, RectF src) {
+    /*package*/ static boolean native_mapRect(int native_object, RectF dst, RectF src) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -635,12 +635,12 @@
         return (d.computeTypeMask() & kRectStaysRect_Mask) != 0;
     }
 
-    public static float native_mapRadius(int native_object, float radius) {
+    /*package*/ static float native_mapRadius(int native_object, float radius) {
         // FIXME
-        throw new UnsupportedOperationException();
+        throw new UnsupportedOperationException("Native delegate needed: Matrix_Delegate.native_mapRadius");
     }
 
-    public static void native_getValues(int native_object, float[] values) {
+    /*package*/ static void native_getValues(int native_object, float[] values) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -650,7 +650,7 @@
         System.arraycopy(d.mValues, 0, d.mValues, 0, MATRIX_SIZE);
     }
 
-    public static void native_setValues(int native_object, float[] values) {
+    /*package*/ static void native_setValues(int native_object, float[] values) {
         Matrix_Delegate d = sManager.getDelegate(native_object);
         if (d == null) {
             assert false;
@@ -660,7 +660,7 @@
         System.arraycopy(values, 0, d.mValues, 0, MATRIX_SIZE);
     }
 
-    public static boolean native_equals(int native_a, int native_b) {
+    /*package*/ static boolean native_equals(int native_a, int native_b) {
         Matrix_Delegate a = sManager.getDelegate(native_a);
         if (a == null) {
             assert false;
@@ -682,7 +682,7 @@
         return true;
     }
 
-    public static void finalizer(int native_instance) {
+    /*package*/ static void finalizer(int native_instance) {
         sManager.removeDelegate(native_instance);
     }
 
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint.java b/tools/layoutlib/bridge/src/android/graphics/Paint.java
deleted file mode 100644
index 2de21c1..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/Paint.java
+++ /dev/null
@@ -1,1211 +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.graphics;
-
-import android.text.SpannableString;
-import android.text.SpannableStringBuilder;
-import android.text.SpannedString;
-import android.text.TextUtils;
-
-import java.awt.BasicStroke;
-import java.awt.Font;
-import java.awt.Toolkit;
-import java.awt.font.FontRenderContext;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Rectangle2D;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * A paint implementation overridden by the LayoutLib bridge.
- */
-public class Paint extends _Original_Paint {
-
-    private int mColor = 0xFFFFFFFF;
-    private float mStrokeWidth = 1.f;
-    private float mTextSize = 20;
-    private float mScaleX = 1;
-    private float mSkewX = 0;
-    private Align mAlign = Align.LEFT;
-    private Style mStyle = Style.FILL;
-    private float mStrokeMiter = 4.0f;
-    private Cap mCap = Cap.BUTT;
-    private Join mJoin = Join.MITER;
-    private int mFlags = 0;
-
-    /**
-     * Class associating a {@link Font} and it's {@link java.awt.FontMetrics}.
-     */
-    public static final class FontInfo {
-        Font mFont;
-        java.awt.FontMetrics mMetrics;
-    }
-
-    private List<FontInfo> mFonts;
-    private final FontRenderContext mFontContext = new FontRenderContext(
-            new AffineTransform(), true, true);
-
-    public static final int ANTI_ALIAS_FLAG       = _Original_Paint.ANTI_ALIAS_FLAG;
-    public static final int FILTER_BITMAP_FLAG    = _Original_Paint.FILTER_BITMAP_FLAG;
-    public static final int DITHER_FLAG           = _Original_Paint.DITHER_FLAG;
-    public static final int UNDERLINE_TEXT_FLAG   = _Original_Paint.UNDERLINE_TEXT_FLAG;
-    public static final int STRIKE_THRU_TEXT_FLAG = _Original_Paint.STRIKE_THRU_TEXT_FLAG;
-    public static final int FAKE_BOLD_TEXT_FLAG   = _Original_Paint.FAKE_BOLD_TEXT_FLAG;
-    public static final int LINEAR_TEXT_FLAG      = _Original_Paint.LINEAR_TEXT_FLAG;
-    public static final int SUBPIXEL_TEXT_FLAG    = _Original_Paint.SUBPIXEL_TEXT_FLAG;
-    public static final int DEV_KERN_TEXT_FLAG    = _Original_Paint.DEV_KERN_TEXT_FLAG;
-
-    public static class FontMetrics extends _Original_Paint.FontMetrics {
-    }
-
-    public static class FontMetricsInt extends _Original_Paint.FontMetricsInt {
-    }
-
-    /**
-     * The Style specifies if the primitive being drawn is filled,
-     * stroked, or both (in the same color). The default is FILL.
-     */
-    public enum Style {
-        /**
-         * Geometry and text drawn with this style will be filled, ignoring all
-         * stroke-related settings in the paint.
-         */
-        FILL            (0),
-        /**
-         * Geometry and text drawn with this style will be stroked, respecting
-         * the stroke-related fields on the paint.
-         */
-        STROKE          (1),
-        /**
-         * Geometry and text drawn with this style will be both filled and
-         * stroked at the same time, respecting the stroke-related fields on
-         * the paint.
-         */
-        FILL_AND_STROKE (2);
-
-        Style(int nativeInt) {
-            this.nativeInt = nativeInt;
-        }
-        final int nativeInt;
-    }
-
-    /**
-     * The Cap specifies the treatment for the beginning and ending of
-     * stroked lines and paths. The default is BUTT.
-     */
-    public enum Cap {
-        /**
-         * The stroke ends with the path, and does not project beyond it.
-         */
-        BUTT    (0),
-        /**
-         * The stroke projects out as a square, with the center at the end
-         * of the path.
-         */
-        ROUND   (1),
-        /**
-         * The stroke projects out as a semicircle, with the center at the
-         * end of the path.
-         */
-        SQUARE  (2);
-
-        private Cap(int nativeInt) {
-            this.nativeInt = nativeInt;
-        }
-        final int nativeInt;
-
-        /** custom for layoutlib */
-        public int getJavaCap() {
-            switch (this) {
-                case BUTT:
-                    return BasicStroke.CAP_BUTT;
-                case ROUND:
-                    return BasicStroke.CAP_ROUND;
-                default:
-                case SQUARE:
-                    return BasicStroke.CAP_SQUARE;
-            }
-        }
-    }
-
-    /**
-     * The Join specifies the treatment where lines and curve segments
-     * join on a stroked path. The default is MITER.
-     */
-    public enum Join {
-        /**
-         * The outer edges of a join meet at a sharp angle
-         */
-        MITER   (0),
-        /**
-         * The outer edges of a join meet in a circular arc.
-         */
-        ROUND   (1),
-        /**
-         * The outer edges of a join meet with a straight line
-         */
-        BEVEL   (2);
-
-        private Join(int nativeInt) {
-            this.nativeInt = nativeInt;
-        }
-        final int nativeInt;
-
-        /** custom for layoutlib */
-        public int getJavaJoin() {
-            switch (this) {
-                default:
-                case MITER:
-                    return BasicStroke.JOIN_MITER;
-                case ROUND:
-                    return BasicStroke.JOIN_ROUND;
-                case BEVEL:
-                    return BasicStroke.JOIN_BEVEL;
-            }
-        }
-    }
-
-    /**
-     * Align specifies how drawText aligns its text relative to the
-     * [x,y] coordinates. The default is LEFT.
-     */
-    public enum Align {
-        /**
-         * The text is drawn to the right of the x,y origin
-         */
-        LEFT    (0),
-        /**
-         * The text is drawn centered horizontally on the x,y origin
-         */
-        CENTER  (1),
-        /**
-         * The text is drawn to the left of the x,y origin
-         */
-        RIGHT   (2);
-
-        private Align(int nativeInt) {
-            this.nativeInt = nativeInt;
-        }
-        final int nativeInt;
-    }
-
-    public Paint() {
-        this(0);
-    }
-
-    /*
-     * Do not remove or com.android.layoutlib.bridge.TestClassReplacement fails.
-     */
-    @Override
-    public void finalize() { }
-
-    public Paint(int flags) {
-        setFlags(flags | DEFAULT_PAINT_FLAGS);
-        initFont();
-    }
-
-    public Paint(Paint paint) {
-        set(paint);
-        initFont();
-    }
-
-    @Override
-    public void reset() {
-        super.reset();
-    }
-
-    /**
-     * Returns the list of {@link Font} objects. The first item is the main font, the rest
-     * are fall backs for characters not present in the main font.
-     */
-    public List<FontInfo> getFonts() {
-        return mFonts;
-    }
-
-    private void initFont() {
-        mTypeface = Typeface.DEFAULT;
-        updateFontObject();
-    }
-
-    /**
-     * Update the {@link Font} object from the typeface, text size and scaling
-     */
-    @SuppressWarnings("deprecation")
-    private void updateFontObject() {
-        if (mTypeface != null) {
-            // Get the fonts from the TypeFace object.
-            List<Font> fonts = Typeface_Delegate.getFonts(mTypeface);
-
-            // create new font objects as well as FontMetrics, based on the current text size
-            // and skew info.
-            ArrayList<FontInfo> infoList = new ArrayList<FontInfo>(fonts.size());
-            for (Font font : fonts) {
-                FontInfo info = new FontInfo();
-                info.mFont = font.deriveFont(mTextSize);
-                if (mScaleX != 1.0 || mSkewX != 0) {
-                    // TODO: support skew
-                    info.mFont = info.mFont.deriveFont(new AffineTransform(
-                            mScaleX, mSkewX, 0, 0, 1, 0));
-                }
-                info.mMetrics = Toolkit.getDefaultToolkit().getFontMetrics(info.mFont);
-
-                infoList.add(info);
-            }
-
-            mFonts = Collections.unmodifiableList(infoList);
-        }
-    }
-
-    //----------------------------------------
-
-    public void set(Paint src) {
-        if (this != src) {
-            mColor = src.mColor;
-            mTextSize = src.mTextSize;
-            mScaleX = src.mScaleX;
-            mSkewX = src.mSkewX;
-            mAlign = src.mAlign;
-            mStyle = src.mStyle;
-            mFlags = src.mFlags;
-
-            updateFontObject();
-
-            super.set(src);
-        }
-    }
-
-    @Override
-    public void setCompatibilityScaling(float factor) {
-        super.setCompatibilityScaling(factor);
-    }
-
-    @Override
-    public int getFlags() {
-        return mFlags;
-    }
-
-    @Override
-    public void setFlags(int flags) {
-        mFlags = flags;
-    }
-
-    @Override
-    public boolean isAntiAlias() {
-        return super.isAntiAlias();
-    }
-
-    @Override
-    public boolean isDither() {
-        return super.isDither();
-    }
-
-    @Override
-    public boolean isLinearText() {
-        return super.isLinearText();
-    }
-
-    @Override
-    public boolean isStrikeThruText() {
-        return super.isStrikeThruText();
-    }
-
-    @Override
-    public boolean isUnderlineText() {
-        return super.isUnderlineText();
-    }
-
-    @Override
-    public boolean isFakeBoldText() {
-        return super.isFakeBoldText();
-    }
-
-    @Override
-    public boolean isSubpixelText() {
-        return super.isSubpixelText();
-    }
-
-    @Override
-    public boolean isFilterBitmap() {
-        return super.isFilterBitmap();
-    }
-
-    /**
-     * Return the font's recommended interline spacing, given the Paint's
-     * settings for typeface, textSize, etc. If metrics is not null, return the
-     * fontmetric values in it.
-     *
-     * @param metrics If this object is not null, its fields are filled with
-     *                the appropriate values given the paint's text attributes.
-     * @return the font's recommended interline spacing.
-     */
-    public float getFontMetrics(FontMetrics metrics) {
-        if (mFonts.size() > 0) {
-            java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
-            if (metrics != null) {
-                // Android expects negative ascent so we invert the value from Java.
-                metrics.top = - javaMetrics.getMaxAscent();
-                metrics.ascent = - javaMetrics.getAscent();
-                metrics.descent = javaMetrics.getDescent();
-                metrics.bottom = javaMetrics.getMaxDescent();
-                metrics.leading = javaMetrics.getLeading();
-            }
-
-            return javaMetrics.getHeight();
-        }
-
-        return 0;
-    }
-
-    public int getFontMetricsInt(FontMetricsInt metrics) {
-        if (mFonts.size() > 0) {
-            java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
-            if (metrics != null) {
-                // Android expects negative ascent so we invert the value from Java.
-                metrics.top = - javaMetrics.getMaxAscent();
-                metrics.ascent = - javaMetrics.getAscent();
-                metrics.descent = javaMetrics.getDescent();
-                metrics.bottom = javaMetrics.getMaxDescent();
-                metrics.leading = javaMetrics.getLeading();
-            }
-
-            return javaMetrics.getHeight();
-        }
-
-        return 0;
-    }
-
-    /**
-     * Reimplemented to return Paint.FontMetrics instead of _Original_Paint.FontMetrics
-     */
-    public FontMetrics getFontMetrics() {
-        FontMetrics fm = new FontMetrics();
-        getFontMetrics(fm);
-        return fm;
-    }
-
-    /**
-     * Reimplemented to return Paint.FontMetricsInt instead of _Original_Paint.FontMetricsInt
-     */
-    public FontMetricsInt getFontMetricsInt() {
-        FontMetricsInt fm = new FontMetricsInt();
-        getFontMetricsInt(fm);
-        return fm;
-    }
-
-
-
-    @Override
-    public float getFontMetrics(_Original_Paint.FontMetrics metrics) {
-        throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
-    }
-
-    @Override
-    public int getFontMetricsInt(_Original_Paint.FontMetricsInt metrics) {
-        throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
-    }
-
-    @Override
-    public Typeface setTypeface(Typeface typeface) {
-        if (typeface != null) {
-            mTypeface = typeface;
-        } else {
-            mTypeface = Typeface.DEFAULT;
-        }
-
-        updateFontObject();
-
-        return typeface;
-    }
-
-    @Override
-    public Typeface getTypeface() {
-        return super.getTypeface();
-    }
-
-    @Override
-    public int getColor() {
-        return mColor;
-    }
-
-    @Override
-    public void setColor(int color) {
-        mColor = color;
-    }
-
-    @Override
-    public void setARGB(int a, int r, int g, int b) {
-        super.setARGB(a, r, g, b);
-    }
-
-    @Override
-    public void setAlpha(int alpha) {
-        mColor = (alpha << 24) | (mColor & 0x00FFFFFF);
-    }
-
-    @Override
-    public int getAlpha() {
-        return mColor >>> 24;
-    }
-
-    /**
-     * Set or clear the shader object.
-     * <p />
-     * Pass null to clear any previous shader.
-     * As a convenience, the parameter passed is also returned.
-     *
-     * @param shader May be null. the new shader to be installed in the paint
-     * @return       shader
-     */
-    @Override
-    public Shader setShader(Shader shader) {
-        return mShader = shader;
-    }
-
-    @Override
-    public Shader getShader() {
-        return super.getShader();
-    }
-
-    /**
-     * Set or clear the paint's colorfilter, returning the parameter.
-     *
-     * @param filter May be null. The new filter to be installed in the paint
-     * @return       filter
-     */
-    @Override
-    public ColorFilter setColorFilter(ColorFilter filter) {
-        mColorFilter = filter;
-        return filter;
-    }
-
-    @Override
-    public ColorFilter getColorFilter() {
-        return super.getColorFilter();
-    }
-
-    /**
-     * Set or clear the xfermode object.
-     * <p />
-     * Pass null to clear any previous xfermode.
-     * As a convenience, the parameter passed is also returned.
-     *
-     * @param xfermode May be null. The xfermode to be installed in the paint
-     * @return         xfermode
-     */
-    @Override
-    public Xfermode setXfermode(Xfermode xfermode) {
-        return mXfermode = xfermode;
-    }
-
-    @Override
-    public Xfermode getXfermode() {
-        return super.getXfermode();
-    }
-
-    @Override
-    public Rasterizer setRasterizer(Rasterizer rasterizer) {
-        mRasterizer = rasterizer;
-        return rasterizer;
-    }
-
-    @Override
-    public Rasterizer getRasterizer() {
-        return super.getRasterizer();
-    }
-
-    @Override
-    public void setShadowLayer(float radius, float dx, float dy, int color) {
-        // TODO Auto-generated method stub
-    }
-
-    @Override
-    public void clearShadowLayer() {
-        super.clearShadowLayer();
-    }
-
-    public void setTextAlign(Align align) {
-        mAlign = align;
-    }
-
-    @Override
-    public void setTextAlign(android.graphics._Original_Paint.Align align) {
-        throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
-    }
-
-    public Align getTextAlign() {
-        return mAlign;
-    }
-
-    public void setStyle(Style style) {
-        mStyle = style;
-    }
-
-    @Override
-    public void setStyle(android.graphics._Original_Paint.Style style) {
-        throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
-    }
-
-    public Style getStyle() {
-        return mStyle;
-    }
-
-    @Override
-    public void setDither(boolean dither) {
-        mFlags |= dither ? DITHER_FLAG : ~DITHER_FLAG;
-    }
-
-    @Override
-    public void setAntiAlias(boolean aa) {
-        mFlags |= aa ? ANTI_ALIAS_FLAG : ~ANTI_ALIAS_FLAG;
-    }
-
-    @Override
-    public void setFakeBoldText(boolean flag) {
-        mFlags |= flag ? FAKE_BOLD_TEXT_FLAG : ~FAKE_BOLD_TEXT_FLAG;
-    }
-
-    @Override
-    public void setLinearText(boolean flag) {
-        mFlags |= flag ? LINEAR_TEXT_FLAG : ~LINEAR_TEXT_FLAG;
-    }
-
-    @Override
-    public void setSubpixelText(boolean flag) {
-        mFlags |= flag ? SUBPIXEL_TEXT_FLAG : ~SUBPIXEL_TEXT_FLAG;
-    }
-
-    @Override
-    public void setUnderlineText(boolean flag) {
-        mFlags |= flag ? UNDERLINE_TEXT_FLAG : ~UNDERLINE_TEXT_FLAG;
-    }
-
-    @Override
-    public void setStrikeThruText(boolean flag) {
-        mFlags |= flag ? STRIKE_THRU_TEXT_FLAG : ~STRIKE_THRU_TEXT_FLAG;
-    }
-
-    @Override
-    public void setFilterBitmap(boolean flag) {
-        mFlags |= flag ? FILTER_BITMAP_FLAG : ~FILTER_BITMAP_FLAG;
-    }
-
-    @Override
-    public float getStrokeWidth() {
-        return mStrokeWidth;
-    }
-
-    @Override
-    public void setStrokeWidth(float width) {
-        mStrokeWidth = width;
-    }
-
-    @Override
-    public float getStrokeMiter() {
-        return mStrokeMiter;
-    }
-
-    @Override
-    public void setStrokeMiter(float miter) {
-        mStrokeMiter = miter;
-    }
-
-    @Override
-    public void setStrokeCap(android.graphics._Original_Paint.Cap cap) {
-        throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
-    }
-
-    public void setStrokeCap(Cap cap) {
-        mCap = cap;
-    }
-
-    public Cap getStrokeCap() {
-        return mCap;
-    }
-
-    @Override
-    public void setStrokeJoin(android.graphics._Original_Paint.Join join) {
-        throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
-    }
-
-    public void setStrokeJoin(Join join) {
-        mJoin = join;
-    }
-
-    public Join getStrokeJoin() {
-        return mJoin;
-    }
-
-    @Override
-    public boolean getFillPath(Path src, Path dst) {
-        return super.getFillPath(src, dst);
-    }
-
-    @Override
-    public PathEffect setPathEffect(PathEffect effect) {
-        mPathEffect = effect;
-        return effect;
-    }
-
-    @Override
-    public PathEffect getPathEffect() {
-        return super.getPathEffect();
-    }
-
-    @Override
-    public MaskFilter setMaskFilter(MaskFilter maskfilter) {
-        mMaskFilter = maskfilter;
-        return maskfilter;
-    }
-
-    @Override
-    public MaskFilter getMaskFilter() {
-        return super.getMaskFilter();
-    }
-
-    /**
-     * Return the paint's text size.
-     *
-     * @return the paint's text size.
-     */
-    @Override
-    public float getTextSize() {
-        return mTextSize;
-    }
-
-    /**
-     * Set the paint's text size. This value must be > 0
-     *
-     * @param textSize set the paint's text size.
-     */
-    @Override
-    public void setTextSize(float textSize) {
-        mTextSize = textSize;
-
-        updateFontObject();
-    }
-
-    /**
-     * Return the paint's horizontal scale factor for text. The default value
-     * is 1.0.
-     *
-     * @return the paint's scale factor in X for drawing/measuring text
-     */
-    @Override
-    public float getTextScaleX() {
-        return mScaleX;
-    }
-
-    /**
-     * Set the paint's horizontal scale factor for text. The default value
-     * is 1.0. Values > 1.0 will stretch the text wider. Values < 1.0 will
-     * stretch the text narrower.
-     *
-     * @param scaleX set the paint's scale in X for drawing/measuring text.
-     */
-    @Override
-    public void setTextScaleX(float scaleX) {
-        mScaleX = scaleX;
-
-        updateFontObject();
-    }
-
-    /**
-     * Return the paint's horizontal skew factor for text. The default value
-     * is 0.
-     *
-     * @return         the paint's skew factor in X for drawing text.
-     */
-    @Override
-    public float getTextSkewX() {
-        return mSkewX;
-    }
-
-    /**
-     * Set the paint's horizontal skew factor for text. The default value
-     * is 0. For approximating oblique text, use values around -0.25.
-     *
-     * @param skewX set the paint's skew factor in X for drawing text.
-     */
-    @Override
-    public void setTextSkewX(float skewX) {
-        mSkewX = skewX;
-
-        updateFontObject();
-    }
-
-    @Override
-    public float getFontSpacing() {
-        return super.getFontSpacing();
-    }
-
-    /**
-     * Return the distance above (negative) the baseline (ascent) based on the
-     * current typeface and text size.
-     *
-     * @return the distance above (negative) the baseline (ascent) based on the
-     *         current typeface and text size.
-     */
-    @Override
-    public float ascent() {
-        if (mFonts.size() > 0) {
-            java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
-            // Android expects negative ascent so we invert the value from Java.
-            return - javaMetrics.getAscent();
-        }
-
-        return 0;
-    }
-
-    /**
-     * Return the distance below (positive) the baseline (descent) based on the
-     * current typeface and text size.
-     *
-     * @return the distance below (positive) the baseline (descent) based on
-     *         the current typeface and text size.
-     */
-    @Override
-    public float descent() {
-        if (mFonts.size() > 0) {
-            java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
-            return javaMetrics.getDescent();
-        }
-
-        return 0;
-    }
-
-    /**
-     * Return the width of the text.
-     *
-     * @param text  The text to measure
-     * @param index The index of the first character to start measuring
-     * @param count THe number of characters to measure, beginning with start
-     * @return      The width of the text
-     */
-    @Override
-    public float measureText(char[] text, int index, int count) {
-        // WARNING: the logic in this method is similar to Canvas.drawText.
-        // Any change to this method should be reflected in Canvas.drawText
-        if (mFonts.size() > 0) {
-            FontInfo mainFont = mFonts.get(0);
-            int i = index;
-            int lastIndex = index + count;
-            float total = 0f;
-            while (i < lastIndex) {
-                // always start with the main font.
-                int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex);
-                if (upTo == -1) {
-                    // shortcut to exit
-                    return total + mainFont.mMetrics.charsWidth(text, i, lastIndex - i);
-                } else if (upTo > 0) {
-                    total += mainFont.mMetrics.charsWidth(text, i, upTo - i);
-                    i = upTo;
-                    // don't call continue at this point. Since it is certain the main font
-                    // cannot display the font a index upTo (now ==i), we move on to the
-                    // fallback fonts directly.
-                }
-
-                // no char supported, attempt to read the next char(s) with the
-                // fallback font. In this case we only test the first character
-                // and then go back to test with the main font.
-                // Special test for 2-char characters.
-                boolean foundFont = false;
-                for (int f = 1 ; f < mFonts.size() ; f++) {
-                    FontInfo fontInfo = mFonts.get(f);
-
-                    // need to check that the font can display the character. We test
-                    // differently if the char is a high surrogate.
-                    int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
-                    upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount);
-                    if (upTo == -1) {
-                        total += fontInfo.mMetrics.charsWidth(text, i, charCount);
-                        i += charCount;
-                        foundFont = true;
-                        break;
-
-                    }
-                }
-
-                // in case no font can display the char, measure it with the main font.
-                if (foundFont == false) {
-                    int size = Character.isHighSurrogate(text[i]) ? 2 : 1;
-                    total += mainFont.mMetrics.charsWidth(text, i, size);
-                    i += size;
-                }
-            }
-        }
-
-        return 0;
-    }
-
-    /**
-     * Return the width of the text.
-     *
-     * @param text  The text to measure
-     * @param start The index of the first character to start measuring
-     * @param end   1 beyond the index of the last character to measure
-     * @return      The width of the text
-     */
-    @Override
-    public float measureText(String text, int start, int end) {
-        return measureText(text.toCharArray(), start, end - start);
-    }
-
-    /**
-     * Return the width of the text.
-     *
-     * @param text  The text to measure
-     * @return      The width of the text
-     */
-    @Override
-    public float measureText(String text) {
-        return measureText(text.toCharArray(), 0, text.length());
-    }
-
-    /*
-     * re-implement to call SpannableStringBuilder.measureText with a Paint object
-     * instead of an _Original_Paint
-     */
-    @Override
-    public float measureText(CharSequence text, int start, int end) {
-        if (text instanceof String) {
-            return measureText((String)text, start, end);
-        }
-        if (text instanceof SpannedString ||
-            text instanceof SpannableString) {
-            return measureText(text.toString(), start, end);
-        }
-        if (text instanceof SpannableStringBuilder) {
-            return ((SpannableStringBuilder)text).measureText(start, end, this);
-        }
-
-        char[] buf = TemporaryBuffer.obtain(end - start);
-        TextUtils.getChars(text, start, end, buf, 0);
-        float result = measureText(buf, 0, end - start);
-        TemporaryBuffer.recycle(buf);
-        return result;
-    }
-
-    /**
-     * Measure the text, stopping early if the measured width exceeds maxWidth.
-     * Return the number of chars that were measured, and if measuredWidth is
-     * not null, return in it the actual width measured.
-     *
-     * @param text  The text to measure
-     * @param index The offset into text to begin measuring at
-     * @param count The number of maximum number of entries to measure. If count
-     *              is negative, then the characters before index are measured
-     *              in reverse order. This allows for measuring the end of
-     *              string.
-     * @param maxWidth The maximum width to accumulate.
-     * @param measuredWidth Optional. If not null, returns the actual width
-     *                     measured.
-     * @return The number of chars that were measured. Will always be <=
-     *         abs(count).
-     */
-    @Override
-    public int breakText(char[] text, int index, int count,
-                                float maxWidth, float[] measuredWidth) {
-        int inc = count > 0 ? 1 : -1;
-
-        int measureIndex = 0;
-        float measureAcc = 0;
-        for (int i = index ; i != index + count ; i += inc, measureIndex++) {
-            int start, end;
-            if (i < index) {
-                start = i;
-                end = index;
-            } else {
-                start = index;
-                end = i;
-            }
-
-            // measure from start to end
-            float res = measureText(text, start, end - start + 1);
-
-            if (measuredWidth != null) {
-                measuredWidth[measureIndex] = res;
-            }
-
-            measureAcc += res;
-            if (res > maxWidth) {
-                // we should not return this char index, but since it's 0-based and we need
-                // to return a count, we simply return measureIndex;
-                return measureIndex;
-            }
-
-        }
-
-        return measureIndex;
-    }
-
-    /**
-     * Measure the text, stopping early if the measured width exceeds maxWidth.
-     * Return the number of chars that were measured, and if measuredWidth is
-     * not null, return in it the actual width measured.
-     *
-     * @param text  The text to measure
-     * @param measureForwards If true, measure forwards, starting at index.
-     *                        Otherwise, measure backwards, starting with the
-     *                        last character in the string.
-     * @param maxWidth The maximum width to accumulate.
-     * @param measuredWidth Optional. If not null, returns the actual width
-     *                     measured.
-     * @return The number of chars that were measured. Will always be <=
-     *         abs(count).
-     */
-    @Override
-    public int breakText(String text, boolean measureForwards,
-                                float maxWidth, float[] measuredWidth) {
-        return breakText(text,
-                0 /* start */, text.length() /* end */,
-                measureForwards, maxWidth, measuredWidth);
-    }
-
-    /**
-     * Measure the text, stopping early if the measured width exceeds maxWidth.
-     * Return the number of chars that were measured, and if measuredWidth is
-     * not null, return in it the actual width measured.
-     *
-     * @param text  The text to measure
-     * @param start The offset into text to begin measuring at
-     * @param end   The end of the text slice to measure.
-     * @param measureForwards If true, measure forwards, starting at start.
-     *                        Otherwise, measure backwards, starting with end.
-     * @param maxWidth The maximum width to accumulate.
-     * @param measuredWidth Optional. If not null, returns the actual width
-     *                     measured.
-     * @return The number of chars that were measured. Will always be <=
-     *         abs(end - start).
-     */
-    @Override
-    public int breakText(CharSequence text, int start, int end, boolean measureForwards,
-            float maxWidth, float[] measuredWidth) {
-        char[] buf = new char[end - start];
-        int result;
-
-        TextUtils.getChars(text, start, end, buf, 0);
-
-        if (measureForwards) {
-            result = breakText(buf, 0, end - start, maxWidth, measuredWidth);
-        } else {
-            result = breakText(buf, 0, -(end - start), maxWidth, measuredWidth);
-        }
-
-        return result;
-    }
-
-    /**
-     * Return the advance widths for the characters in the string.
-     *
-     * @param text     The text to measure
-     * @param index    The index of the first char to to measure
-     * @param count    The number of chars starting with index to measure
-     * @param widths   array to receive the advance widths of the characters.
-     *                 Must be at least a large as count.
-     * @return         the actual number of widths returned.
-     */
-    @Override
-    public int getTextWidths(char[] text, int index, int count,
-                             float[] widths) {
-        if (mFonts.size() > 0) {
-            if ((index | count) < 0 || index + count > text.length
-                    || count > widths.length) {
-                throw new ArrayIndexOutOfBoundsException();
-            }
-
-            // FIXME: handle multi-char characters.
-            // Need to figure out if the lengths of the width array takes into account
-            // multi-char characters.
-            for (int i = 0; i < count; i++) {
-                char c = text[i + index];
-                boolean found = false;
-                for (FontInfo info : mFonts) {
-                    if (info.mFont.canDisplay(c)) {
-                        widths[i] = info.mMetrics.charWidth(c);
-                        found = true;
-                        break;
-                    }
-                }
-
-                if (found == false) {
-                    // we stop there.
-                    return i;
-                }
-            }
-
-            return count;
-        }
-
-        return 0;
-    }
-
-    /**
-     * Return the advance widths for the characters in the string.
-     *
-     * @param text   The text to measure
-     * @param start  The index of the first char to to measure
-     * @param end    The end of the text slice to measure
-     * @param widths array to receive the advance widths of the characters.
-     *               Must be at least a large as the text.
-     * @return       the number of unichars in the specified text.
-     */
-    @Override
-    public int getTextWidths(String text, int start, int end, float[] widths) {
-        if ((start | end | (end - start) | (text.length() - end)) < 0) {
-            throw new IndexOutOfBoundsException();
-        }
-        if (end - start > widths.length) {
-            throw new ArrayIndexOutOfBoundsException();
-        }
-
-        return getTextWidths(text.toCharArray(), start, end - start, widths);
-    }
-
-    /*
-     * re-implement to call SpannableStringBuilder.getTextWidths with a Paint object
-     * instead of an _Original_Paint
-     */
-    @Override
-    public int getTextWidths(CharSequence text, int start, int end, float[] widths) {
-        if (text instanceof String) {
-            return getTextWidths((String)text, start, end, widths);
-        }
-        if (text instanceof SpannedString || text instanceof SpannableString) {
-            return getTextWidths(text.toString(), start, end, widths);
-        }
-        if (text instanceof SpannableStringBuilder) {
-            return ((SpannableStringBuilder)text).getTextWidths(start, end, widths, this);
-        }
-
-        char[] buf = TemporaryBuffer.obtain(end - start);
-        TextUtils.getChars(text, start, end, buf, 0);
-        int result = getTextWidths(buf, 0, end - start, widths);
-        TemporaryBuffer.recycle(buf);
-        return result;
-    }
-
-    @Override
-    public int getTextWidths(String text, float[] widths) {
-        return super.getTextWidths(text, widths);
-    }
-
-    /**
-     * Return the path (outline) for the specified text.
-     * Note: just like Canvas.drawText, this will respect the Align setting in
-     * the paint.
-     *
-     * @param text     The text to retrieve the path from
-     * @param index    The index of the first character in text
-     * @param count    The number of characterss starting with index
-     * @param x        The x coordinate of the text's origin
-     * @param y        The y coordinate of the text's origin
-     * @param path     The path to receive the data describing the text. Must
-     *                 be allocated by the caller.
-     */
-    @Override
-    public void getTextPath(char[] text, int index, int count,
-                            float x, float y, Path path) {
-
-        // TODO this is the ORIGINAL implementation. REPLACE AS NEEDED OR REMOVE
-
-        if ((index | count) < 0 || index + count > text.length) {
-            throw new ArrayIndexOutOfBoundsException();
-        }
-
-        // TODO native_getTextPath(mNativePaint, text, index, count, x, y, path.ni());
-
-        throw new UnsupportedOperationException("IMPLEMENT AS NEEDED");
-    }
-
-    /**
-     * Return the path (outline) for the specified text.
-     * Note: just like Canvas.drawText, this will respect the Align setting
-     * in the paint.
-     *
-     * @param text  The text to retrieve the path from
-     * @param start The first character in the text
-     * @param end   1 past the last charcter in the text
-     * @param x     The x coordinate of the text's origin
-     * @param y     The y coordinate of the text's origin
-     * @param path  The path to receive the data describing the text. Must
-     *              be allocated by the caller.
-     */
-    @Override
-    public void getTextPath(String text, int start, int end,
-                            float x, float y, Path path) {
-        if ((start | end | (end - start) | (text.length() - end)) < 0) {
-            throw new IndexOutOfBoundsException();
-        }
-
-        getTextPath(text.toCharArray(), start, end - start, x, y, path);
-    }
-
-    /**
-     * Return in bounds (allocated by the caller) the smallest rectangle that
-     * encloses all of the characters, with an implied origin at (0,0).
-     *
-     * @param text  String to measure and return its bounds
-     * @param start Index of the first char in the string to measure
-     * @param end   1 past the last char in the string measure
-     * @param bounds Returns the unioned bounds of all the text. Must be
-     *               allocated by the caller.
-     */
-    @Override
-    public void getTextBounds(String text, int start, int end, Rect bounds) {
-        if ((start | end | (end - start) | (text.length() - end)) < 0) {
-            throw new IndexOutOfBoundsException();
-        }
-        if (bounds == null) {
-            throw new NullPointerException("need bounds Rect");
-        }
-
-        getTextBounds(text.toCharArray(), start, end - start, bounds);
-    }
-
-    /**
-     * Return in bounds (allocated by the caller) the smallest rectangle that
-     * encloses all of the characters, with an implied origin at (0,0).
-     *
-     * @param text  Array of chars to measure and return their unioned bounds
-     * @param index Index of the first char in the array to measure
-     * @param count The number of chars, beginning at index, to measure
-     * @param bounds Returns the unioned bounds of all the text. Must be
-     *               allocated by the caller.
-     */
-    @Override
-    public void getTextBounds(char[] text, int index, int count, Rect bounds) {
-        // FIXME
-        if (mFonts.size() > 0) {
-            if ((index | count) < 0 || index + count > text.length) {
-                throw new ArrayIndexOutOfBoundsException();
-            }
-            if (bounds == null) {
-                throw new NullPointerException("need bounds Rect");
-            }
-
-            FontInfo mainInfo = mFonts.get(0);
-
-            Rectangle2D rect = mainInfo.mFont.getStringBounds(text, index, index + count, mFontContext);
-            bounds.set(0, 0, (int)rect.getWidth(), (int)rect.getHeight());
-        }
-    }
-
-    public static void finalizer(int foo) {
-        // pass
-    }
-}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
new file mode 100644
index 0000000..e8079ed
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -0,0 +1,750 @@
+/*
+ * Copyright (C) 2010 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.graphics;
+
+import com.android.layoutlib.bridge.DelegateManager;
+
+import android.graphics.Paint.FontMetrics;
+import android.graphics.Paint.FontMetricsInt;
+
+import java.awt.Font;
+import java.awt.Toolkit;
+import java.awt.font.FontRenderContext;
+import java.awt.geom.AffineTransform;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Delegate implementing the native methods of android.graphics.Paint
+ *
+ * Through the layoutlib_create tool, the original native methods of Paint have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original Paint class.
+ *
+ * @see DelegateManager
+ *
+ */
+public class Paint_Delegate {
+
+    /**
+     * Class associating a {@link Font} and it's {@link java.awt.FontMetrics}.
+     */
+    public static final class FontInfo {
+        Font mFont;
+        java.awt.FontMetrics mMetrics;
+    }
+
+    // ---- delegate manager ----
+    private static final DelegateManager<Paint_Delegate> sManager =
+            new DelegateManager<Paint_Delegate>();
+
+    // ---- delegate helper data ----
+    private List<FontInfo> mFonts;
+    private final FontRenderContext mFontContext = new FontRenderContext(
+            new AffineTransform(), true, true);
+
+    // ---- delegate data ----
+    private int mFlags;
+    private int mColor;
+    private int mStyle;
+    private int mCap;
+    private int mJoin;
+    private int mAlign;
+    private int mTypeface;
+    private float mStrokeWidth;
+    private float mStrokeMiter;
+    private float mTextSize;
+    private float mTextScaleX;
+    private float mTextSkewX;
+
+
+    // ---- Public Helper methods ----
+
+    /**
+     * Returns the list of {@link Font} objects. The first item is the main font, the rest
+     * are fall backs for characters not present in the main font.
+     */
+    public List<FontInfo> getFonts() {
+        return mFonts;
+    }
+
+
+    // ---- native methods ----
+
+    /*package*/ static int getFlags(Paint thisPaint) {
+        // get the delegate from the native int.
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        if (delegate == null) {
+            assert false;
+            return 0;
+        }
+
+        return delegate.mFlags;
+    }
+
+    /*package*/ static void setFlags(Paint thisPaint, int flags) {
+        // get the delegate from the native int.
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        if (delegate == null) {
+            assert false;
+            return;
+        }
+
+        delegate.mFlags = flags;
+    }
+
+    /*package*/ static void setFilterBitmap(Paint thisPaint, boolean filter) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void setAntiAlias(Paint thisPaint, boolean aa) {
+        setFlag(thisPaint, Paint.ANTI_ALIAS_FLAG, aa);
+    }
+
+    /*package*/ static void setSubpixelText(Paint thisPaint, boolean subpixelText) {
+        setFlag(thisPaint, Paint.SUBPIXEL_TEXT_FLAG, subpixelText);
+    }
+
+    /*package*/ static void setUnderlineText(Paint thisPaint, boolean underlineText) {
+        setFlag(thisPaint, Paint.UNDERLINE_TEXT_FLAG, underlineText);
+    }
+
+    /*package*/ static void setStrikeThruText(Paint thisPaint, boolean strikeThruText) {
+        setFlag(thisPaint, Paint.STRIKE_THRU_TEXT_FLAG, strikeThruText);
+    }
+
+    /*package*/ static void setFakeBoldText(Paint thisPaint, boolean fakeBoldText) {
+        setFlag(thisPaint, Paint.FAKE_BOLD_TEXT_FLAG, fakeBoldText);
+    }
+
+    /*package*/ static void setDither(Paint thisPaint, boolean dither) {
+        setFlag(thisPaint, Paint.DITHER_FLAG, dither);
+    }
+
+    /*package*/ static void setLinearText(Paint thisPaint, boolean linearText) {
+        setFlag(thisPaint, Paint.LINEAR_TEXT_FLAG, linearText);
+    }
+
+    /*package*/ static int getColor(Paint thisPaint) {
+        // get the delegate from the native int.
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        if (delegate == null) {
+            assert false;
+            return 0;
+        }
+
+        return delegate.mColor;
+    }
+
+    /*package*/ static void setColor(Paint thisPaint, int color) {
+        // get the delegate from the native int.
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        if (delegate == null) {
+            assert false;
+            return;
+        }
+
+        delegate.mColor = color;
+    }
+
+    /*package*/ static int getAlpha(Paint thisPaint) {
+        // get the delegate from the native int.
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        if (delegate == null) {
+            assert false;
+            return 0;
+        }
+
+        return delegate.mColor >>> 24;
+    }
+
+    /*package*/ static void setAlpha(Paint thisPaint, int a) {
+        // get the delegate from the native int.
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        if (delegate == null) {
+            assert false;
+            return;
+        }
+
+        delegate.mColor = (a << 24) | (delegate.mColor & 0x00FFFFFF);
+    }
+
+    /*package*/ static float getStrokeWidth(Paint thisPaint) {
+        // get the delegate from the native int.
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        if (delegate == null) {
+            assert false;
+            return 1.f;
+        }
+
+        return delegate.mStrokeWidth;
+    }
+
+    /*package*/ static void setStrokeWidth(Paint thisPaint, float width) {
+        // get the delegate from the native int.
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        if (delegate == null) {
+            assert false;
+            return;
+        }
+
+        delegate.mStrokeWidth = width;
+    }
+
+    /*package*/ static float getStrokeMiter(Paint thisPaint) {
+        // get the delegate from the native int.
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        if (delegate == null) {
+            assert false;
+            return 1.f;
+        }
+
+        return delegate.mStrokeMiter;
+    }
+
+    /*package*/ static void setStrokeMiter(Paint thisPaint, float miter) {
+        // get the delegate from the native int.
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        if (delegate == null) {
+            assert false;
+            return;
+        }
+
+        delegate.mStrokeMiter = miter;
+    }
+
+    /*package*/ static void nSetShadowLayer(Paint thisPaint, float radius, float dx, float dy,
+            int color) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static float getTextSize(Paint thisPaint) {
+        // get the delegate from the native int.
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        if (delegate == null) {
+            assert false;
+            return 1.f;
+        }
+
+        return delegate.mTextSize;
+    }
+
+    /*package*/ static void setTextSize(Paint thisPaint, float textSize) {
+        // get the delegate from the native int.
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        if (delegate == null) {
+            assert false;
+            return;
+        }
+
+        delegate.mTextSize = textSize;
+    }
+
+    /*package*/ static float getTextScaleX(Paint thisPaint) {
+        // get the delegate from the native int.
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        if (delegate == null) {
+            assert false;
+            return 1.f;
+        }
+
+        return delegate.mTextScaleX;
+    }
+
+    /*package*/ static void setTextScaleX(Paint thisPaint, float scaleX) {
+        // get the delegate from the native int.
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        if (delegate == null) {
+            assert false;
+            return;
+        }
+
+        delegate.mTextScaleX = scaleX;
+    }
+
+    /*package*/ static float getTextSkewX(Paint thisPaint) {
+        // get the delegate from the native int.
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        if (delegate == null) {
+            assert false;
+            return 1.f;
+        }
+
+        return delegate.mTextSkewX;
+    }
+
+    /*package*/ static void setTextSkewX(Paint thisPaint, float skewX) {
+        // get the delegate from the native int.
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        if (delegate == null) {
+            assert false;
+            return;
+        }
+
+        delegate.mTextSkewX = skewX;
+    }
+
+    /*package*/ static float ascent(Paint thisPaint) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static float descent(Paint thisPaint) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static float getFontMetrics(Paint thisPaint, FontMetrics metrics) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static int getFontMetricsInt(Paint thisPaint, FontMetricsInt fmi) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static float native_measureText(Paint thisPaint, char[] text, int index,
+            int count) {
+        // WARNING: the logic in this method is similar to Canvas.drawText.
+        // Any change to this method should be reflected in Canvas.drawText
+
+        // get the delegate
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        if (delegate == null) {
+            assert false;
+            return 0;
+        }
+
+        if (delegate.mFonts.size() > 0) {
+            FontInfo mainFont = delegate.mFonts.get(0);
+            int i = index;
+            int lastIndex = index + count;
+            float total = 0f;
+            while (i < lastIndex) {
+                // always start with the main font.
+                int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex);
+                if (upTo == -1) {
+                    // shortcut to exit
+                    return total + mainFont.mMetrics.charsWidth(text, i, lastIndex - i);
+                } else if (upTo > 0) {
+                    total += mainFont.mMetrics.charsWidth(text, i, upTo - i);
+                    i = upTo;
+                    // don't call continue at this point. Since it is certain the main font
+                    // cannot display the font a index upTo (now ==i), we move on to the
+                    // fallback fonts directly.
+                }
+
+                // no char supported, attempt to read the next char(s) with the
+                // fallback font. In this case we only test the first character
+                // and then go back to test with the main font.
+                // Special test for 2-char characters.
+                boolean foundFont = false;
+                for (int f = 1 ; f < delegate.mFonts.size() ; f++) {
+                    FontInfo fontInfo = delegate.mFonts.get(f);
+
+                    // need to check that the font can display the character. We test
+                    // differently if the char is a high surrogate.
+                    int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
+                    upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount);
+                    if (upTo == -1) {
+                        total += fontInfo.mMetrics.charsWidth(text, i, charCount);
+                        i += charCount;
+                        foundFont = true;
+                        break;
+
+                    }
+                }
+
+                // in case no font can display the char, measure it with the main font.
+                if (foundFont == false) {
+                    int size = Character.isHighSurrogate(text[i]) ? 2 : 1;
+                    total += mainFont.mMetrics.charsWidth(text, i, size);
+                    i += size;
+                }
+            }
+        }
+
+        return 0;
+    }
+
+    /*package*/ static float native_measureText(Paint thisPaint, String text, int start, int end) {
+        return native_measureText(thisPaint, text.toCharArray(), start, end - start);
+    }
+
+    /*package*/ static float native_measureText(Paint thisPaint, String text) {
+        return native_measureText(thisPaint, text.toCharArray(), 0, text.length());
+    }
+
+    /*package*/ static int native_breakText(Paint thisPaint, char[] text, int index, int count,
+            float maxWidth, float[] measuredWidth) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static int native_breakText(Paint thisPaint, String text, boolean measureForwards,
+            float maxWidth, float[] measuredWidth) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+
+    /*package*/ static int native_init() {
+        Paint_Delegate newDelegate = new Paint_Delegate();
+        return sManager.addDelegate(newDelegate);
+    }
+
+    /*package*/ static int native_initWithPaint(int paint) {
+        // get the delegate from the native int.
+        Paint_Delegate delegate = sManager.getDelegate(paint);
+        if (delegate == null) {
+            assert false;
+            return 0;
+        }
+
+        Paint_Delegate newDelegate = new Paint_Delegate(delegate);
+        return sManager.addDelegate(newDelegate);
+    }
+
+    /*package*/ static void native_reset(int native_object) {
+        // get the delegate from the native int.
+        Paint_Delegate delegate = sManager.getDelegate(native_object);
+        if (delegate == null) {
+            assert false;
+            return;
+        }
+
+        delegate.reset();
+    }
+
+    /*package*/ static void native_set(int native_dst, int native_src) {
+        // get the delegate from the native int.
+        Paint_Delegate delegate_dst = sManager.getDelegate(native_dst);
+        if (delegate_dst == null) {
+            assert false;
+            return;
+        }
+
+        // get the delegate from the native int.
+        Paint_Delegate delegate_src = sManager.getDelegate(native_src);
+        if (delegate_src == null) {
+            assert false;
+            return;
+        }
+
+        delegate_dst.set(delegate_src);
+    }
+
+    /*package*/ static int native_getStyle(int native_object) {
+        // get the delegate from the native int.
+        Paint_Delegate delegate = sManager.getDelegate(native_object);
+        if (delegate == null) {
+            assert false;
+            return 0;
+        }
+
+        return delegate.mStyle;
+    }
+
+    /*package*/ static void native_setStyle(int native_object, int style) {
+        // get the delegate from the native int.
+        Paint_Delegate delegate = sManager.getDelegate(native_object);
+        if (delegate == null) {
+            assert false;
+            return;
+        }
+
+        delegate.mStyle = style;
+    }
+
+    /*package*/ static int native_getStrokeCap(int native_object) {
+        // get the delegate from the native int.
+        Paint_Delegate delegate = sManager.getDelegate(native_object);
+        if (delegate == null) {
+            assert false;
+            return 0;
+        }
+
+        return delegate.mCap;
+    }
+
+    /*package*/ static void native_setStrokeCap(int native_object, int cap) {
+        // get the delegate from the native int.
+        Paint_Delegate delegate = sManager.getDelegate(native_object);
+        if (delegate == null) {
+            assert false;
+            return;
+        }
+
+        delegate.mCap = cap;
+    }
+
+    /*package*/ static int native_getStrokeJoin(int native_object) {
+        // get the delegate from the native int.
+        Paint_Delegate delegate = sManager.getDelegate(native_object);
+        if (delegate == null) {
+            assert false;
+            return 0;
+        }
+
+        return delegate.mJoin;
+    }
+
+    /*package*/ static void native_setStrokeJoin(int native_object, int join) {
+        // get the delegate from the native int.
+        Paint_Delegate delegate = sManager.getDelegate(native_object);
+        if (delegate == null) {
+            assert false;
+            return;
+        }
+
+        delegate.mJoin = join;
+    }
+
+    /*package*/ static boolean native_getFillPath(int native_object, int src, int dst) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static int native_setShader(int native_object, int shader) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static int native_setColorFilter(int native_object, int filter) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static int native_setXfermode(int native_object, int xfermode) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static int native_setPathEffect(int native_object, int effect) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static int native_setMaskFilter(int native_object, int maskfilter) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static int native_setTypeface(int native_object, int typeface) {
+        // get the delegate from the native int.
+        Paint_Delegate delegate = sManager.getDelegate(native_object);
+        if (delegate == null) {
+            assert false;
+            return 0;
+        }
+
+        return delegate.mTypeface = typeface;
+    }
+
+    /*package*/ static int native_setRasterizer(int native_object, int rasterizer) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+
+    /*package*/ static int native_getTextAlign(int native_object) {
+        // get the delegate from the native int.
+        Paint_Delegate delegate = sManager.getDelegate(native_object);
+        if (delegate == null) {
+            assert false;
+            return 0;
+        }
+
+        return delegate.mAlign;
+    }
+
+    /*package*/ static void native_setTextAlign(int native_object, int align) {
+        // get the delegate from the native int.
+        Paint_Delegate delegate = sManager.getDelegate(native_object);
+        if (delegate == null) {
+            assert false;
+            return;
+        }
+
+        delegate.mAlign = align;
+    }
+
+    /*package*/ static float native_getFontMetrics(int native_paint, FontMetrics metrics) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static int native_getTextWidths(int native_object, char[] text, int index,
+            int count, float[] widths) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static int native_getTextWidths(int native_object, String text, int start,
+            int end, float[] widths) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static float native_getTextRunAdvances(int native_object,
+            char[] text, int index, int count, int contextIndex, int contextCount,
+            int flags, float[] advances, int advancesIndex) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static float native_getTextRunAdvances(int native_object,
+            String text, int start, int end, int contextStart, int contextEnd,
+            int flags, float[] advances, int advancesIndex) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static int native_getTextRunCursor(Paint thisPaint, int native_object, char[] text,
+            int contextStart, int contextLength, int flags, int offset, int cursorOpt) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static int native_getTextRunCursor(Paint thisPaint, int native_object, String text,
+            int contextStart, int contextEnd, int flags, int offset, int cursorOpt) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void native_getTextPath(int native_object, int bidiFlags,
+                char[] text, int index, int count, float x, float y, int path) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void native_getTextPath(int native_object, int bidiFlags,
+            String text, int start, int end, float x, float y, int path) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void nativeGetStringBounds(int nativePaint, String text, int start,
+            int end, Rect bounds) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void nativeGetCharArrayBounds(int nativePaint, char[] text, int index,
+            int count, Rect bounds) {
+        // FIXME
+        throw new UnsupportedOperationException();
+    }
+
+    /*package*/ static void finalizer(int nativePaint) {
+        sManager.removeDelegate(nativePaint);
+    }
+
+    // ---- Private delegate/helper methods ----
+
+    private Paint_Delegate() {
+        reset();
+
+        mTypeface = Typeface.sDefaults[0].native_instance;
+        updateFontObject();
+    }
+
+    private Paint_Delegate(Paint_Delegate paint) {
+        set(paint);
+        updateFontObject();
+    }
+
+    private void set(Paint_Delegate paint) {
+        mFlags = paint.mFlags;
+        mColor = paint.mColor;
+        mStyle = paint.mStyle;
+        mCap = paint.mCap;
+        mJoin = paint.mJoin;
+        mAlign = paint.mAlign;
+        mTypeface = paint.mTypeface;
+        mStrokeWidth = paint.mStrokeWidth;
+        mStrokeMiter = paint.mStrokeMiter;
+        mTextSize = paint.mTextSize;
+        mTextScaleX = paint.mTextScaleX;
+        mTextSkewX = paint.mTextSkewX;
+    }
+
+    private void reset() {
+        mFlags = Paint.DEFAULT_PAINT_FLAGS;
+        mColor = 0;
+        mStyle = 0;
+        mCap = 0;
+        mJoin = 0;
+        mAlign = 0;
+        mTypeface = 0;
+        mStrokeWidth = 1.f;
+        mStrokeMiter = 2.f;
+        mTextSize = 20.f;
+        mTextScaleX = 1.f;
+        mTextSkewX = 0.f;
+    }
+
+    /**
+     * Update the {@link Font} object from the typeface, text size and scaling
+     */
+    private void updateFontObject() {
+        if (mTypeface != 0) {
+            // Get the fonts from the TypeFace object.
+            List<Font> fonts = Typeface_Delegate.getFonts(mTypeface);
+
+            // create new font objects as well as FontMetrics, based on the current text size
+            // and skew info.
+            ArrayList<FontInfo> infoList = new ArrayList<FontInfo>(fonts.size());
+            for (Font font : fonts) {
+                FontInfo info = new FontInfo();
+                info.mFont = font.deriveFont(mTextSize);
+                if (mTextScaleX != 1.0 || mTextSkewX != 0) {
+                    // TODO: support skew
+                    info.mFont = info.mFont.deriveFont(new AffineTransform(
+                            mTextScaleX, mTextSkewX, 0, 0, 1, 0));
+                }
+                info.mMetrics = Toolkit.getDefaultToolkit().getFontMetrics(info.mFont);
+
+                infoList.add(info);
+            }
+
+            mFonts = Collections.unmodifiableList(infoList);
+        }
+    }
+
+    private static void setFlag(Paint thisPaint, int flagMask, boolean flagValue) {
+        // get the delegate from the native int.
+        Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+        if (delegate == null) {
+            assert false;
+            return;
+        }
+
+        if (flagValue) {
+            delegate.mFlags |= flagMask;
+        } else {
+            delegate.mFlags &= ~flagMask;
+        }
+    }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
index 309d934..7e90e7d 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
@@ -34,7 +34,7 @@
  *
  * This class behaves like the original native implementation, but in Java, keeping previously
  * native data into its own objects and mapping them to int that are sent back and forth between
- * it and the original Matrix class.
+ * it and the original Typeface class.
  *
  * @see DelegateManager
  *
@@ -72,7 +72,11 @@
     }
 
     public static List<Font> getFonts(Typeface typeface) {
-        Typeface_Delegate delegate = sManager.getDelegate(typeface.native_instance);
+        return getFonts(typeface.native_instance);
+    }
+
+    public static List<Font> getFonts(int native_int) {
+        Typeface_Delegate delegate = sManager.getDelegate(native_int);
         if (delegate == null) {
             assert false;
             return null;
@@ -84,7 +88,7 @@
 
     // ---- native methods ----
 
-    public static synchronized int nativeCreate(String familyName, int style) {
+    /*package*/ static synchronized int nativeCreate(String familyName, int style) {
         if (familyName == null) {
             familyName = DEFAULT_FAMILY;
         }
@@ -102,7 +106,7 @@
         return sManager.addDelegate(newDelegate);
     }
 
-    public static synchronized int nativeCreateFromTypeface(int native_instance, int style) {
+    /*package*/ static synchronized int nativeCreateFromTypeface(int native_instance, int style) {
         Typeface_Delegate delegate = sManager.getDelegate(native_instance);
         if (delegate == null) {
             assert false;
@@ -122,21 +126,21 @@
         return sManager.addDelegate(newDelegate);
     }
 
-    public static synchronized int nativeCreateFromAsset(AssetManager mgr, String path) {
+    /*package*/ static synchronized int nativeCreateFromAsset(AssetManager mgr, String path) {
         // FIXME
-        throw new UnsupportedOperationException();
+        throw new UnsupportedOperationException("Native delegate needed: Typeface_Delegate.nativeCreateFromAsset");
     }
 
-    public static synchronized int nativeCreateFromFile(String path) {
+    /*package*/ static synchronized int nativeCreateFromFile(String path) {
         // FIXME
-        throw new UnsupportedOperationException();
+        throw new UnsupportedOperationException("Native delegate needed: Typeface_Delegate.nativeCreateFromFile");
     }
 
-    public static void nativeUnref(int native_instance) {
+    /*package*/ static void nativeUnref(int native_instance) {
         sManager.removeDelegate(native_instance);
     }
 
-    public static int nativeGetStyle(int native_instance) {
+    /*package*/ static int nativeGetStyle(int native_instance) {
         Typeface_Delegate delegate = sManager.getDelegate(native_instance);
         if (delegate == null) {
             assert false;
@@ -146,7 +150,7 @@
         return delegate.mStyle;
     }
 
-    public static void setGammaForText(float blackGamma, float whiteGamma) {
+    /*package*/ static void setGammaForText(float blackGamma, float whiteGamma) {
         // This is for device testing only: pass
     }
 
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 9eb83c8..cdb4148 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -24,6 +24,7 @@
 import com.android.layoutlib.api.IResourceValue;
 import com.android.layoutlib.api.IStyleResourceValue;
 import com.android.layoutlib.api.IXmlPullParser;
+import com.android.layoutlib.api.IDensityBasedResourceValue.Density;
 import com.android.layoutlib.api.ILayoutResult.ILayoutViewInfo;
 import com.android.layoutlib.bridge.LayoutResult.LayoutViewInfo;
 import com.android.ninepatch.NinePatch;
@@ -33,7 +34,9 @@
 import android.content.ClipData;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
+import android.graphics.Bitmap_Delegate;
 import android.graphics.Canvas;
+import android.graphics.Canvas_Delegate;
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.graphics.Typeface_Delegate;
@@ -64,6 +67,7 @@
 import android.widget.TabHost;
 import android.widget.TabWidget;
 
+import java.awt.image.BufferedImage;
 import java.lang.ref.SoftReference;
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
@@ -450,13 +454,28 @@
             view.layout(0, screenOffset, screenWidth, screenHeight);
 
             // draw the views
-            Canvas canvas = new Canvas(screenWidth, screenHeight - screenOffset, logger);
+            // create the BufferedImage into which the layout will be rendered.
+            BufferedImage image = new BufferedImage(screenWidth, screenHeight - screenOffset,
+                    BufferedImage.TYPE_INT_ARGB);
+
+            // create an Android bitmap around the BufferedImage
+            Bitmap bitmap = Bitmap_Delegate.createBitmap(image, Density.getEnum(density));
+
+            // create a Canvas around the Android bitmap
+            Canvas canvas = new Canvas(bitmap);
+
+            // to set the logger, get the native delegate
+            Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(canvas);
+            canvasDelegate.setLogger(logger);
+
 
             root.draw(canvas);
-            canvas.dispose();
+            canvasDelegate.dispose();
 
-            return new LayoutResult(visit(((ViewGroup)view).getChildAt(0), context),
-                    canvas.getImage());
+            return new LayoutResult(
+                    visit(((ViewGroup)view).getChildAt(0), context),
+                    image);
+
         } catch (PostInflateException e) {
             return new LayoutResult(ILayoutResult.ERROR, "Error during post inflation process:\n"
                     + e.getMessage());
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/NinePatchDrawable.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/NinePatchDrawable.java
index abbf2f0..2c92567 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/NinePatchDrawable.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/NinePatchDrawable.java
@@ -19,6 +19,7 @@
 import com.android.ninepatch.NinePatch;
 
 import android.graphics.Canvas;
+import android.graphics.Canvas_Delegate;
 import android.graphics.ColorFilter;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
@@ -80,7 +81,8 @@
     @Override
     public void draw(Canvas canvas) {
         Rect r = getBounds();
-        m9Patch.draw(canvas.getGraphics2d(), r.left, r.top, r.width(), r.height());
+        Canvas_Delegate canvasDelegate = Canvas_Delegate.getDelegate(canvas);
+        m9Patch.draw(canvasDelegate.getGraphics2d(), r.left, r.top, r.width(), r.height());
 
         return;
     }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/ResourceHelper.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/ResourceHelper.java
index f624753..f13ecdc 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/ResourceHelper.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/ResourceHelper.java
@@ -17,8 +17,8 @@
 package com.android.layoutlib.bridge;
 
 import com.android.layoutlib.api.IDensityBasedResourceValue;
-import com.android.layoutlib.api.IResourceValue;
 import com.android.layoutlib.api.IDensityBasedResourceValue.Density;
+import com.android.layoutlib.api.IResourceValue;
 import com.android.ninepatch.NinePatch;
 
 import org.kxml2.io.KXmlParser;
@@ -26,6 +26,7 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import android.graphics.Bitmap;
+import android.graphics.Bitmap_Delegate;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
@@ -105,7 +106,8 @@
      * @param isFramework indicates whether the resource is a framework resources.
      * Framework resources are cached, and loaded only once.
      */
-    public static Drawable getDrawable(IResourceValue value, BridgeContext context, boolean isFramework) {
+    public static Drawable getDrawable(IResourceValue value, BridgeContext context,
+            boolean isFramework) {
         Drawable d = null;
 
         String stringValue = value.getValue();
@@ -168,14 +170,8 @@
                             isFramework ? null : context.getProjectKey());
 
                     if (bitmap == null) {
-                        bitmap = new Bitmap(bmpFile);
-                        try {
-                            bitmap.setDensity(Density.MEDIUM.getValue());
-                        } catch (NoClassDefFoundError error) {
-                            // look like we're running in an older version of ADT that doesn't
-                            // include the new layoutlib_api. Let's just ignore this, the drawing
-                            // will just be wrong.
-                        }
+                        // always create the cache copy in the original density.
+                        bitmap = Bitmap_Delegate.createBitmap(bmpFile, Density.MEDIUM);
                         Bridge.setCachedBitmap(stringValue, bitmap,
                                 isFramework ? null : context.getProjectKey());
                     }
diff --git a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/AndroidGraphicsTests.java b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/AndroidGraphicsTests.java
index 6e14e82..ba3c51a 100644
--- a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/AndroidGraphicsTests.java
+++ b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/AndroidGraphicsTests.java
@@ -17,8 +17,6 @@
 package com.android.layoutlib.bridge;
 
 import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics._Original_Paint;
 import android.text.TextPaint;
 
 import junit.framework.TestCase;
@@ -58,14 +56,6 @@
         }
     }
 
-    public void testPaint() {
-        _Original_Paint o = new _Original_Paint();
-        assertNotNull(o);
-
-        Paint p = new Paint();
-        assertNotNull(p);
-    }
-
     public void textTextPaint() {
         TextPaint p = new TextPaint();
         assertNotNull(p);
diff --git a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/TestNativeDelegate.java b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/TestNativeDelegate.java
index 6eed8ba..a86b5c9 100644
--- a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/TestNativeDelegate.java
+++ b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/TestNativeDelegate.java
@@ -87,7 +87,11 @@
 
             try {
                 // try to load the method with the given parameter types.
-                delegateClass.getMethod(originalMethod.getName(), parameters);
+                Method delegateMethod = delegateClass.getDeclaredMethod(originalMethod.getName(),
+                        parameters);
+
+                // check that the method is static
+                assertTrue((delegateMethod.getModifiers() & Modifier.STATIC) == Modifier.STATIC);
             } catch (NoSuchMethodException e) {
                 // compute a full class name that's long but not too long.
                 StringBuilder sb = new StringBuilder(originalMethod.getName() + "(");
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index f6d11fe..c845cc4 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -103,7 +103,10 @@
      * The list of classes on which to delegate all native methods.
      */
     private final static String[] DELEGATE_CLASS_NATIVES = new String[] {
+        "android.graphics.Bitmap",
+        "android.graphics.Canvas",
         "android.graphics.Matrix",
+        "android.graphics.Paint",
         "android.graphics.Typeface",
     };
 
@@ -123,14 +126,11 @@
      */
     private final static String[] RENAMED_CLASSES =
         new String[] {
-            "android.graphics.Bitmap",              "android.graphics._Original_Bitmap",
             "android.graphics.BitmapFactory",       "android.graphics._Original_BitmapFactory",
             "android.graphics.BitmapShader",        "android.graphics._Original_BitmapShader",
-            "android.graphics.Canvas",              "android.graphics._Original_Canvas",
             "android.graphics.ComposeShader",       "android.graphics._Original_ComposeShader",
             "android.graphics.DashPathEffect",       "android.graphics._Original_DashPathEffect",
             "android.graphics.LinearGradient",      "android.graphics._Original_LinearGradient",
-            "android.graphics.Paint",               "android.graphics._Original_Paint",
             "android.graphics.Path",                "android.graphics._Original_Path",
             "android.graphics.PorterDuffXfermode",  "android.graphics._Original_PorterDuffXfermode",
             "android.graphics.RadialGradient",      "android.graphics._Original_RadialGradient",
@@ -150,13 +150,6 @@
      */
     private final static String[] DELETE_RETURNS =
         new String[] {
-            "android.graphics.Paint",       // class to delete methods from
-            "android.graphics.Paint$Align", // list of type identifying methods to delete
-            "android.graphics.Paint$Style",
-            "android.graphics.Paint$Join",
-            "android.graphics.Paint$Cap",
-            "android.graphics.Paint$FontMetrics",
-            "android.graphics.Paint$FontMetricsInt",
             null };                         // separator, for next class/methods list.
 }
 
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java
index 21d6682..c7968a4 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java
@@ -169,7 +169,7 @@
         // Construct the descriptor of the delegate. For a static method, it's the same
         // however for an instance method we need to pass the 'this' reference first
         String desc = mDesc;
-        if (!mIsStatic && argTypes.length > 0) {
+        if (!mIsStatic) {
             Type[] argTypes2 = new Type[argTypes.length + 1];
 
             argTypes2[0] = Type.getObjectType(mClassName);